2023 day 10 in Nim
0.01s user 0.01s system 96% cpu 0.021 total
This commit is contained in:
parent
dd09059408
commit
f298850413
|
@ -0,0 +1,103 @@
|
||||||
|
import std/sequtils
|
||||||
|
import std/sugar
|
||||||
|
import std/strutils
|
||||||
|
import std/options
|
||||||
|
import std/sets
|
||||||
|
|
||||||
|
type Point = tuple
|
||||||
|
x: int
|
||||||
|
y: int
|
||||||
|
|
||||||
|
type Area* = ref object
|
||||||
|
data: seq[string]
|
||||||
|
x, y: int
|
||||||
|
|
||||||
|
proc charAt(a: Area, p: Point): char =
|
||||||
|
a.data[p.x][p.y]
|
||||||
|
|
||||||
|
proc findStart(a: Area): Point =
|
||||||
|
for x in 0..a.x - 1:
|
||||||
|
for y in 0..a.y - 1:
|
||||||
|
let p = (x, y)
|
||||||
|
if a.charAt(p) == 'S':
|
||||||
|
return p
|
||||||
|
|
||||||
|
proc neighbours(p: Point, c: char): seq[Point] =
|
||||||
|
case c:
|
||||||
|
of '|': @[(p.x + 1, p.y), (p.x - 1, p.y)]
|
||||||
|
of '-': @[(p.x, p.y + 1), (p.x, p.y - 1)]
|
||||||
|
of 'J': @[(p.x - 1, p.y), (p.x, p.y - 1)]
|
||||||
|
of '7': @[(p.x + 1, p.y), (p.x, p.y - 1)]
|
||||||
|
of 'F': @[(p.x + 1, p.y), (p.x, p.y + 1)]
|
||||||
|
of 'L': @[(p.x - 1, p.y), (p.x, p.y + 1)]
|
||||||
|
else: @[]
|
||||||
|
|
||||||
|
proc isWithin(p: Point, b: Area): bool =
|
||||||
|
p.x >= 0 and p.y >= 0 and p.x < b.x and p.y < b.y
|
||||||
|
|
||||||
|
proc determineStartType(start: Point, a: Area): char =
|
||||||
|
for option in "|-J7FL":
|
||||||
|
let neighs = neighbours(start, option).filterIt(it.isWithin(a))
|
||||||
|
if neighs.all(n => neighbours(n, a.charAt(n)).anyIt(it == start)):
|
||||||
|
return option
|
||||||
|
|
||||||
|
proc nextStep(a: Area, p: Point, visited: HashSet[Point]): Option[Point] =
|
||||||
|
let n = neighbours(p, a.charAt(p)).filterIt(not visited.contains(it))
|
||||||
|
if n == @[]:
|
||||||
|
none(Point)
|
||||||
|
else:
|
||||||
|
some(n[0])
|
||||||
|
|
||||||
|
proc isInside(a: Area, p: Point, v: HashSet[Point]): bool =
|
||||||
|
if v.contains(p):
|
||||||
|
return false
|
||||||
|
|
||||||
|
var inside = false
|
||||||
|
var x = p.x
|
||||||
|
var y = p.y
|
||||||
|
while (x, y).isWithin(a):
|
||||||
|
let c = a.charAt((x, y))
|
||||||
|
if v.contains((x, y)) and c != 'L' and c != '7':
|
||||||
|
inside = not inside
|
||||||
|
x += 1
|
||||||
|
y += 1
|
||||||
|
inside
|
||||||
|
|
||||||
|
proc main() =
|
||||||
|
let s = readAll(stdin)
|
||||||
|
var lines = splitLines(s)
|
||||||
|
|
||||||
|
var a = Area(data: lines, x: (len lines) - 1, y: len lines[0])
|
||||||
|
|
||||||
|
let start = a.findStart()
|
||||||
|
a.data[start.x][start.y] = determineStartType(start, a)
|
||||||
|
|
||||||
|
var visited: HashSet[Point] = initHashSet[Point]()
|
||||||
|
|
||||||
|
var np = start
|
||||||
|
while true:
|
||||||
|
visited.incl(np)
|
||||||
|
let nop = nextStep(a, np, visited)
|
||||||
|
if nop.isNone:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
np = nop.get()
|
||||||
|
|
||||||
|
let length = (len visited) div 2
|
||||||
|
|
||||||
|
for x in 0..a.x - 1:
|
||||||
|
for y in 0..a.y - 1:
|
||||||
|
if not visited.contains((x, y)):
|
||||||
|
a.data[x][y] = '.'
|
||||||
|
|
||||||
|
var counter = 0
|
||||||
|
for x in 0..a.x - 1:
|
||||||
|
for y in 0..a.y - 1:
|
||||||
|
if isInside(a, (x, y), visited):
|
||||||
|
counter += 1
|
||||||
|
|
||||||
|
echo "Part 1: $1" % [$length]
|
||||||
|
echo "Part 2: $1" % [$counter]
|
||||||
|
|
||||||
|
when isMainModule:
|
||||||
|
main()
|
|
@ -0,0 +1,5 @@
|
||||||
|
.....
|
||||||
|
.S-7.
|
||||||
|
.|.|.
|
||||||
|
.L-J.
|
||||||
|
.....
|
|
@ -0,0 +1,5 @@
|
||||||
|
..F7.
|
||||||
|
.FJ|.
|
||||||
|
SJ.L7
|
||||||
|
|F--J
|
||||||
|
LJ...
|
|
@ -0,0 +1,9 @@
|
||||||
|
...........
|
||||||
|
.S-------7.
|
||||||
|
.|F-----7|.
|
||||||
|
.||.....||.
|
||||||
|
.||.....||.
|
||||||
|
.|L-7.F-J|.
|
||||||
|
.|..|.|..|.
|
||||||
|
.L--J.L--J.
|
||||||
|
...........
|
Loading…
Reference in New Issue