Ben Ashton
1 year ago
2 changed files with 2894 additions and 0 deletions
@ -0,0 +1,139 @@ |
|||||||
|
import { readFileSync } from 'node:fs'; |
||||||
|
|
||||||
|
const input = readFileSync('input', 'utf-8'); |
||||||
|
|
||||||
|
class Monkey { |
||||||
|
constructor(monkeys, name) { |
||||||
|
this.monkeys = monkeys; |
||||||
|
this.name = name; |
||||||
|
this.value = undefined; |
||||||
|
this.formulas = []; |
||||||
|
this.aliases = []; |
||||||
|
} |
||||||
|
|
||||||
|
addFormula(left, operator, right) { |
||||||
|
this.formulas.push([left, operator, right]); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
removeFormulasInvolving(name) { |
||||||
|
this.formulas = this.formulas.filter( |
||||||
|
([left, _, right]) => left !== name && right !== name |
||||||
|
); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
addAlias(name) { |
||||||
|
this.aliases.push(name); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
setValue(value) { |
||||||
|
this.value = value; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
solve(path = []) { |
||||||
|
if (this.value !== undefined) { |
||||||
|
return this.value; |
||||||
|
} |
||||||
|
for (const name of this.aliases) { |
||||||
|
if (path.includes(name)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
const value = this.monkeys[name].solve([...path, this.name]); |
||||||
|
if (value !== 'UNKNOWN') { |
||||||
|
return value; |
||||||
|
} |
||||||
|
} |
||||||
|
for (const [left, operator, right] of this.formulas) { |
||||||
|
if (path.includes(left) || path.includes(right)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
const leftValue = this.monkeys[left].solve([...path, this.name]); |
||||||
|
const rightValue = this.monkeys[right].solve([...path, this.name]); |
||||||
|
|
||||||
|
if (leftValue === 'UNKNOWN' || rightValue === 'UNKNOWN') { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
switch (operator) { |
||||||
|
case '*': return leftValue * rightValue; |
||||||
|
case '/': return leftValue / rightValue; |
||||||
|
case '+': return leftValue + rightValue; |
||||||
|
case '-': return leftValue - rightValue; |
||||||
|
} |
||||||
|
} |
||||||
|
return 'UNKNOWN'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const monkeys = {}; |
||||||
|
function getMonkey(name) { |
||||||
|
if (!monkeys.hasOwnProperty(name)) { |
||||||
|
monkeys[name] = new Monkey(monkeys, name) |
||||||
|
} |
||||||
|
return monkeys[name]; |
||||||
|
} |
||||||
|
|
||||||
|
input |
||||||
|
.split('\n') |
||||||
|
.filter(line => !!line.trim()) |
||||||
|
.forEach(line => { |
||||||
|
const match = line.match(/^(\w+):\s+(.+?)\s*$/); |
||||||
|
if (!match) { |
||||||
|
throw new Error(`Invalid monkey: ${line}`); |
||||||
|
} |
||||||
|
const name = match[1]; |
||||||
|
const job = match[2]; |
||||||
|
|
||||||
|
if (/^\d+$/.test(job)) { |
||||||
|
getMonkey(name).setValue(parseInt(job)); |
||||||
|
} else { |
||||||
|
const match = job.match(/^(\w+)\s*([*\/+\-=])\s*(\w+)$/); |
||||||
|
if (!match) { |
||||||
|
throw new Error(`Invalid formula: ${formula}`); |
||||||
|
} |
||||||
|
const left = match[1]; |
||||||
|
const operator = match[2]; |
||||||
|
const right = match[3]; |
||||||
|
|
||||||
|
switch (operator) { |
||||||
|
case '*': |
||||||
|
getMonkey(name).addFormula(left, '*', right); |
||||||
|
getMonkey(left).addFormula(name, '/', right); |
||||||
|
getMonkey(right).addFormula(name, '/', left); |
||||||
|
break; |
||||||
|
case '/': |
||||||
|
getMonkey(name).addFormula(left, '/', right); |
||||||
|
getMonkey(left).addFormula(name, '*', right); |
||||||
|
getMonkey(right).addFormula(left, '/', name); |
||||||
|
break; |
||||||
|
case '-': |
||||||
|
getMonkey(name).addFormula(left, '-', right); |
||||||
|
getMonkey(left).addFormula(name, '+', right); |
||||||
|
getMonkey(right).addFormula(left, '-', name); |
||||||
|
break; |
||||||
|
case '+': |
||||||
|
getMonkey(name).addFormula(left, '+', right); |
||||||
|
getMonkey(left).addFormula(name, '-', right); |
||||||
|
getMonkey(right).addFormula(name, '-', left); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new Error(`Invalid operator: ${operator}`); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
const rootYells = monkeys['root'].solve(); |
||||||
|
console.log('The root monkey will yell:', rootYells); |
||||||
|
|
||||||
|
for (const monkey of Object.values(monkeys)) { |
||||||
|
monkey.removeFormulasInvolving('root'); |
||||||
|
} |
||||||
|
const {0: left, 2: right} = monkeys['root'].formulas[0]; |
||||||
|
monkeys[left].addAlias(right); |
||||||
|
monkeys[right].addAlias(left); |
||||||
|
const humnYells = monkeys['humn'].setValue(undefined).solve(); |
||||||
|
console.log('To pass roots equality test, yell:', humnYells); |
Loading…
Reference in new issue