aboutsummaryrefslogtreecommitdiff
path: root/2021/day24/24a.mzn
diff options
context:
space:
mode:
Diffstat (limited to '2021/day24/24a.mzn')
-rw-r--r--2021/day24/24a.mzn117
1 files changed, 117 insertions, 0 deletions
diff --git a/2021/day24/24a.mzn b/2021/day24/24a.mzn
new file mode 100644
index 0000000..4ad0d82
--- /dev/null
+++ b/2021/day24/24a.mzn
@@ -0,0 +1,117 @@
+include "globals.mzn";
+
+% Types
+enum Operation = {
+ i_inp,
+ i_add,
+ i_mul,
+ i_div,
+ i_mod,
+ i_eql
+};
+enum Pos = { Arg1, Arg2 };
+enum Arg = R(Registers) ++ Imm(Immediates) ++ { None };
+
+enum Registers = {x, y, z, w};
+
+set of int: Immediates = -127..127;
+set of int: Digits = 0..9;
+
+% Input
+array[int] of Operation: inp_ops;
+array[int, Pos] of Arg: inp_args;
+
+% Properties derived from input
+set of int: Steps = index_set(inp_ops);
+set of int: Inputs = 1..count(inp_ops, i_inp);
+
+set of int: ExtendedSteps = min(Steps)..max(Steps) + 1;
+set of int: ExtendedInputs = min(Inputs)..max(Inputs) + 1;
+
+% State
+array[ExtendedSteps, Registers] of var int: regs;
+array[Inputs] of var Digits: inputs;
+
+% Everything is 0 to start with
+constraint forall (r in Registers) (
+ regs[min(Steps), r] = 0
+);
+
+% All registers unaffected by the instruction at a given step
+function set of Registers: unaffected(Steps: step) = {
+ r | r in Registers where R(r) != inp_args[step, Arg1]
+};
+
+% The argument at pos addressed by the instruction at i_step, pointing to the registers at r_step
+function var int: arg(Steps: i_step, ExtendedSteps: r_step, Pos: pos) =
+ if inp_args[i_step, pos] in R(Registers) then
+ regs[r_step, R^-1(inp_args[i_step, pos])]
+ elseif inp_args[i_step, pos] in Imm(Immediates) then
+ Imm^-1(inp_args[i_step, pos])
+ else
+ assert(false, "no value for argument of instruction at step")
+ endif;
+
+% Where to write the result of an instruction
+function var int: writearg(Steps: step) = arg(step, step + 1, Arg1);
+
+% Read the argument at pos of instruction at step
+function var int: readarg(Steps: step, Pos: pos) = arg(step, step, pos);
+
+predicate interpret(Steps: step, ExtendedInputs: next_input) = (
+ % Constrain state based on instruction at step
+ if inp_ops[step] = i_inp then
+ writearg(step) = inputs[next_input]
+ else
+ let {
+ Operation: o = inp_ops[step],
+ var int: a = readarg(step, Arg1),
+ var int: b = readarg(step, Arg2),
+ var int: x = writearg(step),
+ } in
+ if o = i_add then
+ x = a + b
+ elseif o = i_mul then
+ x = a * b
+ elseif o = i_div then
+ b != 0 /\
+ x * b = a - (a mod b)
+ elseif o = i_mod then
+ a >= 0 /\
+ b > 0 /\
+ x = a mod b
+ elseif o = i_eql then
+ x = (a = b)
+ else
+ assert(false, "unimplemented instruction at ")
+ endif
+ endif /\
+ % Leave the rest unchanged
+ forall (r in unaffected(step)) (
+ regs[step + 1, r] = regs[step, r]
+ ) /\
+ % Perform induction
+ if step + 1 in Steps then
+ interpret(step + 1, next_input + (inp_ops[step] = i_inp))
+ else
+ true
+ endif
+);
+
+constraint interpret(min(Steps), min(Inputs));
+
+% Finish with z = 0
+constraint regs[max(ExtendedSteps), z] = 0;
+
+% No 0s in serial number
+constraint forall (i in Inputs) (
+ inputs[i] != 0
+);
+
+% Find the largest first
+solve :: int_search(inputs, input_order, indomain_max) satisfy;
+
+output [
+ "inputs: ", show(inputs), "\n",
+ "final registers: ", show(regs[max(ExtendedSteps), ..]), "\n",
+]; \ No newline at end of file