Ben Ashton
1 year ago
2 changed files with 191 additions and 0 deletions
@ -0,0 +1,55 @@
|
||||
Monkey 0: |
||||
Starting items: 54, 98, 50, 94, 69, 62, 53, 85 |
||||
Operation: new = old * 13 |
||||
Test: divisible by 3 |
||||
If true: throw to monkey 2 |
||||
If false: throw to monkey 1 |
||||
|
||||
Monkey 1: |
||||
Starting items: 71, 55, 82 |
||||
Operation: new = old + 2 |
||||
Test: divisible by 13 |
||||
If true: throw to monkey 7 |
||||
If false: throw to monkey 2 |
||||
|
||||
Monkey 2: |
||||
Starting items: 77, 73, 86, 72, 87 |
||||
Operation: new = old + 8 |
||||
Test: divisible by 19 |
||||
If true: throw to monkey 4 |
||||
If false: throw to monkey 7 |
||||
|
||||
Monkey 3: |
||||
Starting items: 97, 91 |
||||
Operation: new = old + 1 |
||||
Test: divisible by 17 |
||||
If true: throw to monkey 6 |
||||
If false: throw to monkey 5 |
||||
|
||||
Monkey 4: |
||||
Starting items: 78, 97, 51, 85, 66, 63, 62 |
||||
Operation: new = old * 17 |
||||
Test: divisible by 5 |
||||
If true: throw to monkey 6 |
||||
If false: throw to monkey 3 |
||||
|
||||
Monkey 5: |
||||
Starting items: 88 |
||||
Operation: new = old + 3 |
||||
Test: divisible by 7 |
||||
If true: throw to monkey 1 |
||||
If false: throw to monkey 0 |
||||
|
||||
Monkey 6: |
||||
Starting items: 87, 57, 63, 86, 87, 53 |
||||
Operation: new = old * old |
||||
Test: divisible by 11 |
||||
If true: throw to monkey 5 |
||||
If false: throw to monkey 0 |
||||
|
||||
Monkey 7: |
||||
Starting items: 73, 59, 82, 65 |
||||
Operation: new = old + 6 |
||||
Test: divisible by 2 |
||||
If true: throw to monkey 4 |
||||
If false: throw to monkey 3 |
@ -0,0 +1,136 @@
|
||||
import { readFileSync } from 'node:fs'; |
||||
|
||||
const input = readFileSync('input', 'utf-8'); |
||||
|
||||
class Item { |
||||
constructor(initialWorryLevel) { |
||||
this.worryLevel = initialWorryLevel; |
||||
} |
||||
} |
||||
|
||||
class Monkey { |
||||
constructor(monkeys, number, items, operation, test, afterInspectHook) { |
||||
this.monkeys = monkeys; |
||||
this.number = number; |
||||
this.items = items; |
||||
this.operation = operation; |
||||
this.test = test; |
||||
this.afterInspectHook = afterInspectHook; |
||||
|
||||
this.inspectCount = 0; |
||||
} |
||||
|
||||
processItem() { |
||||
const item = this.items.shift(); |
||||
item.worryLevel = this.operation(item.worryLevel); |
||||
this.inspectCount++; |
||||
this.afterInspectHook?.(item); |
||||
const passToMonkey = this.monkeys.get(this.test.test(item.worryLevel)); |
||||
passToMonkey.items.push(item); |
||||
} |
||||
|
||||
processItems() { |
||||
while (this.items.length) { |
||||
this.processItem(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
class Test { |
||||
constructor(divisibleBy, trueCondition, falseCondition) { |
||||
this.divisibleBy = divisibleBy; |
||||
this.trueCondition = trueCondition; |
||||
this.falseCondition = falseCondition; |
||||
} |
||||
|
||||
test(worryLevel) { |
||||
return worryLevel % this.divisibleBy === 0 ? |
||||
this.trueCondition : |
||||
this.falseCondition; |
||||
} |
||||
} |
||||
|
||||
export function getMonkeys(afterInspectHook) { |
||||
const monkeys = new Map(); |
||||
input |
||||
.split('\n\n') |
||||
.filter(monkeyData => /\S/.test(monkeyData)) |
||||
.forEach(monkeyData => { |
||||
let number; |
||||
let items; |
||||
let operation; |
||||
let test; |
||||
monkeyData |
||||
.trim() |
||||
.split(/\n (?=\S)/) |
||||
.forEach(data => { |
||||
if (data.startsWith('Monkey')) { |
||||
number = parseInt(data.match(/\d+/)[0]); |
||||
} else if (data.startsWith('Starting items')) { |
||||
items = data |
||||
.split(': ', 2)[1] |
||||
.split(', ') |
||||
.map(worryLevel => new Item(parseInt(worryLevel))); |
||||
} else if (data.startsWith('Operation')) { |
||||
operation = new Function( |
||||
'old', |
||||
`return ${data.split('new = ', 2)[1].trim()}` |
||||
); |
||||
} else if (data.startsWith('Test')) { |
||||
const divisibleBy = parseInt(data.match(/divisible by (\d+)/)[1]); |
||||
const trueCondition = parseInt(data.match(/true[^\n]*(\d+)/)[1]); |
||||
const falseCondition = parseInt(data.match(/false[^\n]*(\d+)/)[1]); |
||||
test = new Test(divisibleBy, trueCondition, falseCondition); |
||||
} |
||||
}); |
||||
monkeys.set( |
||||
number, |
||||
new Monkey(monkeys, number, items, operation, test, afterInspectHook) |
||||
); |
||||
}); |
||||
|
||||
return monkeys; |
||||
} |
||||
|
||||
export function simulateRounds(monkeys, nRounds) { |
||||
for (let round = 0; round < nRounds; round++) { |
||||
for (const number of [...monkeys.keys()].sort()) { |
||||
const monkey = monkeys.get(number); |
||||
|
||||
monkey.processItems(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
function calculateMonkeyBusinessLevel(monkeys) { |
||||
return [...monkeys.values()] |
||||
.sort((m1, m2) => m2.inspectCount - m1.inspectCount) |
||||
.slice(0, 2) |
||||
.map(monkey => monkey.inspectCount) |
||||
.reduce((total, monkeyBusiness) => total * monkeyBusiness); |
||||
} |
||||
|
||||
let monkeys; |
||||
let monkeyBusinessLevel; |
||||
|
||||
monkeys = getMonkeys( |
||||
item => item.worryLevel = Math.floor(item.worryLevel / 3) |
||||
); |
||||
simulateRounds(monkeys, 20); |
||||
monkeyBusinessLevel = calculateMonkeyBusinessLevel(monkeys); |
||||
console.log( |
||||
`Level of monkey business after 20 rounds: ${monkeyBusinessLevel}` |
||||
); |
||||
|
||||
monkeys = getMonkeys(item => { |
||||
const commonMultiple = [...monkeys.values()] |
||||
.map(monkey => monkey.test.divisibleBy) |
||||
.reduce((total, divisibleBy) => total * divisibleBy); |
||||
// Reduce item by commonMultiple whenever it exceeds that value
|
||||
return item.worryLevel = item.worryLevel % commonMultiple; |
||||
}); |
||||
simulateRounds(monkeys, 10000); |
||||
monkeyBusinessLevel = calculateMonkeyBusinessLevel(monkeys); |
||||
console.log( |
||||
`Level of monkey business after 10000 rounds: ${monkeyBusinessLevel}` |
||||
); |
Loading…
Reference in new issue