TypeScript Day 5

This commit is contained in:
Tobias Berger 2020-11-19 12:37:41 +01:00 committed by Tobias Berger
parent 3ebf21f6be
commit b8ed051163
Signed by: toby
GPG key ID: 2D05EFAB764D6A88
10 changed files with 461 additions and 78 deletions

View file

@ -1,6 +1,6 @@
{
"scripts": {
"lint": "prettier solution_a.ts solution_b.ts --write",
"lint": "prettier solution_a.ts solution_b.ts --write --print-width=120",
"a": "ts-node solution_a.ts",
"b": "ts-node solution_b.ts"
},
@ -8,7 +8,8 @@
"prettier": "^2.1.2"
},
"dependencies": {
"@types/node": "^14.14.6",
"@types/node": "^14.14.8",
"readline": "^1.3.0",
"ts-node": "^9.0.0",
"typescript": "^4.0.5"
},

View file

@ -1,71 +1,207 @@
import * as fs from 'fs';
const input = fs.readFileSync("input").toString().split(",").map(num => parseInt(num));
import * as fs from "fs";
const fsPromises = fs.promises;
import * as readline from "readline";
enum ParameterModes {
const rl = readline.createInterface(process.stdin, process.stdout);
enum ParameterMode {
position = 0,
immediate = 1
immediate = 1,
}
async function run(noun: number, verb: number) {
let memory = input.slice();
enum Instruction {
add = 1,
mul = 2,
inp = 3,
out = 4,
end = 99,
}
// Restore integrity
memory[1] = noun
memory[2] = verb
//
type Memory = Array<OpCode>;
let index = 0;
class OpCode {
private _executable: boolean = false;
private _literalValue: number = 0;
private _instruction?: Instruction;
private _parameterModes?: [a: ParameterMode, b: ParameterMode, c: ParameterMode];
let [a,b,x] = [0,0,0];
while(index < memory.length) {
switch(memory[index]){
case 1:
// .add
[a, b, x] = memory.slice(index+1, index+4);
memory[x] = memory[a] + memory[b];
index += 4;
break;
case 2:
// .mul
[a, b, x] = memory.slice(index+1, index+4);
memory[x] = memory[a] * memory[b];
index += 4;
break;
case 3:
x = memory[index+1];
memory[x]=x
break;
case 99:
// .end
return memory;
default:
// .hcf
throw new Error("Halt and catch fire");
constructor(value: number);
constructor(value: string);
constructor(value: string | number) {
let valueNumber: number;
let valueString: string;
if (typeof value === "number") {
valueNumber = value;
valueString = value.toString();
} else {
valueString = value;
valueNumber = parseInt(value);
}
}
}
if (isNaN(valueNumber)) throw new Error(`Invalid value '${value}' for OpCode.`);
valueString = valueString.padStart(5, "0");
async function main(){
let noun = 0;
let verb = 0;
while(noun < 99) {
while(verb < 99) {
console.log(`Testing [${noun}, ${verb}]`)
if(await run(noun,verb) === 19690720) {
console.log("Success!")
return 100*noun+verb
this._literalValue = valueNumber;
if (valueNumber >= 0 && valueNumber <= 99999 && valueNumber % 100 in Instruction) {
const parameterModes: [ParameterMode, ParameterMode, ParameterMode] = [
Math.floor(valueNumber / 10000) % 10,
Math.floor(valueNumber / 1000) % 10,
Math.floor(valueNumber / 100) % 10,
];
if (parameterModes.filter((val) => val in ParameterMode).length === 3) {
this._parameterModes = parameterModes;
this._instruction = valueNumber % 100;
} else {
return;
}
verb++;
this._executable = true;
}
noun++;
verb = 0;
}
throw new Error("Found no solution!")
get executable() {
if (this._instruction === undefined || this._parameterModes === undefined) {
this._executable = false;
}
return this._executable;
}
get literalValue() {
return this._literalValue;
}
get instruction() {
return this._instruction;
}
get parameterModes() {
return this._parameterModes;
}
toString() {
return this.literalValue.toString();
}
}
main().then(console.log);
class Machine {
private readonly initialMemory: Memory;
private memory: Memory;
constructor(program: Memory) {
this.initialMemory = program;
this.memory = program;
}
async run(debug: boolean = false) {
let index = 0;
let debugIteration = 0;
const debugLog = await fsPromises.open("out.log", "w");
let output: number[] = [];
try {
while (index < this.memory.length) {
/*for (let i = 0; i < this.memory.length; i++) {
this.memory[i] = this.memory[i] ?? new OpCode(0);
}*/
if (debug) {
debugLog.write(
`${(++debugIteration).toString().padStart(5, "0")};${index.toString().padStart(5, "0")};[${this.memory
.map((op) => op.literalValue)
.join(",")}]\n`
);
}
const opCode = this.memory[index];
if (!opCode.executable) {
throw new Error(`Tried executing non-executable value ${this.memory[index]} at index ${index}`);
}
const parameterModes = opCode.parameterModes!;
const valueA = this.memory[index + 1]?.literalValue ?? 0;
const valueB = this.memory[index + 2]?.literalValue ?? 0;
const valueC = this.memory[index + 3]?.literalValue ?? 0;
const paramA = parameterModes[2] === ParameterMode.immediate ? valueA : this.memory[valueA]?.literalValue ?? 0;
const paramB = parameterModes[1] === ParameterMode.immediate ? valueB : this.memory[valueB]?.literalValue ?? 0;
const paramC = parameterModes[0] === ParameterMode.immediate ? valueC : this.memory[valueC]?.literalValue ?? 0;
/*console.debug(
opCode,
this.memory.slice(index, index + 4).map((val) => val.literalValue)
);*/
switch (opCode.instruction) {
case Instruction.add:
if (debug) {
console.debug(`Adding ${paramA}+${paramB} and writing ${paramA + paramB} to ${valueC}`);
}
this.memory[valueC] = new OpCode(paramA + paramB);
index += 4;
break;
case Instruction.mul:
if (debug) {
console.debug(`Multiplying ${paramA}*${paramB} and writing ${paramA * paramB} to ${valueC}`);
}
this.memory[valueC] = new OpCode(paramA * paramB);
index += 4;
break;
case Instruction.inp:
this.memory[valueA] = await new Promise<OpCode>((resolve, reject) => {
rl.question(`[${index.toString().padStart(5, "0")}]> `, (answer) => {
try {
const op = new OpCode(answer);
if (debug) {
console.debug(`Writing opCode with value ${op.literalValue} to ${valueA}`);
}
resolve(op);
} catch (e) {
reject(e);
}
});
});
index += 2;
break;
case Instruction.out:
if (debug) {
console.debug(`Outputting ${paramA}`);
}
output.push(paramA);
index += 2;
break;
case Instruction.end:
console.log("Final output:", output);
return this.memory;
}
}
} catch (e) {
console.debug(`Execution failed at index ${index}. Dumping memory.`);
debugLog.write(
`${debugIteration.toString().padStart(5, "0")};${index.toString().padStart(5, "0")};[${this.memory
.map((op) => op.literalValue)
.join(",")}]\n`
);
throw e;
}
console.log("Final output:", output);
return this.memory;
}
reset() {
this.memory = this.initialMemory;
}
static memdump(memory: Memory) {
return memory.map((op) => op.toString()).join(",");
}
}
async function main(code: string) {
const memdump: Memory = code.split(",").map((val) => new OpCode(val));
const machine = new Machine(memdump);
const result = await machine.run();
rl.close();
return; // result ? Machine.memdump(result) : result;
}
const input = fs.readFileSync("input").toString();
main(input)
.then(console.log)
.catch((...args) => {
rl.close();
console.error(args);
});

View file

@ -1,6 +1,247 @@
import * as fs from "fs";
const input = fs.readFileSync("input");
const fsPromises = fs.promises;
import * as readline from "readline";
async function main() {}
const rl = readline.createInterface(process.stdin, process.stdout);
main().then(console.log);
enum ParameterMode {
position = 0,
immediate = 1,
}
enum Instruction {
add = 1,
mul = 2,
inp = 3,
out = 4,
jnz = 5,
jz = 6,
lt = 7,
eq = 8,
end = 99,
}
type Memory = Array<OpCode>;
class OpCode {
private _executable: boolean = false;
private _literalValue: number = 0;
private _instruction?: Instruction;
private _parameterModes?: [a: ParameterMode, b: ParameterMode, c: ParameterMode];
constructor(value: number);
constructor(value: string);
constructor(value: string | number) {
let valueNumber: number;
let valueString: string;
if (typeof value === "number") {
valueNumber = value;
valueString = value.toString();
} else {
valueString = value;
valueNumber = parseInt(value);
}
if (isNaN(valueNumber)) throw new Error(`Invalid value '${value}' for OpCode.`);
valueString = valueString.padStart(5, "0");
this._literalValue = valueNumber;
if (valueNumber >= 0 && valueNumber <= 99999 && valueNumber % 100 in Instruction) {
const parameterModes: [ParameterMode, ParameterMode, ParameterMode] = [
Math.floor(valueNumber / 10000) % 10,
Math.floor(valueNumber / 1000) % 10,
Math.floor(valueNumber / 100) % 10,
];
if (parameterModes.filter((val) => val in ParameterMode).length === 3) {
this._parameterModes = parameterModes;
this._instruction = valueNumber % 100;
} else {
return;
}
this._executable = true;
}
}
get executable() {
if (this._instruction === undefined || this._parameterModes === undefined) {
this._executable = false;
}
return this._executable;
}
get literalValue() {
return this._literalValue;
}
get instruction() {
return this._instruction;
}
get parameterModes() {
return this._parameterModes;
}
toString() {
return this.literalValue.toString();
}
}
class Machine {
private readonly initialMemory: Memory;
private memory: Memory;
constructor(program: Memory) {
this.initialMemory = program;
this.memory = program;
}
async run(debug: boolean = false) {
let index = 0;
let debugIteration = 0;
const debugLog = debug ? await fsPromises.open("out.log", "w") : undefined;
let output: number[] = [];
try {
while (index < this.memory.length) {
/*for (let i = 0; i < this.memory.length; i++) {
this.memory[i] = this.memory[i] ?? new OpCode(0);
}*/
if (debug) {
debugLog!.write(
`${(++debugIteration).toString().padStart(5, "0")};${index.toString().padStart(5, "0")};[${this.memory
.map((op) => op.literalValue)
.join(",")}]\n`
);
}
const opCode = this.memory[index];
if (!opCode.executable) {
throw new Error(`Tried executing non-executable value ${this.memory[index]} at index ${index}`);
}
const parameterModes = opCode.parameterModes!;
const valueA = this.memory[index + 1]?.literalValue ?? 0;
const valueB = this.memory[index + 2]?.literalValue ?? 0;
const valueC = this.memory[index + 3]?.literalValue ?? 0;
const paramA = parameterModes[2] === ParameterMode.immediate ? valueA : this.memory[valueA]?.literalValue ?? 0;
const paramB = parameterModes[1] === ParameterMode.immediate ? valueB : this.memory[valueB]?.literalValue ?? 0;
const paramC = parameterModes[0] === ParameterMode.immediate ? valueC : this.memory[valueC]?.literalValue ?? 0;
/*console.debug(
opCode,
this.memory.slice(index, index + 4).map((val) => val.literalValue)
);*/
switch (opCode.instruction) {
case Instruction.add:
if (debug) {
console.debug(`Adding ${paramA}+${paramB} and writing ${paramA + paramB} to ${valueC}`);
}
this.memory[valueC] = new OpCode(paramA + paramB);
index += 4;
break;
case Instruction.mul:
if (debug) {
console.debug(`Multiplying ${paramA}*${paramB} and writing ${paramA * paramB} to ${valueC}`);
}
this.memory[valueC] = new OpCode(paramA * paramB);
index += 4;
break;
case Instruction.inp:
this.memory[valueA] = await new Promise<OpCode>((resolve, reject) => {
rl.question(`[${index.toString().padStart(5, "0")}]> `, (answer) => {
try {
const op = new OpCode(answer);
if (debug) {
console.debug(`Writing opCode with value ${op.literalValue} to ${valueA}`);
}
resolve(op);
} catch (e) {
reject(e);
}
});
});
index += 2;
break;
case Instruction.out:
if (debug) {
console.debug(`Outputting ${paramA}`);
}
output.push(paramA);
index += 2;
break;
case Instruction.jnz:
if (debug) {
console.debug(`Testing if ${paramA}!=0, if so, jumping to ${paramB}`);
}
if (paramA !== 0) {
index = paramB;
} else {
index += 3;
}
break;
case Instruction.jz:
if (debug) {
console.debug(`Testing if ${paramA}==0, if so, jumping to ${paramB}`);
}
if (paramA === 0) {
index = paramB;
} else {
index += 3;
}
break;
case Instruction.lt:
if (debug) {
console.debug(`Testing if ${paramA}<${paramB}, writing result to ${valueC}`);
}
this.memory[valueC] = new OpCode(paramA < paramB ? 1 : 0);
index += 4;
break;
case Instruction.eq:
if (debug) {
console.debug(`Testing if ${paramA}==${paramB}, writing result to ${valueC}`);
}
this.memory[valueC] = new OpCode(paramA === paramB ? 1 : 0);
index += 4;
break;
case Instruction.end:
console.log("Final output:", output);
return this.memory;
}
}
} catch (e) {
console.debug(`Execution failed at index ${index}. Dumping memory.`);
if (debug) {
debugLog!.write(
`${debugIteration.toString().padStart(5, "0")};${index.toString().padStart(5, "0")};[${this.memory
.map((op) => op.literalValue)
.join(",")}]\n`
);
}
throw e;
}
console.log("Final output:", output);
return this.memory;
}
reset() {
this.memory = this.initialMemory;
}
static memdump(memory: Memory) {
return memory.map((op) => op.toString()).join(",");
}
}
async function main(code: string) {
const memdump: Memory = code.split(",").map((val) => new OpCode(val));
const machine = new Machine(memdump);
const result = await machine.run();
rl.close();
return; // result ? Machine.memdump(result) : result;
}
const input = fs.readFileSync("input").toString();
main(input)
.then(console.log)
.catch((...args) => {
rl.close();
console.error(args);
});

View file

@ -12,14 +12,14 @@
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
"sourceMap": false, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
"noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

View file

@ -2,10 +2,10 @@
# yarn lockfile v1
"@types/node@^14.14.6":
version "14.14.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.6.tgz#146d3da57b3c636cc0d1769396ce1cfa8991147f"
integrity sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==
"@types/node@^14.14.8":
version "14.14.8"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.8.tgz#2127bd81949a95c8b7d3240f3254352d72563aec"
integrity sha512-z/5Yd59dCKI5kbxauAJgw6dLPzW+TNOItNE00PkpzNwUIEwdj/Lsqwq94H5DdYBX7C13aRA0CY32BK76+neEUA==
arg@^4.1.0:
version "4.1.3"
@ -32,6 +32,11 @@ prettier@^2.1.2:
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.1.2.tgz#3050700dae2e4c8b67c4c3f666cdb8af405e1ce5"
integrity sha512-16c7K+x4qVlJg9rEbXl7HEGmQyZlG4R9AgP+oHKRMsMsuk8s+ATStlf1NpDqyBI1HpVyfjLOeMhH2LvuNvV5Vg==
readline@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c"
integrity sha1-xYDXfvLPyHUrEySYBg3JeTp6wBw=
source-map-support@^0.5.17:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"

View file

@ -1,6 +1,6 @@
{
"scripts": {
"lint": "prettier solution_a.ts solution_b.ts --write",
"lint": "prettier solution_a.ts solution_b.ts --write --print-width=120",
"a": "ts-node solution_a.ts",
"b": "ts-node solution_b.ts"
},
@ -8,7 +8,7 @@
"prettier": "^2.1.2"
},
"dependencies": {
"@types/node": "^14.14.6",
"@types/node": "^14.14.8",
"ts-node": "^9.0.0",
"typescript": "^4.0.5"
},

View file

@ -3,4 +3,4 @@ const input = fs.readFileSync("input");
async function main() {}
main().then(console.log);
main().then(console.log).catch(console.error);

View file

@ -3,4 +3,4 @@ const input = fs.readFileSync("input");
async function main() {}
main().then(console.log);
main().then(console.log).catch(console.error);

View file

@ -12,14 +12,14 @@
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
"sourceMap": true, /* Generates corresponding '.map' file. */
"sourceMap": false, /* Generates corresponding '.map' file. */
// "outFile": "./", /* Concatenate and emit output to single file. */
// "outDir": "./", /* Redirect output structure to the directory. */
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. */
// "noEmit": true, /* Do not emit outputs. */
"noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */

View file

@ -2,10 +2,10 @@
# yarn lockfile v1
"@types/node@^14.14.6":
version "14.14.6"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.6.tgz#146d3da57b3c636cc0d1769396ce1cfa8991147f"
integrity sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==
"@types/node@^14.14.8":
version "14.14.8"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.8.tgz#2127bd81949a95c8b7d3240f3254352d72563aec"
integrity sha512-z/5Yd59dCKI5kbxauAJgw6dLPzW+TNOItNE00PkpzNwUIEwdj/Lsqwq94H5DdYBX7C13aRA0CY32BK76+neEUA==
arg@^4.1.0:
version "4.1.3"