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