From 6ee578fd9b4dfa93c6e2fbdc59f61b959ff80de2 Mon Sep 17 00:00:00 2001 From: Christian Ulrich Date: Fri, 3 Dec 2021 23:02:51 +0100 Subject: [PATCH] add day 3 solution part 2 --- day03/part2.nim | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 day03/part2.nim diff --git a/day03/part2.nim b/day03/part2.nim new file mode 100644 index 0000000..519f51a --- /dev/null +++ b/day03/part2.nim @@ -0,0 +1,74 @@ +# 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 . + +# 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())