day20: raw (ugly) version
This commit is contained in:
parent
5accf0f63b
commit
10ffd11c46
@ -1,5 +1,7 @@
|
|||||||
def printSolution(day, part, solution, test=False):
|
def printSolution(day, part, solution, test=None):
|
||||||
if test:
|
if test:
|
||||||
print("(TEST) ", end="")
|
print("(TEST) ", end="")
|
||||||
|
|
||||||
print("Solution to day %s, part %s: %s" % (day, part, solution))
|
print("Solution to day %s, part %s: %s" % (day, part, solution))
|
||||||
|
if test:
|
||||||
|
print("Expected: %s (%s)" % (test, "correct" if test == solution else "WRONG"))
|
||||||
|
|||||||
223
day20.py
Normal file
223
day20.py
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
import aoclib
|
||||||
|
import math
|
||||||
|
import re
|
||||||
|
|
||||||
|
DAY = 20
|
||||||
|
TEST_SOLUTION_PART1 = 20899048083289
|
||||||
|
TEST_SOLUTION_PART2 = 273
|
||||||
|
|
||||||
|
|
||||||
|
class Tile:
|
||||||
|
def __init__(self, raw_input):
|
||||||
|
self.image_id = int(raw_input[0][5:-1])
|
||||||
|
self.image = raw_input[1:]
|
||||||
|
|
||||||
|
def getPossibleBorderList(self):
|
||||||
|
return [
|
||||||
|
self.image[0],
|
||||||
|
"".join([x[0] for x in self.image]),
|
||||||
|
"".join([x[-1] for x in self.image]),
|
||||||
|
self.image[-1],
|
||||||
|
"".join(reversed(self.image[0])),
|
||||||
|
"".join(reversed([x[0] for x in self.image])),
|
||||||
|
"".join(reversed([x[-1] for x in self.image])),
|
||||||
|
"".join(reversed(self.image[-1])),
|
||||||
|
]
|
||||||
|
|
||||||
|
def getBorderlessImage(self):
|
||||||
|
return ["".join(x for x in y[1:-1]) for y in self.image[1:-1]]
|
||||||
|
|
||||||
|
def getCurrentBorders(self):
|
||||||
|
# top right bottom left
|
||||||
|
return [
|
||||||
|
self.image[0],
|
||||||
|
"".join([x[-1] for x in self.image]),
|
||||||
|
self.image[-1],
|
||||||
|
"".join([x[0] for x in self.image])
|
||||||
|
]
|
||||||
|
|
||||||
|
def rotateRight(self):
|
||||||
|
self.image = rotateRight(self.image)
|
||||||
|
|
||||||
|
def rotateLeft(self):
|
||||||
|
self.image = rotateLeft(self.image)
|
||||||
|
|
||||||
|
def flipHorizontally(self):
|
||||||
|
self.image = flipHorizontally(self.image)
|
||||||
|
|
||||||
|
def flipVertically(self):
|
||||||
|
self.image = flipVertically(self.image)
|
||||||
|
|
||||||
|
|
||||||
|
def rotateRight(image):
|
||||||
|
return ["".join([x[line_no] for x in reversed(image)]) for line_no in range(len(image))]
|
||||||
|
|
||||||
|
|
||||||
|
def rotateLeft(image):
|
||||||
|
return ["".join([x[line_no] for x in image]) for line_no in reversed(range(len(image)))]
|
||||||
|
|
||||||
|
|
||||||
|
def flipHorizontally(image):
|
||||||
|
return list(reversed(image))
|
||||||
|
|
||||||
|
|
||||||
|
def flipVertically(image):
|
||||||
|
return ["".join(x for x in reversed(y)) for y in image]
|
||||||
|
|
||||||
|
|
||||||
|
def getAllPossibleBorders(tile_dict, exception):
|
||||||
|
all_possible_borders = []
|
||||||
|
for tile_id, tile in tile_dict.items():
|
||||||
|
if tile_id != exception:
|
||||||
|
all_possible_borders.extend(tile.getPossibleBorderList())
|
||||||
|
|
||||||
|
return all_possible_borders
|
||||||
|
|
||||||
|
|
||||||
|
def getCornerPieces(tile_dict):
|
||||||
|
corner_pieces = []
|
||||||
|
for tile_id, tile in tile_dict.items():
|
||||||
|
impossible_borders = 0
|
||||||
|
all_other_borders = getAllPossibleBorders(tile_dict, tile_id)
|
||||||
|
for border in tile.getPossibleBorderList():
|
||||||
|
if border not in all_other_borders:
|
||||||
|
impossible_borders += 1
|
||||||
|
|
||||||
|
# we need to find the tiles where 2 borders (and their reverse) don't match any other border
|
||||||
|
if impossible_borders == 4:
|
||||||
|
corner_pieces.append(tile_id)
|
||||||
|
|
||||||
|
return corner_pieces
|
||||||
|
|
||||||
|
|
||||||
|
def part1(test_mode=False):
|
||||||
|
my_input = aoclib.getMultiLineInputAsArray(day=DAY, test=test_mode)
|
||||||
|
tile_dict = {}
|
||||||
|
for tile_input in my_input:
|
||||||
|
tile = Tile(tile_input)
|
||||||
|
tile_dict[tile.image_id] = tile
|
||||||
|
|
||||||
|
return math.prod(getCornerPieces(tile_dict))
|
||||||
|
|
||||||
|
|
||||||
|
def part2(test_mode=False):
|
||||||
|
my_input = aoclib.getMultiLineInputAsArray(day=DAY, test=test_mode)
|
||||||
|
tile_dict = {}
|
||||||
|
for tile_input in my_input:
|
||||||
|
tile = Tile(tile_input)
|
||||||
|
tile_dict[tile.image_id] = tile
|
||||||
|
|
||||||
|
borderlen = int(math.sqrt(len(tile_dict)))
|
||||||
|
all_pieces = list(tile_dict.keys())
|
||||||
|
corner_piece = getCornerPieces(tile_dict)[0]
|
||||||
|
all_pieces.remove(corner_piece)
|
||||||
|
|
||||||
|
# first - find correct orientation of corner piece
|
||||||
|
possible_borders = getAllPossibleBorders(tile_dict, corner_piece)
|
||||||
|
found = False
|
||||||
|
for _ in range(2):
|
||||||
|
for _ in range(2):
|
||||||
|
for _ in range(4):
|
||||||
|
if tile_dict[corner_piece].getCurrentBorders()[0] not in possible_borders \
|
||||||
|
and tile_dict[corner_piece].getCurrentBorders()[3] not in possible_borders:
|
||||||
|
found = True
|
||||||
|
break
|
||||||
|
|
||||||
|
tile_dict[corner_piece].rotateRight()
|
||||||
|
|
||||||
|
if found:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
tile_dict[corner_piece].flipHorizontally()
|
||||||
|
|
||||||
|
if found:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
tile_dict[corner_piece].flipVertically()
|
||||||
|
|
||||||
|
# flip diagonally to match with example from aoc webpage
|
||||||
|
tile_dict[corner_piece].rotateRight()
|
||||||
|
tile_dict[corner_piece].flipVertically()
|
||||||
|
|
||||||
|
full_image = []
|
||||||
|
for y in range(borderlen):
|
||||||
|
full_image.append([])
|
||||||
|
for x in range(borderlen):
|
||||||
|
if x == 0 and y == 0:
|
||||||
|
full_image[y].append(corner_piece)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# find matching piece with correct orientation for the piece to the left (or the top if y > 0 and x == 0)
|
||||||
|
if x == 0: # check against bottom border of upper piece
|
||||||
|
check_border = tile_dict[full_image[y - 1][x]].getCurrentBorders()[2]
|
||||||
|
else:
|
||||||
|
check_border = tile_dict[full_image[y][x - 1]].getCurrentBorders()[1]
|
||||||
|
|
||||||
|
for possible_tile in all_pieces:
|
||||||
|
if check_border in tile_dict[possible_tile].getPossibleBorderList():
|
||||||
|
# found my piece ... now orientate it correctly
|
||||||
|
oriented = False
|
||||||
|
for _ in range(2):
|
||||||
|
for _ in range(2):
|
||||||
|
for _ in range(4):
|
||||||
|
if (x == 0 and tile_dict[possible_tile].getCurrentBorders()[0] == check_border)\
|
||||||
|
or (x != 0 and tile_dict[possible_tile].getCurrentBorders()[3] == check_border):
|
||||||
|
oriented = True
|
||||||
|
full_image[y].append(possible_tile)
|
||||||
|
all_pieces.remove(possible_tile)
|
||||||
|
break
|
||||||
|
|
||||||
|
tile_dict[possible_tile].rotateRight()
|
||||||
|
|
||||||
|
if oriented:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
tile_dict[possible_tile].flipVertically()
|
||||||
|
|
||||||
|
if oriented:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
tile_dict[possible_tile].flipHorizontally()
|
||||||
|
|
||||||
|
# now that we have the full picture, assemble the borderless full image
|
||||||
|
borderless_image = []
|
||||||
|
full_hash_count = 0
|
||||||
|
for y in full_image:
|
||||||
|
for image_line in range(8):
|
||||||
|
borderless_image.append("".join([tile_dict[x].getBorderlessImage()[image_line] for x in y]))
|
||||||
|
full_hash_count += borderless_image[-1].count('#')
|
||||||
|
|
||||||
|
# and finally scan for our sea monster
|
||||||
|
# seamonster_line_1 = re.compile(r"..................#.")
|
||||||
|
seamonster_line_2 = re.compile(r"#....##....##....###")
|
||||||
|
seamonster_line_3 = re.compile(r".#..#..#..#..#..#...")
|
||||||
|
seamonster_hashcount = 15 # amount of '#' in the sea monster
|
||||||
|
seamonster_count = 0
|
||||||
|
for _ in range(2):
|
||||||
|
for _ in range(2):
|
||||||
|
for _ in range(4):
|
||||||
|
for x in range(len(borderless_image) - 2):
|
||||||
|
if s_2 := re.split(seamonster_line_2, borderless_image[x+1]):
|
||||||
|
if s_3 := re.split(seamonster_line_3, borderless_image[x+2]):
|
||||||
|
# yes, this is somewhat optimistic, but it results in the correct answer
|
||||||
|
if len(s_2) > 1 and len(s_2) == len(s_3):
|
||||||
|
seamonster_count += len(s_2) - 1
|
||||||
|
|
||||||
|
if seamonster_count == 0:
|
||||||
|
borderless_image = rotateRight(borderless_image)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if seamonster_count == 0:
|
||||||
|
borderless_image = flipHorizontally(borderless_image)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if seamonster_count == 0:
|
||||||
|
borderless_image = flipVertically(borderless_image)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
print(seamonster_count)
|
||||||
|
|
||||||
|
return full_hash_count - seamonster_count * seamonster_hashcount
|
||||||
107
inputs/20_test
Normal file
107
inputs/20_test
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
Tile 2311:
|
||||||
|
..##.#..#.
|
||||||
|
##..#.....
|
||||||
|
#...##..#.
|
||||||
|
####.#...#
|
||||||
|
##.##.###.
|
||||||
|
##...#.###
|
||||||
|
.#.#.#..##
|
||||||
|
..#....#..
|
||||||
|
###...#.#.
|
||||||
|
..###..###
|
||||||
|
|
||||||
|
Tile 1951:
|
||||||
|
#.##...##.
|
||||||
|
#.####...#
|
||||||
|
.....#..##
|
||||||
|
#...######
|
||||||
|
.##.#....#
|
||||||
|
.###.#####
|
||||||
|
###.##.##.
|
||||||
|
.###....#.
|
||||||
|
..#.#..#.#
|
||||||
|
#...##.#..
|
||||||
|
|
||||||
|
Tile 1171:
|
||||||
|
####...##.
|
||||||
|
#..##.#..#
|
||||||
|
##.#..#.#.
|
||||||
|
.###.####.
|
||||||
|
..###.####
|
||||||
|
.##....##.
|
||||||
|
.#...####.
|
||||||
|
#.##.####.
|
||||||
|
####..#...
|
||||||
|
.....##...
|
||||||
|
|
||||||
|
Tile 1427:
|
||||||
|
###.##.#..
|
||||||
|
.#..#.##..
|
||||||
|
.#.##.#..#
|
||||||
|
#.#.#.##.#
|
||||||
|
....#...##
|
||||||
|
...##..##.
|
||||||
|
...#.#####
|
||||||
|
.#.####.#.
|
||||||
|
..#..###.#
|
||||||
|
..##.#..#.
|
||||||
|
|
||||||
|
Tile 1489:
|
||||||
|
##.#.#....
|
||||||
|
..##...#..
|
||||||
|
.##..##...
|
||||||
|
..#...#...
|
||||||
|
#####...#.
|
||||||
|
#..#.#.#.#
|
||||||
|
...#.#.#..
|
||||||
|
##.#...##.
|
||||||
|
..##.##.##
|
||||||
|
###.##.#..
|
||||||
|
|
||||||
|
Tile 2473:
|
||||||
|
#....####.
|
||||||
|
#..#.##...
|
||||||
|
#.##..#...
|
||||||
|
######.#.#
|
||||||
|
.#...#.#.#
|
||||||
|
.#########
|
||||||
|
.###.#..#.
|
||||||
|
########.#
|
||||||
|
##...##.#.
|
||||||
|
..###.#.#.
|
||||||
|
|
||||||
|
Tile 2971:
|
||||||
|
..#.#....#
|
||||||
|
#...###...
|
||||||
|
#.#.###...
|
||||||
|
##.##..#..
|
||||||
|
.#####..##
|
||||||
|
.#..####.#
|
||||||
|
#..#.#..#.
|
||||||
|
..####.###
|
||||||
|
..#.#.###.
|
||||||
|
...#.#.#.#
|
||||||
|
|
||||||
|
Tile 2729:
|
||||||
|
...#.#.#.#
|
||||||
|
####.#....
|
||||||
|
..#.#.....
|
||||||
|
....#..#.#
|
||||||
|
.##..##.#.
|
||||||
|
.#.####...
|
||||||
|
####.#.#..
|
||||||
|
##.####...
|
||||||
|
##..#.##..
|
||||||
|
#.##...##.
|
||||||
|
|
||||||
|
Tile 3079:
|
||||||
|
#.#.#####.
|
||||||
|
.#..######
|
||||||
|
..#.......
|
||||||
|
######....
|
||||||
|
####.#..#.
|
||||||
|
.#...#.##.
|
||||||
|
#.#####.##
|
||||||
|
..#.###...
|
||||||
|
..#.......
|
||||||
|
..#.###...
|
||||||
12
main.py
12
main.py
@ -58,7 +58,11 @@ for lib in sorted(imported):
|
|||||||
|
|
||||||
if not flags.part or flags.part == 1:
|
if not flags.part or flags.part == 1:
|
||||||
if not flags.timeit:
|
if not flags.timeit:
|
||||||
aoclib.printSolution(day, 1, globals()[lib].part1(test_mode=flags.test), test=flags.test)
|
solution = globals()[lib].part1(test_mode=flags.test)
|
||||||
|
if flags.test:
|
||||||
|
aoclib.printSolution(day, 1, solution, test=globals()[lib].TEST_SOLUTION_PART1)
|
||||||
|
else:
|
||||||
|
aoclib.printSolution(day, 1, solution)
|
||||||
else:
|
else:
|
||||||
exec_time = timeit.timeit(
|
exec_time = timeit.timeit(
|
||||||
'globals()[lib].part1(test_mode=flags.test)',
|
'globals()[lib].part1(test_mode=flags.test)',
|
||||||
@ -69,7 +73,11 @@ for lib in sorted(imported):
|
|||||||
|
|
||||||
if not flags.part or flags.part == 2:
|
if not flags.part or flags.part == 2:
|
||||||
if not flags.timeit:
|
if not flags.timeit:
|
||||||
aoclib.printSolution(day, 2, globals()[lib].part2(test_mode=flags.test), test=flags.test)
|
solution = globals()[lib].part2(test_mode=flags.test)
|
||||||
|
if flags.test:
|
||||||
|
aoclib.printSolution(day, 2, solution, test=globals()[lib].TEST_SOLUTION_PART2)
|
||||||
|
else:
|
||||||
|
aoclib.printSolution(day, 2, solution)
|
||||||
else:
|
else:
|
||||||
exec_time = timeit.timeit(
|
exec_time = timeit.timeit(
|
||||||
'globals()[lib].part2(test_mode=flags.test)',
|
'globals()[lib].part2(test_mode=flags.test)',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user