300 lines
7.2 KiB
TypeScript
300 lines
7.2 KiB
TypeScript
namespace AdventOfCode2019_07_2
|
|
{
|
|
const DAY = 7;
|
|
const PROBLEM = 2;
|
|
|
|
export async function run()
|
|
{
|
|
let input = await AdventOfCode.getInput(DAY);
|
|
if (input == null) return;
|
|
|
|
let code = input.split(",").map(p => parseInt(p.trim()));
|
|
|
|
let outputs: number[] = [];
|
|
|
|
for(let i=0; i < 5*5*5*5*5; i++)
|
|
{
|
|
let v = i;
|
|
let a1 = v%5 + 5; v = Math.floor(v/5);
|
|
let a2 = v%5 + 5; v = Math.floor(v/5);
|
|
let a3 = v%5 + 5; v = Math.floor(v/5);
|
|
let a4 = v%5 + 5; v = Math.floor(v/5);
|
|
let a5 = v%5 + 5; v = Math.floor(v/5);
|
|
|
|
if ([a1,a2,a3,a4,a5].sort((a, b) => a - b).filter((v,i,s) => s.indexOf(v)===i).length !== 5) continue;
|
|
|
|
const r = evalConfiguration(code, a1,a2,a3,a4,a5)
|
|
|
|
outputs.push(r);
|
|
AdventOfCode.outputConsole([a1,a2,a3,a4,a5].toString() + " --> " + r);
|
|
}
|
|
|
|
const max = outputs.sort((a, b) => a - b).reverse()[0];
|
|
|
|
AdventOfCode.output(DAY, PROBLEM, max.toString());
|
|
}
|
|
|
|
function evalConfiguration(code: number[], a1 : number, a2 : number, a3 : number, a4 : number, a5 : number) : number
|
|
{
|
|
const runner1 = new Interpreter(code, [a1, 0]);
|
|
const runner2 = new Interpreter(code, [a2]);
|
|
const runner3 = new Interpreter(code, [a3]);
|
|
const runner4 = new Interpreter(code, [a4]);
|
|
const runner5 = new Interpreter(code, [a5]);
|
|
|
|
let optr1 = 0;
|
|
let optr2 = 0;
|
|
let optr3 = 0;
|
|
let optr4 = 0;
|
|
let optr5 = 0;
|
|
|
|
while (!runner5.is_halted)
|
|
{
|
|
runner1.singleStep();
|
|
if (runner1.output.length > optr1)
|
|
{
|
|
runner2.inputqueue.push(runner1.output[optr1]);
|
|
optr1++;
|
|
}
|
|
|
|
runner2.singleStep();
|
|
if (runner2.output.length > optr2)
|
|
{
|
|
runner3.inputqueue.push(runner2.output[optr2]);
|
|
optr2++;
|
|
}
|
|
|
|
runner3.singleStep();
|
|
if (runner3.output.length > optr3)
|
|
{
|
|
runner4.inputqueue.push(runner3.output[optr3]);
|
|
optr3++;
|
|
}
|
|
|
|
runner4.singleStep();
|
|
if (runner4.output.length > optr4)
|
|
{
|
|
runner5.inputqueue.push(runner4.output[optr4]);
|
|
optr4++;
|
|
}
|
|
|
|
runner5.singleStep();
|
|
if (runner5.output.length > optr5)
|
|
{
|
|
runner1.inputqueue.push(runner5.output[optr5]);
|
|
optr5++;
|
|
}
|
|
}
|
|
|
|
return runner5.output.reverse()[0];
|
|
}
|
|
|
|
class Interpreter
|
|
{
|
|
program: number[];
|
|
inputqueue: number[];
|
|
instructionpointer: number;
|
|
output: number[];
|
|
|
|
is_halted: boolean = false;
|
|
|
|
constructor(prog: number[], input: number[])
|
|
{
|
|
this.program = Object.assign([], prog);
|
|
this.inputqueue = Object.assign([], input);
|
|
this.instructionpointer = 0;
|
|
this.output = [];
|
|
}
|
|
|
|
fullRun() : number[]
|
|
{
|
|
while(!this.is_halted)
|
|
{
|
|
const r = this.singleStep();
|
|
|
|
if (r === StepResult.EXECUTED) continue;
|
|
if (r === StepResult.HALTED) return this.output;
|
|
if (r === StepResult.WAITING_FOR_IN) throw "not enough input";
|
|
|
|
throw "unknown output of singleStep";
|
|
}
|
|
|
|
return this.output;
|
|
}
|
|
|
|
singleStep() : StepResult
|
|
{
|
|
const cmd = new Op(this.program[this.instructionpointer]);
|
|
|
|
if (cmd.opcode == OpCode.ADD)
|
|
{
|
|
const p0 = cmd.getParameter(this, 0);
|
|
const p1 = cmd.getParameter(this, 1);
|
|
const pv = p0 + p1;
|
|
cmd.setParameter(this, 2, pv);
|
|
|
|
this.incInstrPtr(cmd);
|
|
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.MUL)
|
|
{
|
|
const p0 = cmd.getParameter(this, 0);
|
|
const p1 = cmd.getParameter(this, 1);
|
|
const pv = p0 * p1;
|
|
cmd.setParameter(this, 2, pv);
|
|
|
|
this.incInstrPtr(cmd);
|
|
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.HALT)
|
|
{
|
|
this.is_halted = true;
|
|
return StepResult.HALTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.IN)
|
|
{
|
|
if (this.inputqueue.length == 0) return StepResult.WAITING_FOR_IN;
|
|
|
|
const pv = this.inputqueue[0];
|
|
cmd.setParameter(this, 0, pv);
|
|
this.inputqueue = this.inputqueue.slice(1);
|
|
|
|
this.incInstrPtr(cmd);
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.OUT)
|
|
{
|
|
const p0 = cmd.getParameter(this, 0);
|
|
this.output.push(p0);
|
|
|
|
this.incInstrPtr(cmd);
|
|
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.TJMP)
|
|
{
|
|
const p0 = cmd.getParameter(this, 0);
|
|
if (p0 != 0) this.instructionpointer = cmd.getParameter(this, 1);
|
|
else this.incInstrPtr(cmd);
|
|
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.FJMP)
|
|
{
|
|
const p0 = cmd.getParameter(this, 0);
|
|
if (p0 == 0) this.instructionpointer = cmd.getParameter(this, 1);
|
|
else this.incInstrPtr(cmd);
|
|
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.LT)
|
|
{
|
|
const p0 = cmd.getParameter(this, 0);
|
|
const p1 = cmd.getParameter(this, 1);
|
|
const pv = p0 < p1 ? 1 : 0;
|
|
cmd.setParameter(this, 2, pv);
|
|
|
|
this.incInstrPtr(cmd);
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else if (cmd.opcode == OpCode.EQ)
|
|
{
|
|
const p0 = cmd.getParameter(this, 0);
|
|
const p1 = cmd.getParameter(this, 1);
|
|
const pv = p0 == p1 ? 1 : 0;
|
|
cmd.setParameter(this, 2, pv);
|
|
|
|
this.incInstrPtr(cmd);
|
|
return StepResult.EXECUTED;
|
|
}
|
|
else throw "Unknown Op: " + cmd.opcode + " @ " + this.instructionpointer;
|
|
}
|
|
|
|
private incInstrPtr(cmd: Op)
|
|
{
|
|
this.instructionpointer += 1 + cmd.parametercount;
|
|
}
|
|
}
|
|
|
|
enum StepResult { EXECUTED, HALTED, WAITING_FOR_IN }
|
|
|
|
enum OpCode
|
|
{
|
|
ADD = 1,
|
|
MUL = 2,
|
|
IN = 3,
|
|
OUT = 4,
|
|
TJMP = 5,
|
|
FJMP = 6,
|
|
LT = 7,
|
|
EQ = 8,
|
|
HALT = 99,
|
|
}
|
|
|
|
enum ParamMode
|
|
{
|
|
POSITION_MODE = 0,
|
|
IMMEDIATE_MODE = 1,
|
|
}
|
|
|
|
class Op
|
|
{
|
|
opcode: OpCode;
|
|
modes: ParamMode[];
|
|
|
|
name: string;
|
|
parametercount: number;
|
|
|
|
constructor(v: number)
|
|
{
|
|
this.opcode = v%100;
|
|
v = Math.floor(v/100);
|
|
this.modes = [];
|
|
for(let i=0; i<4; i++)
|
|
{
|
|
this.modes.push(v%10);
|
|
v = Math.floor(v/10);
|
|
}
|
|
|
|
if (this.opcode == OpCode.ADD) { this.name="ADD"; this.parametercount=3; }
|
|
else if (this.opcode == OpCode.MUL) { this.name="MUL"; this.parametercount=3; }
|
|
else if (this.opcode == OpCode.HALT) { this.name="HALT"; this.parametercount=0; }
|
|
else if (this.opcode == OpCode.IN) { this.name="IN"; this.parametercount=1; }
|
|
else if (this.opcode == OpCode.OUT) { this.name="OUT"; this.parametercount=1; }
|
|
else if (this.opcode == OpCode.TJMP) { this.name="TJMP"; this.parametercount=2; }
|
|
else if (this.opcode == OpCode.FJMP) { this.name="FJMP"; this.parametercount=2; }
|
|
else if (this.opcode == OpCode.LT) { this.name="LT"; this.parametercount=3; }
|
|
else if (this.opcode == OpCode.EQ) { this.name="EQ"; this.parametercount=3; }
|
|
else throw "Unknown opcode: "+this.opcode;
|
|
}
|
|
|
|
getParameter(proc: Interpreter, index: number): number
|
|
{
|
|
const prog = proc.program;
|
|
const ip = proc.instructionpointer;
|
|
|
|
let p = prog[ip+1+index];
|
|
|
|
if (this.modes[index] == ParamMode.POSITION_MODE) p = prog[p];
|
|
else if (this.modes[index] == ParamMode.IMMEDIATE_MODE) p = p;
|
|
else throw "Unknown ParamMode: "+this.modes[index];
|
|
|
|
return p;
|
|
}
|
|
|
|
setParameter(proc: Interpreter, index: number, value: number): void
|
|
{
|
|
const prog = proc.program;
|
|
const ip = proc.instructionpointer;
|
|
|
|
let p = prog[ip+1+index];
|
|
|
|
if (this.modes[index] == ParamMode.POSITION_MODE) prog[p] = value;
|
|
else if (this.modes[index] == ParamMode.IMMEDIATE_MODE) throw "Immediate mode not allowed in write";
|
|
else throw "Unknown ParamMpde: "+this.modes[index];
|
|
}
|
|
}
|
|
}
|