77 lines
1.8 KiB
Nim
77 lines
1.8 KiB
Nim
|
|
import std/sequtils
|
|
import std/strutils
|
|
import tables
|
|
|
|
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]
|
|
|
|
iterator eachPChar(a: Area): (Point, char) =
|
|
for x in 0..a.x - 1:
|
|
for y in 0..a.y - 1:
|
|
let p = (x, y)
|
|
yield (p, a.charAt(p))
|
|
|
|
iterator column(a: Area, y: int): char =
|
|
for x in 0..a.x - 1:
|
|
yield a.charAt((x, y))
|
|
|
|
proc realPosition(t: Table[Point, Point], g: Point): Point =
|
|
let offset = t[g]
|
|
(g.x + offset.x, g.y + offset.y)
|
|
|
|
proc solve(a: Area, galaxies: Table[Point, Point], offset: int): int =
|
|
var galaxies = galaxies
|
|
let offset = offset - 1
|
|
|
|
for x in 0..a.x - 1:
|
|
if a.data[x].allIt(it == '.'):
|
|
for pos, off in galaxies:
|
|
if pos.x > x:
|
|
galaxies[pos] = (off.x + offset, off.y)
|
|
|
|
for y in 0..a.y - 1:
|
|
if a.column(y).toSeq.allIt(it == '.'):
|
|
for pos, off in galaxies:
|
|
if pos.y > y:
|
|
galaxies[pos] = (off.x, off.y + offset)
|
|
|
|
var distances = initTable[(Point, Point), int]()
|
|
for g1 in galaxies.keys:
|
|
for g2 in galaxies.keys:
|
|
if g1 != g2 and (g1, g2) notin distances and (g2, g1) notin distances:
|
|
let r1 = realPosition(galaxies, g1)
|
|
let r2 = realPosition(galaxies, g2)
|
|
let d = abs(r1.x - r2.x) + abs(r1.y - r2.y)
|
|
distances[(g1, g2)] = d
|
|
|
|
distances.values.toSeq.foldl(a + b)
|
|
|
|
proc main() =
|
|
let s = readAll(stdin)
|
|
var lines = splitLines(s)
|
|
|
|
let a = Area(data: lines, x: (len lines) - 1, y: len lines[0])
|
|
|
|
var galaxies = initTable[Point, Point]()
|
|
for p, c in a.eachPChar:
|
|
if c == '#':
|
|
galaxies[p] = (0, 0)
|
|
|
|
let p1 = solve(a, galaxies, 2)
|
|
let p2 = solve(a, galaxies, 1000000)
|
|
|
|
echo "Part 1: $1" % [$p1]
|
|
echo "Part 2: $1" % [$p2]
|
|
|
|
when isMainModule:
|
|
main()
|