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