DEV Community

Viper
Viper

Posted on

Advent of Code 2020: Python Solution Day 20

This is the most hardest challenge and I again could not find solution by myself. So I had to cheat instead. And it is pretty known that today's challenge took nearly 20 minutes for fastest solution too. All the credit goes to the author.

I will update his code to make it work on NumPy because it is more faster to do transpose and indexing than general list. I will update this blog soon.

import math import re def transposed(tile): return list(''.join(row) for row in zip(*tile)) def reversed_tile(tile): return [''.join(reversed(row)) for row in tile] def rotations(tile): ans = [tile] for _ in range(3): ans.append(reversed_tile(transposed(ans[-1]))) return ans def group(tile): return rotations(tile) + rotations(transposed(tile)) tiles = {} for tile in open('day20.txt').read().split('\n\n'): lines = tile.strip().split('\n') tile_id = int(re.fullmatch(r'Tile (\d+):', lines[0]).group(1)) rows = lines[1:] tiles[tile_id] = group(rows) n = int(math.sqrt(len(tiles))) arranged = [[0] * n for _ in range(n)] stack = list(reversed(list((r, c) for c in range(n) for r in range(n)))) def solve(): if not stack: print(arranged[0][0][0] * arranged[-1][0][0] * arranged[0][-1][0] * arranged[-1][-1][0]) return True (r, c) = stack.pop() for tile_id in list(tiles): tile_group = tiles[tile_id] del tiles[tile_id] for tile in tile_group: if r > 0: if arranged[r - 1][c][1][-1] != tile[0]: continue if c > 0: if list(row[-1] for row in arranged[r][c - 1][1]) != list( row[0] for row in tile): continue arranged[r][c] = (tile_id, tile) if solve(): return True tiles[tile_id] = tile_group stack.append((r, c)) solve() def remove_border(tile): return [row[1:-1] for row in tile[1:-1]] board = [[remove_border(tile[1]) for tile in row] for row in arranged] tile_n = len(board[0][0]) def get(r, c): return board[r // tile_n][c // tile_n][r % tile_n][c % tile_n] board = [ ''.join(get(r, c) for c in range(n * tile_n)) for r in range(n * tile_n) ] for pattern in group( [' # ', '# ## ## ###', ' # # # # # # ']): matches = 0 for dr in range(len(board) - len(pattern) + 1): for dc in range(len(board[0]) - len(pattern[0]) + 1): matches += all(pattern[r][c] == ' ' or board[r + dr][c + dc] == '#' for r in range(len(pattern)) for c in range(len(pattern[0]))) if matches: print(''.join(board).count('#') - ''.join(pattern).count('#') * matches) break 
Enter fullscreen mode Exit fullscreen mode

Top comments (0)