From b0609897dfbb2515ac69fc774895dff037ee37d6 Mon Sep 17 00:00:00 2001 From: Max Nuding Date: Fri, 3 Dec 2021 21:50:50 +0100 Subject: [PATCH] 03b --- Sources/aoc2021/03.swift | 76 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 3 deletions(-) diff --git a/Sources/aoc2021/03.swift b/Sources/aoc2021/03.swift index 0c5f654..f088608 100644 --- a/Sources/aoc2021/03.swift +++ b/Sources/aoc2021/03.swift @@ -16,15 +16,15 @@ struct Day03 { let commands = input .components(separatedBy: .newlines) .filter { !$0.isEmpty } - //.compactMap { MoveCommand(line: $0) } runA(commands) - //runB(commands) + runB(commands) } func runA(_ commands: [String]) { let neededForMajority = commands.count / 2 let lastBitIndex = commands.first!.count var countsOnes = [Int](repeating: 0, count: lastBitIndex) + // There's probably some clever bitwise operation to solve this for command in commands { let m = command.map { Bool.init(digit: $0)! }.map { $0 ? 1 : 0 } countsOnes.enumerated().forEach { (idx, elem) in @@ -42,11 +42,81 @@ struct Day03 { } return (gamma, episolon) }) - print(dec.episolon * dec.gamma)< + print(dec.episolon * dec.gamma) } func runB(_ commands: [String]) { + // Incredibly naive, iterates through the list many, many times + // Still runs plenty fast (~70ms on my machine) + // Too tired to optimize this + let lastBitIndex = commands.first!.count + var countsOnes = [Int](repeating: 0, count: lastBitIndex) + for command in commands { + let m = command.map { Bool.init(digit: $0)! }.map { $0 ? 1 : 0 } + countsOnes.enumerated().forEach { (idx, elem) in + countsOnes[idx] += m[idx] + } + } + + var oxygenCommands = commands + var scrubberCommands = commands + for pos in 0..= neededForMajorityOxygen + let digit = Bool(digit: command[idx]) + let keepOxygen = digit == isMostCommon + if !keepOxygen, oxygenCommands.count > 1, let coi = oxygenCommands.firstIndex(of: command){ + oxygenCommands.remove(at: coi) + } + } + + let neededForMajorityScrubber = Int(ceil(Double(scrubberCommands.count) / 2.0)) + for command in scrubberCommands { + let idx = command.index(command.startIndex, offsetBy: pos) + let isLeastCommon = countsOnesScrubber[pos] < neededForMajorityScrubber + let digit = Bool(digit: command[idx]) + let keepScrubber = digit == isLeastCommon + if !keepScrubber, scrubberCommands.count > 1, let ci = scrubberCommands.firstIndex(of: command) { + scrubberCommands.remove(at: ci) + } + } + + } + let finalOxygenNumber = oxygenCommands.first! + let finalScruberNumber = scrubberCommands.first! + + print(ToDecimal(num: finalOxygenNumber) * ToDecimal(num: finalScruberNumber)) + } + + private func ToDecimal(num: String) -> Int { + var pot = -1 + var val = 0 + for c in num.reversed() { + pot += 1 + if c == "0" { + continue + } + val += Int(truncating: NSDecimalNumber(decimal: pow(2, pot))) + } + return val } }