99 lines
2.8 KiB
Nim
99 lines
2.8 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: ./part2 < input
|
|
|
|
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:
|
|
var x = line.start.x
|
|
if line.start.y < line.end.y:
|
|
for y in countup(line.start.y, line.end.y):
|
|
area[x][y].inc()
|
|
x.inc()
|
|
else:
|
|
for y in countdown(line.start.y, line.end.y):
|
|
area[x][y].inc()
|
|
x.inc()
|
|
|
|
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:
|
|
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())
|