aoc-all

My solutions to all Advent of Code
git clone https://git.instinctive.eu/aoc-all.git
Log | Files | Refs | README | LICENSE

commit c1f229bec1b84a4759dbbae19f198d47d3ce3ce3
parent b4ccb3a2eff5bda2b0ba6227d85d9a3ea559fc0e
Author: Natasha Kerensikova <natgh@instinctive.eu>
Date:   Sat, 21 Dec 2024 17:08:58 +0000

Day 21 reference and solutions
Diffstat:
A2024/day21.nim | 211+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A2024/ref/day21.txt | 5+++++
2 files changed, 216 insertions(+), 0 deletions(-)

diff --git a/2024/day21.nim b/2024/day21.nim @@ -0,0 +1,211 @@ +# Copyright (c) 2024, Natacha Porté +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +from std/sequtils import concat, filterIt, foldl, map, mapIt, toSeq, zip +from std/strutils import parseInt, repeat +from std/tables import `[]`, `[]=`, hasKey, Table, toTable, pairs, keys + +# Read input file + +type + Point = tuple + x, y: int + +let + data = stdin.lines().toSeq() + num_pad = { + '7': (x: 0, y: 0), + '8': (x: 1, y: 0), + '9': (x: 2, y: 0), + '4': (x: 0, y: 1), + '5': (x: 1, y: 1), + '6': (x: 2, y: 1), + '1': (x: 0, y: 2), + '2': (x: 1, y: 2), + '3': (x: 2, y: 2), + '*': (x: 0, y: 3), + '0': (x: 1, y: 3), + 'A': (x: 2, y: 3) + }.toTable + dir_pad = { + '*': (x: 0, y: 0), + '^': (x: 1, y: 0), + 'A': (x: 2, y: 0), + '<': (x: 0, y: 1), + 'v': (x: 1, y: 1), + '>': (x: 2, y: 1) + }.toTable + +# Puzzle 1 + +func minimize(s: seq[string]): seq[string] = + let l = min(s.mapIt(len(it))) + result = s.filterIt(len(it) == l) + +func cat4(a, b, c, d: string): string = a & b & c & d + +proc cmd(s: string, pad: Table[char, Point]): seq[string] = + var p = pad['A'] + result = @[""] + for d in s.mapIt(pad[it]): + var h, v: string + if d.y > p.y: + v = repeat('v', d.y - p.y) + if d.y < p.y: + v = repeat('^', p.y - d.y) + if d.x > p.x: + h = repeat('>', d.x - p.x) + if d.x < p.x: + h = repeat('<', p.x - d.x) + + if h == "" or v == "" or pad['*'] == (x: p.x, y: d.y): + result = result.mapIt(cat4(it, h, v, "A")) + elif pad['*'] == (x: d.x, y: p.y): + result = result.mapIt(cat4(it, v, h, "A")) + else: + result = concat(result.mapIt(cat4(it, h, v, "A")), result.mapIt(cat4(it, v, h, "A"))) + + p = d + + result = minimize(result) + +proc cmd_seq(s: seq[string], pad: Table[char, Point]): seq[string] = + for c in s: + result = minimize(concat(result, cmd(c, pad))) + +proc puzzle1(s: string): int = + let + s1 = cmd(s, num_pad) + s2 = cmd_seq(s1, dir_pad) + s3 = cmd_seq(s2, dir_pad) + n = parseInt(s[0 .. ^2]) + result = len(s3[0]) * n + +echo "Puzzle 1: ", data.map(puzzle1).foldl(a + b) + +# Puzzle 2 +# 154115708116294 is too low + +var memo: Table[(char, char, int), int] + +proc base_steps(start, dest: char, depth: int, pad: Table[char, Point]): int + +proc steps(start, dest: char, depth: int): int = + if start == dest: + return 1 + elif memo.hasKey((start, dest, depth)): + return memo[(start, dest, depth)] + result = base_steps(start, dest, depth, dir_pad) +# echo repeat(" ", depth), "storing(", start, ", ", dest, ", ", depth, "): ", result + memo[(start, dest, depth)] = result + +proc base_steps(start, dest: char, depth: int, pad: Table[char, Point]): int = + let + ps = pad[start] + pd = pad[dest] + cx = if ps.x < pd.x: '>' elif ps.x > pd.x: '<' else: '.' + cy = if ps.y < pd.y: 'v' elif ps.y > pd.y: '^' else: '.' + dx = abs (ps.x - pd.x) + dy = abs (ps.y - pd.y) + if depth == 0: + return dx + dy + 1 + + if dx == 0: + assert dy > 0 + result = steps('A', cy, depth - 1) + (dy-1) + steps(cy, 'A', depth - 1) + elif dy == 0: + assert dx > 0 + result = steps('A', cx, depth - 1) + (dx-1) + steps(cx, 'A', depth - 1) + elif pad['*'] == (x: pd.x, y: ps.y): + result = steps('A', cy, depth - 1) + (dy-1) + steps(cy, cx, depth - 1) + (dx-1) + steps(cx, 'A', depth - 1) + elif pad['*'] == (x: ps.x, y: pd.y): + result = steps('A', cx, depth - 1) + (dx-1) + steps(cx, cy, depth - 1) + (dy-1) + steps(cy, 'A', depth - 1) + else: + let + rvh = steps('A', cy, depth - 1) + (dy-1) + steps(cy, cx, depth - 1) + (dx-1) + steps(cx, 'A', depth - 1) + rhv = steps('A', cx, depth - 1) + (dx-1) + steps(cx, cy, depth - 1) + (dy-1) + steps(cy, 'A', depth - 1) + result = min(rvh, rhv) + +proc full_steps(s: string, depth: int): int = + for (s,d) in zip("A" & s[0 .. ^2], s): + result += base_steps(s, d, depth, num_pad) + +proc puzzle2(s: string, depth: int): int = + full_steps(s, depth) * parseInt(s[0 .. ^2]) + +for cmd in data: +# echo cmd, ": ", full_steps(cmd, 2) + assert puzzle2(cmd, 2) == puzzle1(cmd) + +echo "Puzzle 2: ", data.mapIt(puzzle2(it, 25)).foldl(a + b) + +var debug_memo: Table[(char, char, int), string] + +proc debug_base_steps(start, dest: char, depth: int, pad: Table[char, Point]): string + +proc debug_steps(start, dest: char, depth: int): string = + if start == dest: + return "A" + elif debug_memo.hasKey((start, dest, depth)): + return debug_memo[(start, dest, depth)] + result = debug_base_steps(start, dest, depth, dir_pad) + echo repeat(" ", 4 - depth), "storing(", start, ", ", dest, ", ", depth, "): ", result + debug_memo[(start, dest, depth)] = result + +proc debug_base_steps(start, dest: char, depth: int, pad: Table[char, Point]): string = + let + ps = pad[start] + pd = pad[dest] + cx = if ps.x < pd.x: '>' elif ps.x > pd.x: '<' else: '.' + cy = if ps.y < pd.y: 'v' elif ps.y > pd.y: '^' else: '.' + dx = abs (ps.x - pd.x) + dy = abs (ps.y - pd.y) + if depth == 0: + if pad['*'] == (x: pd.x, y: ps.y): + return repeat(cy, dy) & repeat(cx, dx) & "A" + else: + return repeat(cx, dx) & repeat(cy, dy) & "A" + + if dx == 0: + assert dy > 0 + echo repeat(" ", 4 - depth), "expanding(", start, ", ", dest, ", ", depth, "): \"", repeat(cy, dy), "A\"" + result = debug_steps('A', cy, depth - 1) & repeat('A', dy-1) & debug_steps(cy, 'A', depth - 1) + elif dy == 0: + assert dx > 0 + echo repeat(" ", 4 - depth), "expanding(", start, ", ", dest, ", ", depth, "): \"", repeat(cx, dx), "A\"" + result = debug_steps('A', cx, depth - 1) & repeat('A', dx-1) & debug_steps(cx, 'A', depth - 1) + elif pad['*'] == (x: pd.x, y: ps.y): + echo repeat(" ", 4 - depth), "expanding(", start, ", ", dest, ", ", depth, "): \"", repeat(cy, dy), repeat(cx, dx), "A\"" + result = debug_steps('A', cy, depth - 1) & repeat('A', dy-1) & debug_steps(cy, cx, depth - 1) & repeat('A', dx-1) & debug_steps(cx, 'A', depth - 1) + elif pad['*'] == (x: ps.x, y: pd.y): + echo repeat(" ", 4 - depth), "expanding(", start, ", ", dest, ", ", depth, "): \"", repeat(cx, dx), repeat(cy, dy), "A\"" + result = debug_steps('A', cx, depth - 1) & repeat('A', dx-1) & debug_steps(cx, cy, depth - 1) & repeat('A', dy-1) & debug_steps(cy, 'A', depth - 1) + else: + echo repeat(" ", 4 - depth), "expanding(", start, ", ", dest, ", ", depth, "): \"", repeat(cx, dx), repeat(cy, dy), "A\" and \"", repeat(cy, dy), repeat(cx, dx), "A\"" + let + rvh = debug_steps('A', cy, depth - 1) & repeat('A', dy-1) & debug_steps(cy, cx, depth - 1) & repeat('A', dx-1) & debug_steps(cx, 'A', depth - 1) + rhv = debug_steps('A', cx, depth - 1) & repeat('A', dx-1) & debug_steps(cx, cy, depth - 1) & repeat('A', dy-1) & debug_steps(cy, 'A', depth - 1) + if len(rvh) < len(rvh): + echo repeat(" ", 4 - depth), "↳ choosing \"", repeat(cy, dy), repeat(cx, dx), "A\" (", len(rvh), " over ", len(rhv), ")" + result = rvh + else: + echo repeat(" ", 4 - depth), "↳ choosing \"", repeat(cx, dx), repeat(cy, dy), "A\" (", len(rhv), " over ", len(rvh), ")" + result = rhv + +proc debug_full_steps(s: string, depth: int): string = + for (s,d) in zip("A" & s[0 .. ^2], s): + result &= debug_base_steps(s, d, depth, num_pad) + +# for cmd in data: +# echo cmd, ": ", debug_full_steps(cmd, 2) diff --git a/2024/ref/day21.txt b/2024/ref/day21.txt @@ -0,0 +1,5 @@ +029A +980A +179A +456A +379A