My solutions for Advent of Code.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
adventofcode/2020/20.py

179 lines
4.2 KiB

#!/usr/bin/env python
from collections import defaultdict as dd
from aoc import get_input # AoC
import re # regex
import numpy as np
from copy import deepcopy as copy
from sys import setrecursionlimit
setrecursionlimit(20000)
data = get_input(20).strip()
pics = dict()
for genpic in data.split("\n\n"):
foundTitle = None
for i, row in enumerate(genpic.splitlines()):
if(foundTitle == None):
titleCheck = re.match(r"^Tile ([0-9]+):", row)
if(titleCheck != None):
foundTitle = titleCheck[1]
pics[foundTitle] = []
else:
try:
pics[foundTitle].append( list(row) )
except:
pics[foundTitle] = []
pics[foundTitle].append( list(row) )
for pid, pic in pics.items():
pics[pid] = np.asarray(pic)
mapWidth = len(pics) ** (1/2)
def compileBorder(row):
out = ""
for char in row:
out += char
return out
def compileSideBorder(pic, xOffset=0):
out = ""
for row in pic:
out += row[xOffset]
return out
# check 4 border locations, up, down, left, right
picBorders = dict()
def genBorders(picid):
pic = pics[picid]
## compile its borders
borders = dict()
borders["U"] = compileBorder(pic[0])
borders["R"] = compileSideBorder(pic, -1)
borders["D"] = compileBorder(pic[-1]) # up: 0, right: 1, down: 2, left: 3
borders["L"] = compileSideBorder(pic, 0)
return borders
for pid, pic in pics.items():
picBorders[pid] = genBorders(pid)
# picmap = dict() # map of the arranged pics
def flip(otherside):
# 0 up, 1 right, 2 down, 3 left
sidething = { # used to rotate as the rotation is allways the opposite relative to the whole system
"U": "D",
"R": "L",
"D": "U",
"L": "R"
}
newotherside = sidething[otherside]
# update the connected tiles rotation
return newotherside
def borderCheck(border, other):
other_rev = other[::-1]
if( border == other or border == other_rev ):
return True, border
else:
return False, other
fitsDict = dd(dict)
# fits struc
#
# fits[id] = { "L": (otherid, rotation) }
# where key = "L", "R", "U", "D", "UL", "UR", "DL", "DR"
# otherid is the one that fits
# rotation is the other that fits rotation to be able to fit
def getFits(borders, fits=fitsDict, ignore=[]):
#print(fits)
#print("\n#", borders, "\n")
ignoreLen = len(ignore)
borLen = len(borders)
print(ignoreLen, borLen)
if(ignoreLen >= borLen):
print("goodbye")
return fits # if there is nothing to do then return the result
newborders = copy(borders)
for pid, border in borders.items(): # borders[pid]
#print(f"\nChecking {pid=}")
if( pid in ignore ):
continue
for pos, bor in border.items(): # check each border : borders[pid][pos]
print(f"##Border {pid=} {pos=} {bor=}")
for pid2, border2 in borders.items(): # check for others borders ; borders[pid2]
if(pid2 == pid or pid2 in ignore):
continue
for pos2, bor2 in border2.items(): # check for other matching border ; borders[pid2][pos2]
check, newBor2 = borderCheck(bor, bor2)
print(f"####Border2 {pid2=} {pos2=} {bor2=} {newBor2=} {check=}")
if(check): # if the two borders match:
fits[pid] = dict()
fits[pid][pos] = (pid2, pos2)
ignore.append(pid)
fits[pid] = fits[pid] or {"E": None} # It has to end somewhere
return getFits(newborders, fits, ignore) # do the other borders
print(picBorders)
fits = getFits(picBorders, fitsDict)
print("------------")
print(fits)
picmap = dd(dict) # inp: coord [][] -> pid
coords = dict() # inp: pid -> out: coord (tuple)
pidList = fits.keys()
firstID = None
for pid in pidList:
firstID = pid
break
# y x
picmap[0][0] = firstID
print(firstID)
for pid, fit in fits.items():
if(pid == firstID):
continue
for pos, fitin in fit.items():
if(pos != "E"):
fitID, fitDIR = fitin[0], fitin[1]
print(f"{pid=} {pos=} : {fitID=} {fitDIR=}")
else:
continue