adventofcode2021/day05/part1.nim

92 lines
2.7 KiB
Nim

# Copyright 2021 Christian Ulrich
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# usage: ./part1 < input
import sequtils
import strutils
type
Point = tuple[x: uint16, y: uint16]
Line = tuple[start: Point, `end`: Point]
Orientation = enum
Horizontal, Vertical, Diagonal
Area = array[1000, array[1000, uint8]]
proc orientation(line: Line): Orientation =
if line.start.y == line.end.y:
result = Horizontal
elif line.start.x == line.end.x:
result = Vertical
else:
result = Diagonal
proc add(area: var Area, line: Line) =
case line.orientation()
of Horizontal:
for x in line.start.x .. line.end.x:
area[x][line.start.y].inc()
of Vertical:
for y in line.start.y .. line.end.y:
area[line.start.x][y].inc()
of Diagonal:
assert(false, "not implemented")
proc initLine(start, `end`: Point): Line =
result = (start: start, `end`: `end`)
let orientation = result.orientation()
if orientation == Horizontal and result.start.x > result.end.x or
orientation == Vertical and result.start.y > result.end.y or
orientation == Diagonal and result.start.x > result.end.x:
result = (start: result.end, `end`: result.start)
proc parsePoint(input: string): Point =
let coords = input.split(',', 1)
if coords.len() != 2:
raise newException(ValueError, "invalid point")
result = (x: uint16(parseUint(coords[0])), y: uint16(parseUint(coords[1])))
proc parseLines(): seq[Line] =
var line = ""
while readLine(stdin, line):
if line.len() > 0:
let tokens = line.split(' ', 2)
if tokens.len() != 3 or tokens[1] != "->":
raise newException(ValueError, "invalid line")
result.add(initLine(parsePoint(tokens[0]), parsePoint(tokens[2])))
proc countOverlaps(): int =
let lines = parseLines()
var area: Area
for line in lines.filterIt(it.orientation() in [Horizontal, Vertical]):
area.add(line)
for x in 0 .. high(area):
for y in 0 .. high(area[0]):
if area[x][y] > 1:
result.inc()
proc main(): int =
try:
echo countOverlaps()
except Exception as error:
echo error.msg
result = -1
when isMainModule:
quit(main())