function readAllSamples(cb) { require("fs").readFile('./input', 'utf8', (err, data) => { var samples = data.split("\n\n").map(l => { var args = l.match(/(\d+)/g); if (args) return new Sample(args); }).filter(i => !!i); cb(samples); }); } function readProgram(cb) { require("fs").readFile('./testprogram', 'utf8', (err, data) => { cb(data.split("\n").filter(i => !!i).map(i => i.match(/(\d+)/g).map(i => parseInt(i)))); }); } var ops = { "addr": function(args, reg) { reg[args[3]] = reg[args[1]] +reg[args[2]]; }, "addi": function(args, reg) { reg[args[3]] = reg[args[1]] +args[2]; }, "mulr": function(args, reg) { reg[args[3]] = reg[args[1]] *reg[args[2]]; }, "muli": function(args, reg) { reg[args[3]] = reg[args[1]] *args[2]; }, "banr": function(args, reg) { reg[args[3]] = reg[args[1]] & reg[args[2]]; }, "bani": function(args, reg) { reg[args[3]] = reg[args[1]] & args[2]; }, "borr": function(args, reg) { reg[args[3]] = reg[args[1]] | reg[args[2]]; }, "bori": function(args, reg) { reg[args[3]] = reg[args[1]] | args[2]; }, "setr": function(args, reg) { reg[args[3]] = reg[args[1]] }, "seti": function(args, reg) { reg[args[3]] = args[1] }, "gtir": function(args, reg) { reg[args[3]] = args[1] > reg[args[2]] ? 1 : 0 }, "gtri": function(args, reg) { reg[args[3]] = reg[args[1]] > args[2] ? 1 : 0 }, "gtrr": function(args, reg) { reg[args[3]] = reg[args[1]] > reg[args[2]] ? 1 : 0 }, "eqir": function(args, reg) { reg[args[3]] = args[1] == reg[args[2]] ? 1 : 0 }, "eqri": function(args, reg) { reg[args[3]] = reg[args[1]] == args[2] ? 1 : 0 }, "eqrr": function(args, reg) { reg[args[3]] = reg[args[1]] == reg[args[2]] ? 1 : 0 } }; function Sample(args) { this.from = args.splice(0, 4).map(i => parseInt(i)); this.args = args.splice(0, 4).map(i => parseInt(i)); this.to = args.splice(0, 4).map(i => parseInt(i)); } Sample.prototype.getNotPossibleOps = function() { var notPossibleOps = []; for (op in ops) { var reg = this.from.slice(); ops[op](this.args, reg); var found = true; for (var i =0; i < reg.length && found; ++i) if (reg[i] !== this.to[i]) found = false; if (!found) notPossibleOps.push(op); } return notPossibleOps; } function runSampleProgram(opCodeMap) { readProgram(instrs => { var reg = [ 0, 0, 0, 0 ]; instrs.forEach(instr => opCodeMap[instr[0]](instr, reg)); console.log("Registers: ", reg); }); } function run() { readAllSamples(samples => { var sampleBehavingLikeThreeOrMoreOpcodes = 0, possibleOpCodes = []; for (var i in ops) possibleOpCodes.push(Object.keys(ops)); samples.forEach(s => { var notPossibleOps = s.getNotPossibleOps(); if (notPossibleOps.length <= possibleOpCodes.length -3) ++sampleBehavingLikeThreeOrMoreOpcodes; notPossibleOps.forEach(o => { var index = possibleOpCodes[s.args[0]].indexOf(o); if (index >= 0) possibleOpCodes[s.args[0]].splice(index, 1); }); }); console.log("Number of sample behaving like 3 or more opcodes: ", sampleBehavingLikeThreeOrMoreOpcodes); var found = true; while (found) { found = false; for (var i =0; i < possibleOpCodes.length; ++i) if (possibleOpCodes[i].length == 1) for (var j =0; j < possibleOpCodes.length; ++j) if (j != i && possibleOpCodes[j].indexOf(possibleOpCodes[i][0]) >= 0) { possibleOpCodes[j].splice(possibleOpCodes[j].indexOf(possibleOpCodes[i][0]), 1); found = true; } } var opCodeMap = possibleOpCodes.map(i => ops[i[0]]); runSampleProgram(opCodeMap); }); } run();