Add day 11 visualisation
This commit is contained in:
parent
bc43258abd
commit
454d8aa3a8
8 changed files with 156 additions and 33 deletions
BIN
11-seatingSystem/0.gif
Normal file
BIN
11-seatingSystem/0.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 MiB |
BIN
11-seatingSystem/1.gif
Normal file
BIN
11-seatingSystem/1.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
|
@ -2,6 +2,12 @@
|
|||
|
||||
This is a [cellular automata](https://en.wikipedia.org/wiki/Cellular_automaton) that (in part one) uses the [Moore neighbourhood](https://en.wikipedia.org/wiki/Moore_neighborhood).
|
||||
|
||||
### Visualisation
|
||||
|
||||
| Part one | Part two |
|
||||
| ------------------------------ | ------------------------------ |
|
||||
|  |  |
|
||||
|
||||
<details><summary>Script output</summary>
|
||||
|
||||
```
|
||||
|
|
|
@ -6,6 +6,7 @@ from rich import print
|
|||
|
||||
from partOne import partOne
|
||||
from partTwo import partTwo
|
||||
import visualise
|
||||
|
||||
|
||||
def run_tests(test_cases):
|
||||
|
@ -59,6 +60,13 @@ if __name__ == "__main__":
|
|||
print("Error: could not open input.txt")
|
||||
sys.exit(-1)
|
||||
|
||||
if "vis" in sys.argv:
|
||||
|
||||
print("[green]Running visualisation....[/green]")
|
||||
|
||||
visualise.visualise(challenge_input)
|
||||
sys.exit()
|
||||
|
||||
run_tests(info["testCases"])
|
||||
|
||||
if "debug" in sys.argv:
|
||||
|
|
|
@ -8,12 +8,27 @@ filled_seat = "#"
|
|||
no_seat = "."
|
||||
|
||||
|
||||
lookup_positions = [
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
(1, 0),
|
||||
(1, -1),
|
||||
(0, -1),
|
||||
(-1, -1),
|
||||
(-1, 0),
|
||||
(-1, 1),
|
||||
]
|
||||
|
||||
|
||||
def parse(instr: str) -> List[List[str]]:
|
||||
return [[char for char in x] for x in instr.strip().split("\n")]
|
||||
|
||||
def iterate(current_hall: List[List[str]], neighbour_counter: Callable, get_new_state: Callable) -> List[List[str]]:
|
||||
|
||||
def iterate(
|
||||
current_hall: List[List[str]], neighbour_counter: Callable, get_new_state: Callable
|
||||
) -> List[List[str]]:
|
||||
# Copy hall
|
||||
next_hall = copy.deepcopy(current_hall) # this is bloody slow
|
||||
next_hall = copy.deepcopy(current_hall) # this is bloody slow
|
||||
|
||||
hall_size = (len(next_hall[0]), len(next_hall))
|
||||
|
||||
|
@ -35,7 +50,10 @@ def iterate(current_hall: List[List[str]], neighbour_counter: Callable, get_new_
|
|||
# Return copied list
|
||||
return next_hall
|
||||
|
||||
def run(current_state:List[List[str]], neighbour_counter:Callable, get_new_state:Callable) -> int:
|
||||
|
||||
def run(
|
||||
current_state: List[List[str]], neighbour_counter: Callable, get_new_state: Callable
|
||||
) -> int:
|
||||
last_state = None
|
||||
|
||||
while current_state != last_state:
|
||||
|
@ -49,5 +67,5 @@ def run(current_state:List[List[str]], neighbour_counter:Callable, get_new_state
|
|||
for b in a:
|
||||
if b == filled_seat:
|
||||
total_occupied += 1
|
||||
|
||||
return total_occupied
|
||||
|
||||
return total_occupied
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import List, Tuple
|
|||
from common import *
|
||||
|
||||
|
||||
def get_new_state(num_neighbours:int, old_state:str) -> str:
|
||||
def get_new_state(num_neighbours: int, old_state: str) -> str:
|
||||
if num_neighbours == 0:
|
||||
return filled_seat
|
||||
elif num_neighbours >= 4 and old_state == filled_seat:
|
||||
|
@ -12,22 +12,14 @@ def get_new_state(num_neighbours:int, old_state:str) -> str:
|
|||
return old_state
|
||||
|
||||
|
||||
def count_neighbours(hall:List[List[str]], current_pos:Tuple[int, int], hall_size:Tuple[int, int]) -> int:
|
||||
num_neighbours = 0
|
||||
check_positions = [
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
(1, 0),
|
||||
(1, -1),
|
||||
(0, -1),
|
||||
(-1, -1),
|
||||
(-1, 0),
|
||||
(-1, 1),
|
||||
]
|
||||
def count_neighbours(
|
||||
hall: List[List[str]], current_pos: Tuple[int, int], hall_size: Tuple[int, int]
|
||||
) -> int:
|
||||
num_neighbours = 0
|
||||
|
||||
row, col = current_pos
|
||||
|
||||
for (x, y) in check_positions:
|
||||
for (x, y) in lookup_positions:
|
||||
test_x_pos = x + col
|
||||
test_y_pos = y + row
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ from typing import List, Tuple
|
|||
from common import *
|
||||
|
||||
|
||||
def get_new_state(num_neighbours:int, old_state:str) -> str:
|
||||
def get_new_state(num_neighbours: int, old_state: str) -> str:
|
||||
if num_neighbours == 0:
|
||||
return filled_seat
|
||||
elif num_neighbours >= 5 and old_state == filled_seat:
|
||||
|
@ -12,22 +12,14 @@ def get_new_state(num_neighbours:int, old_state:str) -> str:
|
|||
return old_state
|
||||
|
||||
|
||||
def count_neighbours(hall:List[List[str]], current_pos:Tuple[int, int], hall_size:Tuple[int, int]) -> int:
|
||||
num_neighbours = 0
|
||||
deltas = [
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
(1, 0),
|
||||
(1, -1),
|
||||
(0, -1),
|
||||
(-1, -1),
|
||||
(-1, 0),
|
||||
(-1, 1),
|
||||
]
|
||||
def count_neighbours(
|
||||
hall: List[List[str]], current_pos: Tuple[int, int], hall_size: Tuple[int, int]
|
||||
) -> int:
|
||||
num_neighbours = 0
|
||||
|
||||
row, col = current_pos
|
||||
|
||||
for (x, y) in deltas:
|
||||
for (x, y) in lookup_positions:
|
||||
|
||||
test_x_pos = col + x
|
||||
test_y_pos = row + y
|
||||
|
|
107
11-seatingSystem/python/visualise.py
Normal file
107
11-seatingSystem/python/visualise.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
import common
|
||||
import partOne
|
||||
import partTwo
|
||||
import os
|
||||
from PIL import Image
|
||||
import ffmpeg
|
||||
import shutil
|
||||
|
||||
from typing import Callable, List
|
||||
|
||||
frame_counter = 1
|
||||
anim_counter = 0
|
||||
skipped_last = True
|
||||
|
||||
background_colour = "#646464"
|
||||
occupied_colour = (230, 0, 0)
|
||||
empty_colour = (100, 220, 100)
|
||||
|
||||
resize_factor = 3
|
||||
|
||||
|
||||
def make_frame(hall: List[List[str]]):
|
||||
global frame_counter, skipped_last # muahahaha
|
||||
|
||||
if not skipped_last:
|
||||
skipped_last = True
|
||||
return
|
||||
else:
|
||||
skipped_last = False
|
||||
|
||||
hall_size = (len(hall[0]), len(hall))
|
||||
|
||||
img = Image.new("RGB", hall_size, color=background_colour)
|
||||
|
||||
for x in range(hall_size[0]):
|
||||
for y in range(hall_size[1]):
|
||||
|
||||
jts = hall[y][x]
|
||||
|
||||
if jts == common.no_seat:
|
||||
continue
|
||||
|
||||
colour = None
|
||||
if jts == common.open_seat:
|
||||
colour = empty_colour
|
||||
elif jts == common.filled_seat:
|
||||
colour = occupied_colour
|
||||
else:
|
||||
continue
|
||||
|
||||
img.putpixel((x, y), colour)
|
||||
|
||||
new_width = int((img.width * resize_factor) / 2) * 2
|
||||
new_height = int((img.height * resize_factor) / 2) * 2
|
||||
|
||||
img = img.resize((new_width, new_height), resample=Image.NEAREST)
|
||||
|
||||
img.save(
|
||||
os.path.join("output", f"{anim_counter}_{str(frame_counter).zfill(4)}.png")
|
||||
)
|
||||
frame_counter += 1
|
||||
|
||||
|
||||
def run(
|
||||
current_state: List[List[str]],
|
||||
neighbour_counter: Callable,
|
||||
get_new_state: Callable,
|
||||
hook: Callable,
|
||||
):
|
||||
last_state = None
|
||||
|
||||
while current_state != last_state:
|
||||
hook(current_state)
|
||||
last_state = current_state
|
||||
current_state = common.iterate(current_state, neighbour_counter, get_new_state)
|
||||
|
||||
|
||||
def visualise(instr: str):
|
||||
|
||||
global anim_counter
|
||||
global frame_counter
|
||||
|
||||
if not os.path.exists("output"):
|
||||
os.mkdir("output")
|
||||
|
||||
run(
|
||||
common.parse(instr), partOne.count_neighbours, partOne.get_new_state, make_frame
|
||||
)
|
||||
anim_counter += 1
|
||||
frame_counter = 0
|
||||
skipped_last = True
|
||||
run(
|
||||
common.parse(instr), partTwo.count_neighbours, partTwo.get_new_state, make_frame
|
||||
)
|
||||
|
||||
for i in range(anim_counter + 1):
|
||||
if os.path.exists(f"{i}.gif"):
|
||||
os.unlink(f"{i}.gif")
|
||||
(
|
||||
ffmpeg.input(
|
||||
os.path.join("output", f"{i}_%04d.png"), framerate=10, start_number=0
|
||||
)
|
||||
.output(f"{i}.gif")
|
||||
.run()
|
||||
)
|
||||
|
||||
shutil.rmtree("output")
|
Loading…
Add table
Add a link
Reference in a new issue