88 lines
2.6 KiB
Nim
88 lines
2.6 KiB
Nim
|
import std/[cmdline, sequtils, strformat, strutils, sugar, tables]
|
||
|
|
||
|
type Position = tuple
|
||
|
row: int
|
||
|
col: int
|
||
|
|
||
|
## Check if any of the grid cells adjacent to position (i, j) match condition cond.
|
||
|
proc isAdjacentToCond(grid: seq[seq[char]], row, col: int, cond: (char) -> bool): Position =
|
||
|
for i in @[row - 1, row, row + 1]:
|
||
|
if i < 0 or i >= grid.len:
|
||
|
continue
|
||
|
for j in @[col - 1, col, col + 1]:
|
||
|
if i == row and j == col:
|
||
|
continue
|
||
|
if j < 0 or j >= grid[i].len:
|
||
|
continue
|
||
|
var ch = grid[i][j]
|
||
|
if cond(ch):
|
||
|
return (i, j)
|
||
|
return (-1, -1)
|
||
|
|
||
|
|
||
|
var fn = if paramCount() > 0: paramStr(1) else: "input_03.txt"
|
||
|
var result = 0
|
||
|
# read input file as seq of lines
|
||
|
var lines = readFile(fn).strip.splitLines
|
||
|
# allocate 2-D seq to hold ros and colums of characters
|
||
|
var grid = newSeqWith(lines.len, newSeq[char](lines[0].strip.len))
|
||
|
# table to save positions of gears and parts connected to it
|
||
|
var gears = initTable[Position, seq[int]]()
|
||
|
|
||
|
# Parse input
|
||
|
for i, line in lines:
|
||
|
for j, ch in line.strip:
|
||
|
grid[i][j] = ch
|
||
|
|
||
|
#echo &"Rows: {grid.len}"
|
||
|
#echo &"Cols: {grid[0].len}"
|
||
|
|
||
|
# Go through grid and find positions of gears
|
||
|
for i, row in grid:
|
||
|
var
|
||
|
isConnectedToGear = false
|
||
|
gear: Position
|
||
|
number = ""
|
||
|
|
||
|
for j, ch in row:
|
||
|
if ch.isDigit:
|
||
|
number &= ch
|
||
|
# Scan adjacent grid cells gor a gear ('*')
|
||
|
var symbol = isAdjacentToCond(grid, i, j, (c) => c == '*')
|
||
|
|
||
|
if symbol != (-1, -1):
|
||
|
# It's a number adjacent to a gear!
|
||
|
isConnectedToGear = true
|
||
|
gear = symbol
|
||
|
if not gears.hasKey(gear):
|
||
|
# save gear position in table
|
||
|
gears[gear] = newSeq[int]()
|
||
|
else:
|
||
|
if isConnectedToGear:
|
||
|
# add part to gear position saved above
|
||
|
# we can save an infinite amount of parts per gear
|
||
|
# but we assume that at most two parts are connected to a gear
|
||
|
gears[gear].add(number.parseInt)
|
||
|
|
||
|
number = ""
|
||
|
isConnectedToGear = false
|
||
|
|
||
|
# account for numbers going until the end of the row
|
||
|
if isConnectedToGear:
|
||
|
# add part to gear position saved above
|
||
|
gears[gear].add(number.parseInt)
|
||
|
|
||
|
# Sum up gear ratios
|
||
|
for pos, parts in gears:
|
||
|
# Ignore gears conencted to only one part
|
||
|
if parts.len > 1:
|
||
|
result += parts[0] * parts[1]
|
||
|
|
||
|
echo &"Result: {result}"
|
||
|
|
||
|
case fn:
|
||
|
of "input_03.txt":
|
||
|
assert result == 86841457
|
||
|
of "sample_input_03.txt":
|
||
|
assert result == 467835
|