diff --git a/2020/20.py b/2020/20.py index 3c044c8..a52b793 100755 --- a/2020/20.py +++ b/2020/20.py @@ -4,6 +4,10 @@ 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() @@ -30,14 +34,8 @@ for genpic in data.split("\n\n"): for pid, pic in pics.items(): pics[pid] = np.asarray(pic) -print(pics["3079"]) - -fits = dict() -# fits struc -# -# fits[id] = { "L": (otherid, rotation) } -# where key = "L", "R", "U", "D", "UL", "UR", "DL", "DR" +mapWidth = len(pics) ** (1/2) def compileBorder(row): out = "" @@ -46,7 +44,7 @@ def compileBorder(row): return out -def compileSideBorder(pic, xOffset=0): +def compileSideBorder(pic, xOffset=0): out = "" for row in pic: out += row[xOffset] @@ -61,10 +59,10 @@ def genBorders(picid): ## compile its borders borders = dict() - borders[0] = compileBorder(pic[0]) - borders[1] = compileSideBorder(pic, -1) - borders[2] = compileBorder(pic[-1]) # up: 0, right: 1, down: 2, left: 3 - borders[3] = compileSideBorder(pic, 0) + 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 @@ -74,14 +72,14 @@ for pid, pic in pics.items(): # picmap = dict() # map of the arranged pics -def rotateTile(otherside): +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 - 0: 2, - 1: 3, - 2: 0, - 3: 1 + "U": "D", + "R": "L", + "D": "U", + "L": "R" } newotherside = sidething[otherside] @@ -98,301 +96,84 @@ def borderCheck(border, other): else: return False, other -def getFits(picid, ignoreid): - borders = picBorders[picid] +fitsDict = dd(dict) - seenborders = [] - attachedTiles = [] +# 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 - # if some border match, i.e. this[2] match other[1] then rotate and/or flip other? - # dont actually have to arrange the map, just get stuff that fits together and their IDs - # - # probably gonna be in part 2 idk - match = False - matchID = None - selfSide = None - matchSide = None - matchFlipped = False +def getFits(borders, fits=fitsDict, ignore=[]): + #print(fits) + #print("\n#", borders, "\n") + ignoreLen = len(ignore) + borLen = len(borders) - prevTile = None + print(ignoreLen, borLen) - for side, border in borders.items(): # TODO: make recursive instead and flip (np.fliplr) (and for up-down) - # check other borders - selfSide = side + if(ignoreLen >= borLen): + print("goodbye") + return fits # if there is nothing to do then return the result - for pid, bor in picBorders.items(): - if(pid == picid or pid == ignoreid): - continue + newborders = copy(borders) + for pid, border in borders.items(): # borders[pid] + #print(f"\nChecking {pid=}") + if( pid in ignore ): + continue - # print("Checking", pid, f"{attachedTiles=}") + for pos, bor in border.items(): # check each border : borders[pid][pos] + print(f"##Border {pid=} {pos=} {bor=}") - for pos, line in bor.items(): # top and bottom matching - if(not pos in [0, len(bor)-1]): + for pid2, border2 in borders.items(): # check for others borders ; borders[pid2] + if(pid2 == pid or pid2 in ignore): continue - if(line in seenborders): - continue - - check, newborder = borderCheck(border, line) - print("TB Checking border", pos, ":", line, f"{newborder=} {line=} : {border=}") - - - if( check ): - matchID = pid - matchSide = pos - matchFlipped = line == newborder # flipped from matchSide axis - - if( newborder != line ): - picBorders[pid][pos] = newborder # flip that border if flipped - otherside = rotateTile(pos) - picBorders[pid][otherside] = picBorders[pid][otherside][::-1] # flip the other side too - - match = True - attachedTiles.append(matchID) - seenborders.append(line) - prevTile = matchID - print("MATCH") - break - - if(not match): - - border_left, border_right = "", "" - for y, line in bor.items(): - border_left += line[0] - border_right += line[-1] - - print(f"LR Checking border : {border_left=} {border_right=}") - check_left, newborder_left = borderCheck(border_left, line) - check_right, newborder_right = borderCheck(border_right, line) - - if(check_left): - pos = 3 - matchID = pid - matchSide = pos - matchFlipped = border_left == newborder_left # flipped from matchSide axis - - if( newborder_left != line ): - picBorders[pid][pos] = newborder_left # flip that border if flipped - otherside = rotateTile(pos) - picBorders[pid][otherside] = picBorders[pid][otherside][::-1] # flip the other side too + for pos2, bor2 in border2.items(): # check for other matching border ; borders[pid2][pos2] - match = True - attachedTiles.append(matchID) - seenborders.append(line) - prevTile = matchID - print("MATCH") - break - elif(check_right): - pos = 1 - matchID = pid - matchSide = pos - matchFlipped = border_right == newborder_right # flipped from matchSide axis + check, newBor2 = borderCheck(bor, bor2) + print(f"####Border2 {pid2=} {pos2=} {bor2=} {newBor2=} {check=}") - if( newborder_right != line ): - picBorders[pid][pos] = newborder_right # flip that border if flipped - otherside = rotateTile(pos) - picBorders[pid][otherside] = picBorders[pid][otherside][::-1] # flip the other side too + if(check): # if the two borders match: + fits[pid] = dict() + fits[pid][pos] = (pid2, pos2) - match = True - attachedTiles.append(matchID) - seenborders.append(line) - prevTile = matchID - print("MATCH") - break + ignore.append(pid) + fits[pid] = fits[pid] or {"E": None} # It has to end somewhere + return getFits(newborders, fits, ignore) # do the other borders - else: - break +print(picBorders) - if(match): - return [selfSide, matchID, matchSide, matchFlipped] +fits = getFits(picBorders, fitsDict) +print("------------") +print(fits) +picmap = dd(dict) # inp: coord [][] -> pid +coords = dict() # inp: pid -> out: coord (tuple) -mapWidth = int(len(pics) ** (1/2)) - -tilemap = np.empty([mapWidth, mapWidth], dtype=str) -print("") -print(tilemap) - -aligns = dict() - -#for pid, pic in pics.items(): -nextTile = None -prevTile = None - -for key in pics.keys(): - nextTile = key - prevTile = key +pidList = fits.keys() +firstID = None +for pid in pidList: + firstID = pid break +# y x +picmap[0][0] = firstID +print(firstID) -seenTiles = [] -loop = False -while(not loop): - fits = getFits(nextTile, prevTile) - aligns[nextTile] = fits - - print(fits) - - # prevTile = nextTile - # nextTile = fits[1] - - # if(nextTile in seenTiles): - # loop = True - # break - - # seenTiles.append(prevTile) - # print(prevTile, nextTile, seenTiles) - -print(aligns) - -def copyList(ls): - return [elem for elem in ls] - -# ################ -# exit() -# ################ - - - - - - -def rotateNumTo(numrot, tonum): - tonum = rotateTile(tonum) - # numrot -> tonum - - # get num of rotations clockwise - rots = numrot - tonum - newrot = numrot + rots - - while(newrot < 0): - newrot += 4 - - newrot = newrot % 4 - - return newrot - - -# ---------------------------------------------- -# | 0 1 2 3 | -# |[selfSide, matchID, matchSide, matchFlipped]| -# ---------------------------------------------- - -# for pid, fit in aligns.items(): -# fitid = fit[1] - -# conRot = fit[0] -# myRot = fit[2] - -# newrot = rotateNumTo(myRot, conRot) -# #print(f"{pid=} {fitid=} : {conRot=} {myRot=} : {newrot=}") - -# aligns[fitid][0] = newrot # make others relative - -print("\n\n----") -rotmap = dd(dict) # inp: coords -rotcoords = dd(tuple) # inp: pid - -seenpid = [] - -i = 0 -for pid, align in aligns.items(): - print(pid, align) - - if( i == 0 ): - coords = (0, 0) - rotmap[coords[1]][coords[0]] = pid - rotcoords[pid] = coords - seenpid.append(pid) +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] - - selfside = align[0] - matchside = align[2] - - matchid = align[1] - - - -# while(len(rots) < len(pics)): - -# for pid, fit in aligns.items(): -# if(len(seenpid) >= len(aligns)): -# break - -# if(pid in seenpid): -# continue - -# seenpid.append(pid) - -# if(len(rotmap) <= 0): -# rotmap[0][0] = pid -# rots[pid] = (0, 0) - -# fitid = fit[1] - -# conRot = fit[0] -# myRot = fit[2] - -# coords = rots[pid] -# print(f"{pid} : {coords} : {fitid} |", end=" ") - -# if(len(coords) < 2): -# print("no coords") -# continue - -# x, y = coords[0], coords[1] - -# if(conRot == 0): -# # put the connected one above it -# # x y is reversed because lists index and stuff -# rots[fitid] = (x, y-1) -# print(f"new coord: {rots[fitid]}") - -# elif(conRot == 1): -# # right of -# rots[fitid] = (x+1, y) -# print(f"new coord: {rots[fitid]}") - -# elif(conRot == 2): -# # down of -# rots[fitid] = (x, y+1) -# print(f"new coord: {rots[fitid]}") - -# elif(conRot == 3): -# # left of -# rots[fitid] = (x-1, y) -# print(f"{fitid} new coord: {rots[fitid]}") - - -# print(rots) - -# def rotateClock( rots, picRot, face ): -# clock = copyList(picRot) -# clocklen = len(clock) - -# facei = face - -# facei += rots - -# while(facei < 0): -# facei += clocklen - - -# facei = facei % clocklen -# face = clock[facei] -# return face - - - - -# fitmap = dict() -# for pid, fits in aligns.items(): -# side, fitid, fitside, flipside = fits - -# newside = rotateTile(side, fitside) + print(f"{pid=} {pos=} : {fitID=} {fitDIR=}") + else: + continue