Skip to content

Instantly share code, notes, and snippets.

@pseale
Created December 21, 2016 08:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pseale/18366d6ccc7df8213479c4550d7160a0 to your computer and use it in GitHub Desktop.
Save pseale/18366d6ccc7df8213479c4550d7160a0 to your computer and use it in GitHub Desktop.
//------------------------------------------------
// Node console runner
import fs = require("fs")
import Global = require("./global")
import parse = require("./parse")
import run = require("./run")
const input = fs.readFileSync("./input.txt", "utf8")
const instructions = parse(input)
console.log("Part A:")
run(instructions, Global.InitType.a)
console.log("\n\n\n")
console.log("Part B:")
run(instructions, Global.InitType.b)
//------------------------------------------------
// run.ts - this is the interesting part
import _ = require("lodash")
import Global = require("./global")
type Registers = Global.RegisterState[]
interface State {
location: number,
registers: Registers
}
// for the purposes of Advent of Code, we'll assume registers are initialized to 0
// Part B - AHA! I KNEW IT! Can't get fooled twice.
function init(type: Global.InitType): State {
return {
location: 0,
registers: [
{ register: Global.Register.a, value: 0},
{ register: Global.Register.b, value: 0},
{ register: Global.Register.c, value: type === Global.InitType.b ? 1 : 0},
{ register: Global.Register.d, value: 0},
]
}
}
function replace(registers: Registers, registerState: Global.RegisterState): Registers {
const others = registers.filter(x => x.register !== registerState.register)
return others.concat(registerState)
}
function processCpyValue(state: State, cpyValue: Global.CpyValue): State {
const registerNewState = {
register: cpyValue.destination,
value: cpyValue.value
}
return {
location: state.location + 1,
registers: replace(state.registers, registerNewState)
}
}
function processCpyRegister(state: State, cpyRegister: Global.CpyRegister): State {
const copyFrom = state.registers.filter(x => x.register === cpyRegister.source)[0]
const registerNewState = {
register: cpyRegister.destination,
value: copyFrom.value
}
return {
location: state.location + 1,
registers: replace(state.registers, registerNewState)
}
}
function processIncOrDec(state: State, register: Global.Register, value: number): State {
const registerCurrentState = state.registers.filter(x => x.register === register)[0]
const registerNewState = {
register,
value: registerCurrentState.value + value
}
return {
location: state.location + 1,
registers: replace(state.registers, registerNewState)
}
}
function processInc(state: State, inc: Global.Inc): State {
return processIncOrDec(state, inc.register, +1)
}
function processDec(state: State, dec: Global.Dec): State {
return processIncOrDec(state, dec.register, -1)
}
function jumpIfNotZero(state: State, value: number, jump: number): State {
if (value !== 0) {
return {
location: state.location + jump,
registers: state.registers
}
}
return {
location: state.location + 1,
registers: state.registers
}
}
function processJnzRegister(state: State, jnz: Global.JnzRegister): State {
const register = state.registers.filter(x => x.register === jnz.register)[0]
// Jump if Not Zero (JNZ)
return jumpIfNotZero(state, register.value, jnz.jump)
}
function processJnzValue(state: State, jnz: Global.JnzValue): State {
// Jump if Not Zero (JNZ)
return jumpIfNotZero(state, jnz.value, jnz.jump)
}
function prettyPrint(state: State): void {
console.log(`Memory location: ${state.location}`)
_(state.registers)
.sortBy(x => x.register)
.each(x => console.log(`Register ${Global.Register[x.register]}: ${x.value}`))
}
function process(state: State, instruction: Global.Instruction): State {
if (instruction instanceof Global.CpyValue) {
return processCpyValue(state, instruction)
} else if (instruction instanceof Global.CpyRegister) {
return processCpyRegister(state, instruction)
} else if (instruction instanceof Global.Inc) {
return processInc(state, instruction)
} else if (instruction instanceof Global.Dec) {
return processDec(state, instruction)
} else if (instruction instanceof Global.JnzRegister) {
return processJnzRegister(state, instruction)
} else if (instruction instanceof Global.JnzValue) {
return processJnzValue(state, instruction)
} else {
throw `Error: couldn't process instruction ${instruction} - type '${typeof(instruction)}'`
}
}
function run(instructions: Global.Instruction[], type: Global.InitType): void {
let state = init(type)
let locationIndicatingWeShouldTerminate = instructions.length
while (state.location < locationIndicatingWeShouldTerminate) {
state = process(state, instructions[state.location])
}
prettyPrint(state)
}
export = run
//------------------------------------------------
// parse.ts - parse text into Instruction objects
import Global = require("./global")
function parseCpy(tokens: string[]): Global.CpyRegister|Global.CpyValue {
const destination = Global.Register[tokens[2]]
const value = Number(tokens[1])
if (!isNaN(value)) {
return new Global.CpyValue(value, destination)
} else {
return new Global.CpyRegister(Global.Register[tokens[1]], destination)
}
}
function parseInc(tokens: string[]): Global.Inc {
return new Global.Inc(Global.Register[tokens[1]])
}
function parseDec(tokens: string[]): Global.Dec {
return new Global.Dec(Global.Register[tokens[1]])
}
function parseJnz(tokens: string[]): Global.JnzRegister|Global.JnzValue {
const jump = Number(tokens[2])
const value = Number(tokens[1])
if (!isNaN(value)) {
return new Global.JnzValue(Number(tokens[1]), jump)
} else {
return new Global.JnzRegister(Global.Register[tokens[1]], jump)
}
}
function parseLine(line: string): Global.Instruction {
const tokens = line.split(" ")
if (tokens[0] === "cpy") {
return parseCpy(tokens)
} else if (tokens[0] === "inc") {
return parseInc(tokens)
} else if (tokens[0] === "dec") {
return parseDec(tokens)
} else if (tokens[0] === "jnz") {
return parseJnz(tokens)
} else {
throw `Error: couldn't parse line as its first token is unrecognized. Line: '${line}'`
}
}
function parse(text: string): Global.Instruction[] {
const lines = text.split("\n")
.map(x => x.trim())
.filter(x => x !== "")
return lines.map(x => parseLine(x))
}
export = parse
//------------------------------------------------
// global.ts - shared types (only types, no shared functions)
// Part A or Part B
export enum InitType {
a,
b
}
export enum Register {
a,
b,
c,
d
}
export class CpyRegister {
private _source: Register
private _destination: Register
get source(): Register { return this._source }
get destination(): Register { return this._destination }
public constructor(source: Register, destination: Register) {
this._source = source
this._destination = destination
}
}
export class CpyValue {
private _value: number
private _destination: Register
get value(): number { return this._value }
get destination(): Register { return this._destination }
public constructor(value: number, destination: Register) {
this._value = value
this._destination = destination
}
}
export class Inc {
private _register: Register
get register(): Register { return this._register }
public constructor(register: Register) {
this._register = register
}
}
export class Dec {
private _register: Register
get register(): Register { return this._register }
public constructor(register: Register) {
this._register = register
}
}
export class JnzValue {
private _value: number
private _jump: number
get value(): Register { return this._value }
get jump(): Register { return this._jump }
public constructor(value: number, jump: number) {
this._value = value
this._jump = jump
}
}
export class JnzRegister {
private _register: Register
private _jump: number
get register(): Register { return this._register }
get jump(): Register { return this._jump }
public constructor(register: Register, jump: number) {
this._register = register
this._jump = jump
}
}
export type Instruction = CpyRegister|CpyValue|Inc|Dec|JnzRegister|JnzValue
export interface RegisterState {
register: Register,
value: number
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment