diff --git a/day23/sol.ivy b/day23/sol.ivy index 0ce0400..e18d351 100644 --- a/day23/sol.ivy +++ b/day23/sol.ivy @@ -1,7 +1,8 @@ )get "input.ivy" sample = 7 7 rho '....#..' '..###.#' '#...#.#' '.#...##' '#.###..' '##.#.##' '.#..#..' -board = sample == '#' +#board = sample == '#' +board = input == '#' #board op north a = 1 flip a @@ -11,6 +12,9 @@ op east a = -1 rot a #north 3 3 rho iota 9 +op lift a = (1,rho a) rho a +op n moveNSWE a = (lift n flip a[1]), (lift (-n) flip a[2]), (lift n rot a[3]), (lift (-n) rot a[4]) + op a coalesce b = a: a b @@ -22,43 +26,102 @@ op maybePad a = needsPad a: pad a a +op maybePad1 a = + c1 = any a[1] + c2 = any a[(rho a)[1]] + c1 and c2: 0,a,0 + c1: 0,a + c2: a,0 + a + +op maybePad a = + a = maybePad1 a + (any a[;1]) or (any a[;(rho a)[2]]): transp maybePad1 transp a + a op smearWE a = a or (west a) or (east a) op smearNS a = a or (north a) or (south a) -op lift a = (1,rho a) rho a op show a = (text ".#23456789"[1+a]),"\n-" M = 0 -a = maybePad board -n = south smearWE a -s = north smearWE a -e = west smearNS a -w = east smearNS a -#n +op axis1 a = 3 1 2 transp a -p = 4 3 2 1 +op look a = + ns = lift smearNS a + we = lift smearWE a + -1 moveNSWE (we, we, ns, ns) -C = (lift n) , (lift s) , (lift w) , (lift e) -rho C -canMove = a and or/ 3 1 2 transp C # can move if there is an elf nearby -C2 = (not C) and (rho C) rho canMove # can move in a direction if not alone and there is no elf in that direction -show C2 -P1 = max/ p * 3 1 2 transp C2 # select direction -P2 = p o.== P1 # decompose into 4x?x? matrix -P1; "\n-" -C3 = (north P2[1]) + (south P2[2]) + (west P2[3]) + (east P2[4]) -C3; "\n-" -notBlock = C3 == 1 -C4 = (lift south notBlock), (lift north notBlock), (lift east notBlock), (lift west notBlock) -rho C4 -P3 = P2 and C4 -show P3 -moved = or/ 3 1 2 transp P3 -moved -#a and not moved -#show P3 -B = (a and not moved) + (north P3[1]) + (south P3[2]) + (west P3[3]) + (east P3[4]) -show a -show B +op dup4 a = (4,rho a) rho a + +# look in each direction +# an elf can move in a direction if there is no elf in said direction and there is an elf somewhere nearby +# returns a 4x(rho a) matrix +op canMove a = + C = look a + (not C) and dup4 (a and or/axis1 C) + + +# prepare moves +# assign each move a priority and take the max +# remove lower priority moves +op p prepare choices = + best = max/ p * axis1 choices # select best direction + p o.== best # decompose into 4x?x? matrix + +# count how many elves want to move to each square +# filter out moves which conflict +op unblocked moves = + open = 1 == +/axis1 1 moveNSWE moves + moves and -1 moveNSWE dup4 open + +priority = 4 3 2 1 +M = 0 +changed = 0 + +op M round a = + a = maybePad a + moves = unblocked (M flip priority) prepare canMove a + moved = or/axis1 moves + changed; changed = +/, moved + b = (a and not moved) + +/axis1 1 moveNSWE moves + b + +op round a = M round a + +# this is implemented using globals +# to store the board instead of recursion +# in order to avoid keeping a bunch of large +# intermediate values alive on the stack +B = 0 +op i loop n = + i > n: i + changed; changed = 0 + B = M round B + M = M - 1 + changed == 0: i + (i+1) loop n + +op n rounds a = + B; B = a + M; M = 0 + 1 loop n + B + +op n numrounds a = + B; B = a + M; M = 0 + 1 loop n + +op score a = + a = maybePad a + n = */ (rho a) - 2 + n - +/, a + +show round board +show 10 rounds board +score 10 rounds board + +1000 numrounds board +#numrounds board