Skip to content

Commit

Permalink
feat(2021-day-06): efficient methods for tracking lampfish schools at…
Browse files Browse the repository at this point in the history
… scale

solves part 2
  • Loading branch information
amclin committed Dec 14, 2021
1 parent b2eac5d commit f46f23a
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 6 deletions.
35 changes: 34 additions & 1 deletion 2021/day-06/fish.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ const NewFishAge = 8 // age of newly spawned fish
const FishSpawnAge = 0 // age when the fish spawns
const ResetFishAge = 6 // age of the original fish after spawning

// allocate an empty big school
const _newBigSchool = () => [...new Array(NewFishAge + 1)].map(() => 0)
let _bigSchool = _newBigSchool()

const ageFish = (age) => {
if (age > NewFishAge) { throw new Error('Fish is too young') }
if (age < FishSpawnAge) { throw new Error('Fish is too old') }
Expand All @@ -17,6 +21,11 @@ const spawn = (qty) => {
_fishes.push(...newFishes)
}

const efficientSpawn = (qty) => {
console.debug(`spawning ${qty} fish`)
_bigSchool[NewFishAge] = qty
}

const school = {
get state () {
return _fishes
Expand All @@ -35,8 +44,32 @@ const school = {
}
}

/**
* The efficient school doesn't track the position of the fish.
* It only cares about the total number of fish of each age
*/
const efficientSchool = {
get state () {
return _bigSchool
},
set state (state) {
_bigSchool = _newBigSchool()
state.forEach((fish) => { _bigSchool[fish]++ })
},
advance: () => {
// Calculate how many will spawn (age 0) and shift the age groups in one quick step
const toSpawn = _bigSchool.shift()
// Iterate old fish back to young since they're spawning
_bigSchool[ResetFishAge] += toSpawn
// Spawn the new fish
efficientSpawn(toSpawn)
}
}

module.exports = {
school,
efficientSchool,
ageFish,
spawn
spawn,
efficientSpawn
}
67 changes: 65 additions & 2 deletions 2021/day-06/fish.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-env mocha */
const { expect } = require('chai')
const { school, ageFish, spawn } = require('./fish')
const { school, ageFish, spawn, efficientSchool, efficientSpawn } = require('./fish')

describe('--- Day 6: Lanternfish ---', () => {
describe('Part 1', () => {
Expand Down Expand Up @@ -71,7 +71,70 @@ describe('--- Day 6: Lanternfish ---', () => {
expect(school.state).to.deep.equal([0, 1, 0, 5, 6, 0, 1, 2, 2, 3, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 7, 8])
school.advance()
expect(school.state).to.deep.equal([6, 0, 6, 4, 5, 6, 0, 1, 1, 2, 6, 0, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 8, 8, 8])
school.advance()
})
})
})
describe('Part 2', () => {
beforeEach(() => {
// ensure flushed state
efficientSchool.state = [3, 4, 3, 1, 2]
expect(efficientSchool.state).to.deep.equal([0, 1, 1, 2, 1, 0, 0, 0, 0])
})
describe('efficientSpawn()', () => {
it('efficiently adds new fish to the school', () => {
efficientSpawn(4)
expect(efficientSchool.state).to.deep.equal([0, 1, 1, 2, 1, 0, 0, 0, 4])
})
})
describe('efficientAdvance', () => {
it('advances one day following the same pattern without tracking unique position', () => {
const sum = (x, y) => x + y
efficientSchool.state = [3, 4, 3, 1, 2]

efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([2, 3, 2, 0, 1].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([1, 2, 1, 6, 0, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([0, 1, 0, 5, 6, 7, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([6, 0, 6, 4, 5, 6, 7, 8, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([5, 6, 5, 3, 4, 5, 6, 7, 7, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([4, 5, 4, 2, 3, 4, 5, 6, 6, 7].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([3, 4, 3, 1, 2, 3, 4, 5, 5, 6].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([2, 3, 2, 0, 1, 2, 3, 4, 4, 5].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([1, 2, 1, 6, 0, 1, 2, 3, 3, 4, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([0, 1, 0, 5, 6, 0, 1, 2, 2, 3, 7, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([6, 0, 6, 4, 5, 6, 0, 1, 1, 2, 6, 7, 8, 8, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([5, 6, 5, 3, 4, 5, 6, 0, 0, 1, 5, 6, 7, 7, 7, 8, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([4, 5, 4, 2, 3, 4, 5, 6, 6, 0, 4, 5, 6, 6, 6, 7, 7, 8, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([3, 4, 3, 1, 2, 3, 4, 5, 5, 6, 3, 4, 5, 5, 5, 6, 6, 7, 7, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([2, 3, 2, 0, 1, 2, 3, 4, 4, 5, 2, 3, 4, 4, 4, 5, 5, 6, 6, 7].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([1, 2, 1, 6, 0, 1, 2, 3, 3, 4, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([0, 1, 0, 5, 6, 0, 1, 2, 2, 3, 0, 1, 2, 2, 2, 3, 3, 4, 4, 5, 7, 8].length)
efficientSchool.advance()
expect(efficientSchool.state.reduce(sum)).to.equal([6, 0, 6, 4, 5, 6, 0, 1, 1, 2, 6, 0, 1, 1, 1, 2, 2, 3, 3, 4, 6, 7, 8, 8, 8, 8].length)
})
it('advances efficiently for a large number of days', () => {
efficientSchool.state = [3, 4, 3, 1, 2]
for (let d = 1; d <= 256; d++) {
efficientSchool.advance()
}
const sum = (x, y) => x + y
efficientSchool.state.reduce(sum)
})
})
})
Expand Down
12 changes: 9 additions & 3 deletions 2021/day-06/solution.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const fs = require('fs')
const path = require('path')
const filePath = path.join(__dirname, 'input.txt')
const { parseData } = require('../../2018/inputParser')
const { school } = require('./fish')
const { school, efficientSchool } = require('./fish')

fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => {
if (err) throw err
Expand All @@ -27,8 +27,14 @@ fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => {

const part2 = () => {
const data = resetInput()
console.debug(data)
return 'No answer yet'
efficientSchool.state = data
// Advance the designated time
for (let x = 0; x < 256; x++) {
efficientSchool.advance()
}
// Count how many fish we have
const sum = (x, y) => x + y
return efficientSchool.state.reduce(sum)
}
const answers = []
answers.push(part1())
Expand Down

0 comments on commit f46f23a

Please sign in to comment.