increase speed by using a cache for positions
This commit is contained in:
parent
5b244fc2de
commit
e60d0e1063
@ -7,50 +7,54 @@ def readFile() -> list:
|
|||||||
with open(f"{__file__.rstrip('code.py')}input.txt", "r") as f:
|
with open(f"{__file__.rstrip('code.py')}input.txt", "r") as f:
|
||||||
return [list(line.strip()) for line in f.readlines()]
|
return [list(line.strip()) for line in f.readlines()]
|
||||||
|
|
||||||
def get_positions(seats: list, x: int, y: int, rx: range, ry: range, adjacent: bool) -> list:
|
def get_positions(seats: list, cache: dict, x: int, y: int):
|
||||||
if adjacent: # check only adjacent tiles
|
idx = (x, y)
|
||||||
positions = [(x+i, y+j) for i in range(-1,2) for j in range(-1,2) if (i,j) != (0,0)]
|
cache[idx] = {"adjacent": [], "next_seat": []}
|
||||||
|
|
||||||
else: # check first seat available in direction
|
for dx in range(-1, 2):
|
||||||
positions = []
|
for dy in range(-1, 2):
|
||||||
for dx in range(-1,2):
|
if dx == 0 and dy == 0:
|
||||||
for dy in range(-1,2):
|
continue
|
||||||
if dx == 0 and dy == 0:
|
# adjacent tiles
|
||||||
continue
|
cache[idx]["adjacent"].append((x + dx, y + dy))
|
||||||
i, j = x, y
|
|
||||||
while i + dx in rx and j + dy in ry:
|
|
||||||
i += dx
|
|
||||||
j += dy
|
|
||||||
if seats[i][j] in ("L", "#"):
|
|
||||||
positions.append((i, j))
|
|
||||||
break
|
|
||||||
|
|
||||||
return positions
|
# next available seat
|
||||||
|
i, j = x, y
|
||||||
|
while i + dx in cache["rx"] and j + dy in cache["ry"]:
|
||||||
|
i += dx
|
||||||
|
j += dy
|
||||||
|
if seats[i][j] in ("L", "#"):
|
||||||
|
cache[idx]["next_seat"].append((i, j))
|
||||||
|
break
|
||||||
|
|
||||||
def count(seats: list, x: int, y: int, seat: str, adjacent: bool) -> int:
|
def count(seats: list, cache: dict, x: int, y: int, seat: str, selection: str) -> int:
|
||||||
rx, ry = range(len(seats)), range(len(seats[0]))
|
return sum(1 for pos in cache[(x, y)][selection] if pos[0] in cache["rx"] and \
|
||||||
positions = get_positions(seats, x, y, rx, ry, adjacent)
|
pos[1] in cache["ry"] and seats[pos[0]][pos[1]] == seat)
|
||||||
return sum(1 for pos in positions if pos[0] in rx and pos[1] in ry and \
|
|
||||||
seats[pos[0]][pos[1]] == seat)
|
|
||||||
|
|
||||||
def iterate(seats: list, adjacent: bool = True) -> list:
|
def create_cache(seats: list) -> dict:
|
||||||
size_outer = len(seats)
|
cache = {"rx": range(len(seats)), "ry": range(len(seats[0]))}
|
||||||
size_inner = len(seats[0])
|
for x in cache["rx"]:
|
||||||
|
for y in cache["ry"]:
|
||||||
|
get_positions(seats, cache, x, y)
|
||||||
|
return cache
|
||||||
|
|
||||||
|
def iterate(seats: list, cache: dict, adjacent: bool = True) -> list:
|
||||||
|
selection = "adjacent" if adjacent else "next_seat"
|
||||||
|
tolerance = 4 if adjacent else 5
|
||||||
while True:
|
while True:
|
||||||
tmp = [s[:] for s in seats]
|
tmp = [s[:] for s in seats]
|
||||||
|
|
||||||
for x in range(size_outer):
|
for x in cache["rx"]:
|
||||||
for y in range(size_inner):
|
for y in cache["ry"]:
|
||||||
if seats[x][y] == ".":
|
if seats[x][y] == ".":
|
||||||
continue
|
continue
|
||||||
|
|
||||||
elif seats[x][y] == "L":
|
elif seats[x][y] == "L":
|
||||||
if count(seats, x, y, "#", adjacent) == 0:
|
if count(seats, cache, x, y, "#", selection) == 0:
|
||||||
tmp[x][y] = "#"
|
tmp[x][y] = "#"
|
||||||
|
|
||||||
else: # seats[x][y] == "#":
|
else: # seats[x][y] == "#":
|
||||||
tolerance = 4 if adjacent else 5
|
if count(seats, cache, x, y, "#", selection) >= tolerance:
|
||||||
if count(seats, x, y, "#", adjacent) >= tolerance:
|
|
||||||
tmp[x][y] = "L"
|
tmp[x][y] = "L"
|
||||||
|
|
||||||
if seats == tmp:
|
if seats == tmp:
|
||||||
@ -58,15 +62,16 @@ def iterate(seats: list, adjacent: bool = True) -> list:
|
|||||||
else:
|
else:
|
||||||
seats = tmp
|
seats = tmp
|
||||||
|
|
||||||
def part1(input: list) -> int:
|
def part1(input: list, cache) -> int:
|
||||||
seats = iterate(input)
|
seats = iterate(input, cache)
|
||||||
return sum([row.count("#") for row in seats])
|
return sum([row.count("#") for row in seats])
|
||||||
|
|
||||||
def part2(input: list) -> int:
|
def part2(input: list, cache) -> int:
|
||||||
seats = iterate(input, adjacent=False)
|
seats = iterate(input, cache, adjacent=False)
|
||||||
return sum([row.count("#") for row in seats])
|
return sum([row.count("#") for row in seats])
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
input = readFile()
|
input = readFile()
|
||||||
print(f"Part 1: {part1(input)}")
|
cache = create_cache(input)
|
||||||
print(f"Part 2: {part2(input)}")
|
print(f"Part 1: {part1(input, cache)}")
|
||||||
|
print(f"Part 2: {part2(input, cache)}")
|
@ -1,7 +1,7 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
# Copyright (c) 2020 Akumatic
|
# Copyright (c) 2020 Akumatic
|
||||||
|
|
||||||
from code import part1, part2, iterate
|
from code import part1, part2, iterate, create_cache
|
||||||
|
|
||||||
def test():
|
def test():
|
||||||
input = [['L', '.', 'L', 'L', '.', 'L', 'L', '.', 'L', 'L'],
|
input = [['L', '.', 'L', 'L', '.', 'L', 'L', '.', 'L', 'L'],
|
||||||
@ -14,7 +14,8 @@ def test():
|
|||||||
['L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'],
|
['L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L', 'L'],
|
||||||
['L', '.', 'L', 'L', 'L', 'L', 'L', 'L', '.', 'L'],
|
['L', '.', 'L', 'L', 'L', 'L', 'L', 'L', '.', 'L'],
|
||||||
['L', '.', 'L', 'L', 'L', 'L', 'L', '.', 'L', 'L']]
|
['L', '.', 'L', 'L', 'L', 'L', 'L', '.', 'L', 'L']]
|
||||||
assert iterate(input) == [
|
cache = create_cache(input)
|
||||||
|
assert iterate(input, cache) == [
|
||||||
['#', '.', '#', 'L', '.', 'L', '#', '.', '#', '#'],
|
['#', '.', '#', 'L', '.', 'L', '#', '.', '#', '#'],
|
||||||
['#', 'L', 'L', 'L', '#', 'L', 'L', '.', 'L', '#'],
|
['#', 'L', 'L', 'L', '#', 'L', 'L', '.', 'L', '#'],
|
||||||
['L', '.', '#', '.', 'L', '.', '.', '#', '.', '.'],
|
['L', '.', '#', '.', 'L', '.', '.', '#', '.', '.'],
|
||||||
@ -25,7 +26,7 @@ def test():
|
|||||||
['#', 'L', '#', 'L', '#', '#', 'L', '#', 'L', '#'],
|
['#', 'L', '#', 'L', '#', '#', 'L', '#', 'L', '#'],
|
||||||
['#', '.', 'L', 'L', 'L', 'L', 'L', 'L', '.', 'L'],
|
['#', '.', 'L', 'L', 'L', 'L', 'L', 'L', '.', 'L'],
|
||||||
['#', '.', '#', 'L', '#', 'L', '#', '.', '#', '#']]
|
['#', '.', '#', 'L', '#', 'L', '#', '.', '#', '#']]
|
||||||
assert iterate(input, adjacent=False) == [
|
assert iterate(input, cache, adjacent=False) == [
|
||||||
['#', '.', 'L', '#', '.', 'L', '#', '.', 'L', '#'],
|
['#', '.', 'L', '#', '.', 'L', '#', '.', 'L', '#'],
|
||||||
['#', 'L', 'L', 'L', 'L', 'L', 'L', '.', 'L', 'L'],
|
['#', 'L', 'L', 'L', 'L', 'L', 'L', '.', 'L', 'L'],
|
||||||
['L', '.', 'L', '.', 'L', '.', '.', '#', '.', '.'],
|
['L', '.', 'L', '.', 'L', '.', '.', '#', '.', '.'],
|
||||||
@ -36,8 +37,8 @@ def test():
|
|||||||
['L', 'L', 'L', '#', '#', '#', 'L', 'L', 'L', '#'],
|
['L', 'L', 'L', '#', '#', '#', 'L', 'L', 'L', '#'],
|
||||||
['#', '.', 'L', 'L', 'L', 'L', 'L', '#', '.', 'L'],
|
['#', '.', 'L', 'L', 'L', 'L', 'L', '#', '.', 'L'],
|
||||||
['#', '.', 'L', '#', 'L', 'L', '#', '.', 'L', '#']]
|
['#', '.', 'L', '#', 'L', 'L', '#', '.', 'L', '#']]
|
||||||
assert part1(input) == 37
|
assert part1(input, cache) == 37
|
||||||
assert part2(input) == 26
|
assert part2(input, cache) == 26
|
||||||
print("Passed tests for", input)
|
print("Passed tests for", input)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
Loading…
x
Reference in New Issue
Block a user