[This post will be in multiple parts because of the 10K character limit]
I'm angry about Day 24 because it was impossible to solve with code. You cannot brute force a 14 digit number, no matter how good your code is you're not writing any. I did write the parser anyway, because I thought maybe Eric was going to be nice enough to restrict the range so it would be found quickly. He did not and so I wasted an hour on that.
I then thought maybe it was supposed to be a threading exercise, so I added parallel threads to my code. That didn't improve things enough to have bothered. (It MIGHT have finished in a couple of days.)
I then wrote code to convert the input "program" into [Java] code, thinking maybe that would run fast enough if multi-threaded. It did run somewhat faster, but not fast enough to complete in reasonable time.
I then spent time simplifying the generated code, removing stuff that wasn't really doing useful processing. As I was doing that, I started to see a trend in the input program. There are 14 input digits, and there was 14 sections in the program that were mostly identical, but with different constants.
Having then run out of ideas, I peeked at the Reddit thread and saw someone suggest the code was using the z register to
implement a stack. Looking over the code, I started to see what they meant, and then manually transcoded the code into a set of 7 rules. I then used those rules to get the first 5 digits, and then let my now fast bruteforcer do the rest. That got me part one. Part two just meant revisiting the working out of the first 5 digits, and then some quick tweaks to my brute forcer and bingo part two done.
To be clear, I didn't need to do any brute forcing, I just thought my code would be marginally faster at getting the results than my working it out by hand.
Although my parser is completely pointless, I will share it here. It also includes the code I used to translate the input program into Java code. I could also include my brute forcer, but it would include my working out of my supplied inputs, and wouldn't really be useful without it, so I don't think I should.
Java:
final class MonadProgram
{
private final String[] monadProgramInstructions;
private long w;
private long x;
private long y;
private long z;
private String[] programInput = new String[0];
private int inputPointer;
public MonadProgram(String[] monadProgramInstructions)
{
this.monadProgramInstructions = monadProgramInstructions;
}
public void translateProgramToJavaCode()
{
System.out.println("long w=0;");
System.out.println("long x=0;");
System.out.println("long y=0;");
System.out.println("long z=0;");
int programCounter = 0;
int inputNumber = 0;
while (programCounter < monadProgramInstructions.length)
{
final String instruction = monadProgramInstructions[programCounter++];
final String[] instructionParts = instruction.split(" ");
switch (instructionParts[0])
{
case "inp": System.out.println(instructionParts[1] + " = input[" + inputNumber++ + "];"); continue;
case "add": System.out.println(instructionParts[1] + " += " + instructionParts[2] + ";"); continue;
case "mul": System.out.println(instructionParts[1] + " *= " + instructionParts[2] + ";"); continue;
case "div": System.out.println(instructionParts[1] + " /= " + instructionParts[2] + ";"); continue;
case "mod": System.out.println(instructionParts[1] + " %= " + instructionParts[2] + ";"); continue;
case "eql": System.out.println(instructionParts[1] + " = (" + instructionParts[1] + "==" + instructionParts[2] + ")?1:0;"); continue;
default: throw new IllegalStateException("Unknown instruction: " + instructionParts[0]);
}
}
}
public void runWithInput(final String[] programInput)
{
w=0;
x=0;
y=0;
z=0;
inputPointer = 0;
this.programInput = programInput;
int programCounter = 0;
while (programCounter < monadProgramInstructions.length)
{
executeInstruction(monadProgramInstructions[programCounter++]);
}
}
private void executeInstruction(final String instruction)
{
final String[] instructionParts = instruction.split(" ");
switch (instructionParts[0])
{
case "inp": doInp(instructionParts[1]); return;
case "add": doAdd(instructionParts[1], instructionParts[2]); return;
case "mul": doMul(instructionParts[1], instructionParts[2]); return;
case "div": doDiv(instructionParts[1], instructionParts[2]); return;
case "mod": doMod(instructionParts[1], instructionParts[2]); return;
case "eql": doEql(instructionParts[1], instructionParts[2]); return;
default: throw new IllegalStateException("Unknown instruction: " + instructionParts[0]);
}
}
private void doInp(final String register)
{
if (inputPointer >= programInput.length) throw new IllegalStateException("Out of input");
final String input = programInput[inputPointer++];
final long val = Long.parseLong(input);
switch (register)
{
case "w": w = val; return;
case "x": x = val; return;
case "y": y = val; return;
case "z": z = val; return;
default: throw new IllegalStateException("Invalid register: " + register);
}
}
private void doAdd(final String register1, final String register2)
{
switch (register1)
{
case "w": w += switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "x": x += switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "y": y += switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "z": z += switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
default: throw new IllegalStateException("Invalid register: " + register1);
}
}
private void doMul(final String register1, final String register2)
{
switch (register1)
{
case "w": w *= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "x": x *= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "y": y *= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "z": z *= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
default: throw new IllegalStateException("Invalid register: " + register1);
}
}
private void doDiv(final String register1, final String register2)
{
switch (register1)
{
case "w": w /= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "x": x /= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "y": y /= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "z": z /= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
default: throw new IllegalStateException("Invalid register: " + register1);
}
}
private void doMod(final String register1, final String register2)
{
switch (register1)
{
case "w": w %= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "x": x %= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "y": y %= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
case "z": z %= switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);}; return;
default: throw new IllegalStateException("Invalid register: " + register1);
}
}
private void doEql(final String register1, final String register2)
{
final long compareTo = switch(register2) {case "w" -> w; case "x" -> x; case "y" -> y; case "z" ->z; default -> Long.parseLong(register2);};
switch (register1)
{
case "w": w = (w == compareTo)?1:0; return;
case "x": x = (x == compareTo)?1:0; return;
case "y": y = (y == compareTo)?1:0; return;
case "z": z = (z == compareTo)?1:0; return;
default: throw new IllegalStateException("Invalid register: " + register1);
}
}
long getW()
{
return w;
}
long getX()
{
return x;
}
long getY()
{
return y;
}
long getZ()
{
return z;
}
}