diff --git a/2021/nim/day24.nim b/2021/nim/day24.nim index af21269..ce48d93 100644 --- a/2021/nim/day24.nim +++ b/2021/nim/day24.nim @@ -1,73 +1,28 @@ import ./common, std/[strutils, sugar, sequtils, options, tables, sets, strformat, algorithm, pegs] -type - Register = int - ALUInstruction = (string, Register, string) - ALUState = array[4, int] - -proc parseInstruction(s: string): ALUInstruction = - # echo s +proc parseInstructionArg(s: string): int = let ss = s.split(' ') - let i = if ss.len > 2: ss[2] else: "" - (ss[0], ss[1][0].ord - ord('w'), i) - -proc runALUInstructions(instructions: seq[ALUInstruction], input: string): ALUState = - var inputs = input.reversed - let registers = toHashSet(['w', 'x', 'y', 'z']) - var n = 0 - for i in instructions: - let (op, reg, arg) = i - var narg = arg - var num = 0 - if arg != "": - if registers.contains(arg[0]): - let index = arg[0].ord - 'w'.ord - num = result[index] - narg = &"r{index+1}" - else: num = arg.parseInt - if n mod 18 in [4, 5, 15, 0]: - echo &"{result} -> {op} {narg} to r{reg+1} (Input Left: {inputs.join})" - case op: - of "inp": result[reg] = inputs.pop.ord - '0'.ord - of "add": result[reg] += num - of "mul": result[reg] *= num - of "div": result[reg] = result[reg] div num - of "mod": result[reg] = result[reg] mod num - of "eql": result[reg] = (result[reg] == num).int - inc n + if ss.len > 2 and not (ss[2][0] in 'w'..'z'): ss[2].parseInt + else: 0 proc p1(input: Lines): uint64 = - # repeating these 18 instructions: - # w is used to store the input digit - # x is zeroed - # z is added to x - # x is modulo'd over 26 - # z is divided by either 1 or 26 (mostly in the latter half of the inputs) - # x is added with SOME NUMBER (sometimes negative) - # x is ALWAYS eql'd with w and 0 - # this is meant to ensure that x is NOT equal to the input? - # y is ALWAYS set to 25 - # y is multiplied by x, which will be 25 if x was 1 or 0 otherwise - # so y will be 25 if x was equal to the input and 0 if not - # y is incremented - # 26 now, if x was equal, 1 if not - # z is multiplied by y - # so z - # y is zeroed out, set to w (the input), added with SOME NUMBER, then multiplied with x - # add y to z - - # if I need to get z to zero, I need to know where those 26-divisions are and leverage them - # if I can ever get y to be negative, that could help a lot as well - - # probably a relatively simple way to bruteforce over this? - let instructions = input.map(parseInstruction) - # let oalu = instructions.runALUInstructions("13579246899999") - # echo oalu - let alu = instructions.runALUInstructions("99879249111111") - echo alu - 0 - -proc p2(input: Lines): uint64 = - 0 + let instructionArgs = input.map(parseInstructionArg) + var reversedDigits = initTable[int, int]() + var cantComputeYet: seq[(int, int)] = @[] + for i in 0..13: + let o = i * 18 + if instructionArgs[o+4] == 26: + let (previousI, previousAddend) = cantComputeYet.pop + let diff = previousAddend + instructionArgs[o+5] + echo diff + echo previousI + if diff < 0: + reversedDigits[previousI] = 9 + reversedDigits[i] = 9 + diff + else: + reversedDigits[previousI] = 9 - diff + reversedDigits[i] = 9 + else: cantComputeYet.add (i, instructionArgs[o+15]) + reversedDigits.keys.toSeq.sorted.mapIt($reversedDigits[it]).join().parseBiggestUInt() time(&"Day 24 Part 1"): echo 24.loadInput.p1