Published
Edited
Dec 9, 2019
Insert cell
md`# Advent of Code 2019 Day 7`
Insert cell
class Intcode {
constructor( program ) {
this.program = [ ...program ];
this.inputs = [];
this.onOutput = () => {};
this.state = 'RUNNING';
this.pointer = 0;
}
input( val ) {
if ( this.state == 'HALTED' ) return;
this.inputs.push( val );
this.state = 'RUNNING';
this.tick();
}
tick() {
if ( this.state == 'HALTED' || this.state == 'WAITING' ) return;
if ( typeof this.pointer == "undefined" ) throw JSON.stringify( this );

let op = this.program[ this.pointer ];
let args = [
this.program[ this.program[ this.pointer + 1 ] ],
this.program[ this.program[ this.pointer + 2 ] ],
this.program[ this.program[ this.pointer + 3 ] ]
];
// Immediate mode
if ( op > 99 ) {
if ( Math.floor( op / 100 ) % 10 == 1 ) args[0] = this.program[ this.pointer + 1 ];
if ( Math.floor( op / 1000 ) % 10 == 1 ) args[1] = this.program[ this.pointer + 2 ];
if ( Math.floor( op / 10000 ) % 10 == 1 ) args[2] = this.program[ this.pointer + 3 ];
op = op % 100;
}
switch ( op ) {
// add
case 1:
this.program[ this.program[ this.pointer + 3 ] ] = args[0] + args[1];
this.pointer += 4;
break;
// multiply
case 2:
this.program[ this.program[ this.pointer + 3 ] ] = args[0] * args[1];
this.pointer += 4;
break;
// input
case 3:
if ( this.inputs.length == 0 ) {
console.log( 'waiting for input', this );
this.state = 'WAITING';
break;
}
console.log( 'used existing input: ', this );
this.program[ this.program[ this.pointer + 1 ] ] = this.inputs.shift();
this.pointer += 2;
break;
// output
case 4:
this.onOutput( args[ 0 ] );
this.pointer += 2;
break;
// not-zero
case 5:
if ( args[0] !== 0 ) {
this.pointer = args[1];
} else {
this.pointer += 3;
}
break;
// equals zero
case 6:
if ( args[0] == 0 ) {
this.pointer = args[1];
} else {
this.pointer += 3;
}
break;
// greater than
case 7:
this.program[ this.program[ this.pointer + 3 ] ] = ( args[0] < args[1] ) ? 1 : 0;
this.pointer += 4;
break;
// equals
case 8:
this.program[ this.program[ this.pointer + 3 ] ] = ( args[0] == args[1] ) ? 1 : 0;
this.pointer += 4;
break;

// halt
case 99:
this.state = 'HALTED';
break;

default:
throw `Bad operation: ${op}`
}
}
}
Insert cell
amplify = ( program, phases ) => {
let signal = 0;
for ( let i = 0; i < phases.length; i++ ) {
const amp = new Intcode( program );
amp.onOutput = ( val ) => signal = val;
amp.input( phases[ i ] );
amp.input( signal );
while ( amp.state !== 'HALTED' ) {
amp.tick();
}
}
return signal;
}
Insert cell
amplify( [ 3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0 ], [4,3,2,1,0] ) // 43210
Insert cell
amplify( [ 3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0 ], [0,1,2,3,4] )
Insert cell
amplify( [ 3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0], [1,0,4,3,2] );
Insert cell
function cut(arr, idx ) {
return [ arr[idx], [ ...arr.slice(0, idx), ...arr.slice(idx + 1) ] ]
}
Insert cell
permute = ( arr ) => {
const results = [];
const permuter = ( arr, memo = [] ) => {
if ( ! arr.length ) {
results.push( memo );
return;
}
for ( let i = 0; i < arr.length; i++ ) {
const [ item, rest ] = cut( arr, i );
permuter( rest, [ ...memo, item ] )
}
}
permuter( arr );
return results;
}
Insert cell
permute( ['A','B','C'] )
Insert cell
permute( [0,1,2,3,4] )
.map( phases => ( { phases, signal: amplify( [3,15,3,16,1002,16,10,16,1,16,15,15,4,15,99,0,0], phases ) } ) )
.reduce( ( memo, sigObj ) => memo.signal > sigObj.signal ? memo : sigObj )
Insert cell
bestSignal = ( program ) => {
return permute( [0,1,2,3,4] )
.map( phases => ( { phases, signal: amplify( program, phases ) } ) )
.reduce( ( memo, sigObj ) => memo.signal > sigObj.signal ? memo : sigObj )
}
Insert cell
bestSignal( [ 3,23,3,24,1002,24,10,24,1002,23,-1,23,101,5,23,23,1,24,23,23,4,23,99,0,0 ] )
Insert cell
bestSignal( [ 3,31,3,32,1002,32,10,32,1001,31,-2,31,1007,31,0,33,1002,33,7,33,1,33,31,31,1,32,31,31,4,31,99,0,0,0] )
Insert cell
bestSignal( [3,8,1001,8,10,8,105,1,0,0,21,46,67,76,97,118,199,280,361,442,99999,3,9,1002,9,3,9,101,4,9,9,102,3,9,9,1001,9,3,9,1002,9,2,9,4,9,99,3,9,102,2,9,9,101,5,9,9,1002,9,2,9,101,2,9,9,4,9,99,3,9,101,4,9,9,4,9,99,3,9,1001,9,4,9,102,2,9,9,1001,9,4,9,1002,9,5,9,4,9,99,3,9,102,3,9,9,1001,9,2,9,1002,9,3,9,1001,9,3,9,4,9,99,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,99] )
Insert cell
md`# Part 2`
Insert cell
amplify2 = ( program, phases ) => {
let signal = 0,
outputs = [];
const nextAmp = ( i ) => ( i < phases.length - 1 ) ? i + 1 : 0;
const amp0 = new Intcode( program );
const amp1 = new Intcode( program );
const amp2 = new Intcode( program );
const amp3 = new Intcode( program );
const amp4 = new Intcode( program );
const amps = [ amp0, amp1, amp2, amp3, amp4 ];
const allStopped = () => amps.every( a => a.state == 'HALTED' );
amp0.onOutput = ( val ) => amp1.input( val );
amp0.input( phases[0] );

amp1.onOutput = ( val ) => amp2.input( val );
amp1.input( phases[1] );
amp2.onOutput = ( val ) => amp3.input( val );
amp2.input( phases[2] );
amp3.onOutput = ( val ) => amp4.input( val );
amp3.input( phases[3] );
amp4.onOutput = ( val ) => {
signal = val;
amp0.input( val );
}
amp4.input( phases[4] );
try {
amp0.input( signal );
while ( ! allStopped() ) {
amps.forEach( a => a.tick() )
}
} catch ( e ) {
console.error( e );
return ["DEAD", amp0, amp1, amp2, amp3, amp4 ];
}
return signal;
}
Insert cell
amplify2( [3,26,1001,26,-4,26,3,27,1002,27,2,27,1,27,26,27,4,27,1001,28,-1,28,1005,28,6,99,0,0,5], [ 9,8,7,6,5 ] )
Insert cell
amplify2( [3,52,1001,52,-5,52,3,53,1,52,56,54,1007,54,5,55,1005,55,26,1001,54,
-5,54,1105,1,12,1,53,54,53,1008,54,0,55,1001,55,1,55,2,53,55,53,4,
53,1001,56,-1,56,1005,56,6,99,0,0,0,0,10], [ 9,7,8,5,6 ] )
Insert cell
bestSignal2 = ( program ) => {
return permute( [5,6,7,8,9] )
.map( phases => ( { phases, signal: amplify2( program, phases ) } ) )
.reduce( ( memo, sigObj ) => memo.signal > sigObj.signal ? memo : sigObj )
}
Insert cell
bestSignal2( [3,8,1001,8,10,8,105,1,0,0,21,46,67,76,97,118,199,280,361,442,99999,3,9,1002,9,3,9,101,4,9,9,102,3,9,9,1001,9,3,9,1002,9,2,9,4,9,99,3,9,102,2,9,9,101,5,9,9,1002,9,2,9,101,2,9,9,4,9,99,3,9,101,4,9,9,4,9,99,3,9,1001,9,4,9,102,2,9,9,1001,9,4,9,1002,9,5,9,4,9,99,3,9,102,3,9,9,1001,9,2,9,1002,9,3,9,1001,9,3,9,4,9,99,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,99,3,9,102,2,9,9,4,9,3,9,101,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,102,2,9,9,4,9,3,9,101,1,9,9,4,9,3,9,101,2,9,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,1,9,4,9,3,9,101,1,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1001,9,1,9,4,9,3,9,1002,9,2,9,4,9,3,9,1001,9,1,9,4,9,99,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1002,9,2,9,4,9,3,9,101,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,101,1,9,9,4,9,3,9,102,2,9,9,4,9,3,9,102,2,9,9,4,9,3,9,1001,9,2,9,4,9,3,9,1002,9,2,9,4,9,99] )
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more