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.

323 lines
7.4 KiB

4 years ago
#!/usr/bin/env python
4 years ago
from collections import defaultdict as dd
4 years ago
from aoc import get_input # AoC
import re # regex
import numpy as np
4 years ago
from copy import deepcopy as copy
from sys import setrecursionlimit
setrecursionlimit(20000)
4 years ago
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 = int(len(pics) ** (1/2))
4 years ago
def compileBorder(row):
out = ""
for char in row:
out += char
return out
4 years ago
def compileSideBorder(pic, xOffset=0):
4 years ago
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()
4 years ago
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)
4 years ago
return borders
for pid, pic in pics.items():
picBorders[pid] = genBorders(pid)
# picmap = dict() # map of the arranged pics
4 years ago
def flip(otherside):
4 years ago
# 0 up, 1 right, 2 down, 3 left
sidething = { # used to rotate as the rotation is allways the opposite relative to the whole system
4 years ago
"U": "D",
"R": "L",
"D": "U",
"L": "R"
4 years ago
}
newotherside = sidething[otherside]
# update the connected tiles rotation
return newotherside
4 years ago
def borderCheck(border, other):
other_rev = other[::-1]
if( border == other or border == other_rev ):
return True, border
else:
return False, other
4 years ago
fitsDict = dd(dict)
4 years ago
4 years ago
# 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
4 years ago
def getFits(borders, fits=fitsDict, ignore=[], ignoreBorder=[]):
4 years ago
#print(fits)
#print("\n#", borders, "\n")
ignoreLen = len(ignoreBorder)
4 years ago
borLen = len(borders)
4 years ago
4 years ago
if(ignoreLen >= borLen):
#print("goodbye")
4 years ago
return fits # if there is nothing to do then return the result
4 years ago
4 years ago
newborders = copy(borders)
for pid, border in borders.items(): # borders[pid]
#print(f"\nChecking {pid=}")
if( pid in ignore ):
continue
4 years ago
4 years ago
for pos, bor in border.items(): # check each border : borders[pid][pos]
4 years ago
#print(f"##Border {pid=} {pos=} {bor=}")
4 years ago
4 years ago
for pid2, border2 in borders.items(): # check for others borders ; borders[pid2]
if(pid2 == pid or pid2 in ignore or border2 in ignoreBorder):
4 years ago
continue
4 years ago
4 years ago
for pos2, bor2 in border2.items(): # check for other matching border ; borders[pid2][pos2]
4 years ago
4 years ago
check, newBor2 = borderCheck(bor, bor2)
#print(f"####Border2 {pid2=} {pos2=} {bor2=} {newBor2=} {check=}")
if( not check ):
continue
4 years ago
4 years ago
if(check): # if the two borders match:
fits[pid] = fits[pid] or dict()
4 years ago
fits[pid][pos] = [pid2, pos2]
4 years ago
#ignore.append(pid)
ignoreBorder.append(bor2)
4 years ago
4 years ago
fits[pid] = fits[pid] or {"E": None} # It has to end somewhere
4 years ago
4 years ago
return getFits(newborders, fits, ignore) # do the other borders
4 years ago
4 years ago
4 years ago
fits = getFits(picBorders, fitsDict)
4 years ago
fitsListKeys = list(fits.keys())
4 years ago
#picmap = [["#" for x in range(mapWidth)] for y in range(mapWidth)] # inp: coord [][] -> pid
picmap = dd(dict)
piccoords = dict() # inp: pid -> out: coord (tuple)
4 years ago
seenPics = []
def translatePos(pos, x, y):
if(pos == "U"):
return x, y-1
elif(pos == "D"):
return x, y+1
elif(pos == "L"):
return x-1, y
elif(pos == "R"):
return x+1, y
def setPos(pid, x, y, pmap, coords, seen=[]):
pmap[y] = pmap[y] or dict()
pmap[y][x] = pid
coords[pid] = (x, y)
4 years ago
seen.add(pid)
return seen
4 years ago
def getPos(x, y, pmap):
try:
pid = pmap[y][x]
4 years ago
if( pid == "----" ):
4 years ago
return None
else:
return pid
except:
return None
def printMap(pmap):
4 years ago
for y in range(mapWidth):
row = pmap[y]
4 years ago
for x in range(mapWidth):
try:
4 years ago
print( row[x], end=" " )
except:
4 years ago
print("----", end=" ")
4 years ago
print("\n")
4 years ago
def findContainer(sid, fits):
foundContainers = []
for pid, fit in fits.items():
for f in fit.values():
if(sid in f):
foundContainers.append(pid)
4 years ago
return foundContainers
4 years ago
corners = []
cornersPos = dict()
4 years ago
# thingid = "1129"
# thing = fits[thingid]["U"]
# fits[thingid]["D"] = thing
# fits[thingid].pop("U")
4 years ago
for pid, cont in fits.items():
if(len(cont) == 2):
corners.append(pid)
4 years ago
print("corner:", pid, cont)
4 years ago
prod = 1
for c in corners:
prod *= int(c)
4 years ago
print("Part1:", prod)
4 years ago
print("\n\n")
4 years ago
seenid = set()
4 years ago
# know the corners
# start from corner 1 then 2, then update 3 and 4
#
# 1---------2
# | |
# | stuff |
# | here |
# | |
# 3---------4
4 years ago
# append the first corner at 0, 0
4 years ago
mapW = mapWidth - 1
4 years ago
for y in range(mapWidth):
for x in range(mapWidth):
4 years ago
picmap[y][x] = "----"
4 years ago
seenid = setPos(corners[0], 0, 0, picmap, piccoords, seenid) # some corner
print("####", corners)
4 years ago
i = 0
4 years ago
def getRotIndex(rot):
return ["U", "R", "D", "L"].index(rot)
4 years ago
def rotateDirs(pid, rot, fits):
irot = getRotIndex(rot)
cont = fits[pid]
4 years ago
newcont = copy(cont)
4 years ago
for pos, stuff in cont.items():
ipos = getRotIndex(pos)
diff = ipos - irot
4 years ago
while(diff < 0):
diff += 4
newpos = ["U", "R", "D", "L"][(ipos + diff) % 4]
newcont[newpos] = stuff
fits[pid] = newcont
return fits[pid]
# U -> L
# => new = U -> rotate(L)
4 years ago
def genPicMap(pmap=picmap, pcoords=piccoords, fits=fits, seenid=set()):
for y in range(mapWidth):
for x in range(mapWidth):
pidAtPos = getPos(x, y, pmap)
if(pidAtPos):
fit = fits[pidAtPos] # possible connections
print(f"\n{pidAtPos}: {fit}")
for pos, child in fit.items():
4 years ago
childID, childRot = child[0], child[1]
if(childID in seenid):
4 years ago
continue
nx, ny = translatePos(pos, x, y)
pidInSpace = getPos(nx, ny, pmap) # check if there is something there
print(f"{pos=} {child=} : {pidInSpace=} {nx,ny=}")
if(pidInSpace or nx < 0 or ny < 0):
continue
4 years ago
# update the childs rotation
fits[childID] = rotateDirs(childID, pos, fits)
4 years ago
4 years ago
# add it to the pos
seenid = setPos(childID, nx, ny, pmap, pcoords, seenid)
4 years ago
while( True ):
genPicMap()
print("")
printMap(picmap)
breakpoint()