adventofcode2021/day03/part2.nim

75 lines
2.3 KiB
Nim
Raw Normal View History

2021-12-03 23:02:51 +01:00
# 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 bitops
import sequtils
proc readNumbers(): tuple[numbers: seq[uint64], numberWidth: int] =
var
line = ""
while readLine(stdin, line):
if line.len() > 0:
if line.len() != result.numberWidth:
if result.numberWidth == 0:
result.numberWidth = line.len()
else:
raise newException(ValueError, "invalid line length")
var number = 0'u64
for index, digit in line.pairs():
case digit
of '0': discard
of '1': number.setBit(result.numberWidth - 1 - index)
else: raise newException(ValueError, "invalid number")
result.numbers.add(number)
proc countBits(numbers: seq[uint64], bitPos: int): tuple[ones: int, zeros: int] =
for number in numbers:
if number.testBit(bitPos):
result.ones.inc()
else:
result.zeros.inc()
proc findNumber(numbers: seq[uint64], numberWidth: int, mostCommon: bool): uint64 =
var remaining = numbers
for bitPos in countdown(numberWidth - 1, 0):
let (ones, zeros) = remaining.countBits(bitPos)
let required = if ones >= zeros:
mostCommon
else:
not mostCommon
remaining = remaining.filterIt(it.testBit(bitPos) == required)
if remaining.len() == 1:
return remaining[0]
raise newException(ValueError, "cannot find number")
proc lifeSupportRating(): uint64 =
let
(numbers, numberWidth) = readNumbers()
oxygen = findNumber(numbers, numberWidth, true)
co2 = findNumber(numbers, numberWidth, false)
result = oxygen * co2
proc main(): int =
try:
echo lifeSupportRating()
except Exception as error:
echo error.msg
result = -1
when isMainModule:
quit(main())