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:
|
||||
print("(TEST) ", end="")
|
||||
|
||||
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.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:
|
||||
exec_time = timeit.timeit(
|
||||
'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.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:
|
||||
exec_time = timeit.timeit(
|
||||
'globals()[lib].part2(test_mode=flags.test)',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user