aoc-all

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

commit 4d1738b65192275992640f00d64ca2b6e1d348ef
parent b97116b99d30c161899d7e91b7ae03ec9983bded
Author: Natasha Kerensikova <natgh@instinctive.eu>
Date:   Wed, 18 Dec 2024 19:03:22 +0000

Day 18 reference and solutions
Diffstat:
A2024/day18.nim | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A2024/ref/day18.txt | 25+++++++++++++++++++++++++
2 files changed, 122 insertions(+), 0 deletions(-)

diff --git a/2024/day18.nim b/2024/day18.nim @@ -0,0 +1,97 @@ +# 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 addUnique, concat, map, mapIt, newSeqWith, toSeq +from std/strutils import split, parseInt, repeat +from std/tables import `[]`, `[]=`, contains, getOrDefault, initTable, Table + +# Read input file + +type + Point = tuple + x, y: int + +func `+`(a, b: Point): Point = (x: a.x + b.x, y: a.y + b.y) +func `[]`(m: seq[string], p: Point): char = m[p.y][p.x] +proc `[]=`(m: var seq[string], p: Point, c: char): void = m[p.y][p.x] = c + +func seq_to_point(s: seq[int]): Point = + assert len(s) == 2 + result = (x: s[0], y: s[1]) + +let + data = stdin.lines().toSeq().mapIt(seq_to_point(it.split(",").map(parseInt))) + xmax = max(data.mapIt(it[0])) + ymax = max(data.mapIt(it[1])) + +# Puzzle 1 + +func next(unvisited: seq[Point], scores: Table[Point, int]): (int, int) = + result = (0, scores[unvisited[0]]) + for i in 1 ..< len(unvisited): + let s = scores[unvisited[i]] + if i == 0 or s < result[1]: + result = (i, s) + +proc update(unvisited: var seq[Point], scores: var Table[Point, int], d: seq[string], p: Point, s: int): void = + if p.x < 0 or p.y < 0 or p.y >= len(d) or p.x >= len(d[p.y]) or d[p] == '#': + return + if not scores.contains(p) or scores[p] > s: + unvisited.addUnique(p) + scores[p] = s + +func to_map(blocks: seq[Point], xmax, ymax: int): seq[string] = + result = newSeqWith(ymax + 1, repeat('.', xmax + 1)) + for b in blocks: + result[b] = '#' + +func answer1(blocks: seq[Point], xmax, ymax: int): int = + let m = to_map(blocks, xmax, ymax) + var + scores = initTable[Point, int]() + unvisited = @[(x: 0, y: 0)] + scores[unvisited[0]] = 0 + while len(unvisited) > 0: + let + (i, s) = next(unvisited, scores) + p = unvisited[i] + if p.x == xmax and p.y == ymax: + return s + unvisited = concat(unvisited[0 ..< i], unvisited[i + 1 .. ^1]) + update(unvisited, scores, m, (x: p.x + 1, y: p.y), s + 1) + update(unvisited, scores, m, (x: p.x - 1, y: p.y), s + 1) + update(unvisited, scores, m, (x: p.x, y: p.y + 1), s + 1) + update(unvisited, scores, m, (x: p.x, y: p.y - 1), s + 1) + return -1 + +echo "Puzzle 1: ", answer1(data, xmax, ymax) + +# Puzzle 2 + +var + bottom = 0 + top = len(data) - 1 + +if answer1(data[0 .. bottom], xmax, ymax) >= 0 and answer1(data[0 .. top], xmax, ymax) < 0: +# echo "starting with ", bottom, " .. ", top + while top - bottom >= 2: + let + mid = bottom + (top - bottom) div 2 + s = answer1(data[0 .. mid], xmax, ymax) +# echo mid, ": ", s + if s >= 0: + bottom = mid + else: + top = mid + echo "Puzzle 2: ", data[top].x, ",", data[top].y, " (", top, ")" diff --git a/2024/ref/day18.txt b/2024/ref/day18.txt @@ -0,0 +1,25 @@ +5,4 +4,2 +4,5 +3,0 +2,1 +6,3 +2,4 +1,5 +0,6 +3,3 +2,6 +5,1 +1,2 +5,5 +2,5 +6,5 +1,4 +0,4 +6,4 +1,1 +6,1 +1,0 +0,5 +1,6 +2,0