Skip to content

Commit f46f23a

Browse files
feat(2021-day-06): efficient methods for tracking lampfish schools at scale
solves part 2
1 parent b2eac5d commit f46f23a

File tree

3 files changed

+108
-6
lines changed

3 files changed

+108
-6
lines changed

2021/day-06/fish.js

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ const NewFishAge = 8 // age of newly spawned fish
44
const FishSpawnAge = 0 // age when the fish spawns
55
const ResetFishAge = 6 // age of the original fish after spawning
66

7+
// allocate an empty big school
8+
const _newBigSchool = () => [...new Array(NewFishAge + 1)].map(() => 0)
9+
let _bigSchool = _newBigSchool()
10+
711
const ageFish = (age) => {
812
if (age > NewFishAge) { throw new Error('Fish is too young') }
913
if (age < FishSpawnAge) { throw new Error('Fish is too old') }
@@ -17,6 +21,11 @@ const spawn = (qty) => {
1721
_fishes.push(...newFishes)
1822
}
1923

24+
const efficientSpawn = (qty) => {
25+
console.debug(`spawning ${qty} fish`)
26+
_bigSchool[NewFishAge] = qty
27+
}
28+
2029
const school = {
2130
get state () {
2231
return _fishes
@@ -35,8 +44,32 @@ const school = {
3544
}
3645
}
3746

47+
/**
48+
* The efficient school doesn't track the position of the fish.
49+
* It only cares about the total number of fish of each age
50+
*/
51+
const efficientSchool = {
52+
get state () {
53+
return _bigSchool
54+
},
55+
set state (state) {
56+
_bigSchool = _newBigSchool()
57+
state.forEach((fish) => { _bigSchool[fish]++ })
58+
},
59+
advance: () => {
60+
// Calculate how many will spawn (age 0) and shift the age groups in one quick step
61+
const toSpawn = _bigSchool.shift()
62+
// Iterate old fish back to young since they're spawning
63+
_bigSchool[ResetFishAge] += toSpawn
64+
// Spawn the new fish
65+
efficientSpawn(toSpawn)
66+
}
67+
}
68+
3869
module.exports = {
3970
school,
71+
efficientSchool,
4072
ageFish,
41-
spawn
73+
spawn,
74+
efficientSpawn
4275
}

2021/day-06/fish.test.js

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-env mocha */
22
const { expect } = require('chai')
3-
const { school, ageFish, spawn } = require('./fish')
3+
const { school, ageFish, spawn, efficientSchool, efficientSpawn } = require('./fish')
44

55
describe('--- Day 6: Lanternfish ---', () => {
66
describe('Part 1', () => {
@@ -71,7 +71,70 @@ describe('--- Day 6: Lanternfish ---', () => {
7171
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])
7272
school.advance()
7373
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])
74-
school.advance()
74+
})
75+
})
76+
})
77+
describe('Part 2', () => {
78+
beforeEach(() => {
79+
// ensure flushed state
80+
efficientSchool.state = [3, 4, 3, 1, 2]
81+
expect(efficientSchool.state).to.deep.equal([0, 1, 1, 2, 1, 0, 0, 0, 0])
82+
})
83+
describe('efficientSpawn()', () => {
84+
it('efficiently adds new fish to the school', () => {
85+
efficientSpawn(4)
86+
expect(efficientSchool.state).to.deep.equal([0, 1, 1, 2, 1, 0, 0, 0, 4])
87+
})
88+
})
89+
describe('efficientAdvance', () => {
90+
it('advances one day following the same pattern without tracking unique position', () => {
91+
const sum = (x, y) => x + y
92+
efficientSchool.state = [3, 4, 3, 1, 2]
93+
94+
efficientSchool.advance()
95+
expect(efficientSchool.state.reduce(sum)).to.equal([2, 3, 2, 0, 1].length)
96+
efficientSchool.advance()
97+
expect(efficientSchool.state.reduce(sum)).to.equal([1, 2, 1, 6, 0, 8].length)
98+
efficientSchool.advance()
99+
expect(efficientSchool.state.reduce(sum)).to.equal([0, 1, 0, 5, 6, 7, 8].length)
100+
efficientSchool.advance()
101+
expect(efficientSchool.state.reduce(sum)).to.equal([6, 0, 6, 4, 5, 6, 7, 8, 8].length)
102+
efficientSchool.advance()
103+
expect(efficientSchool.state.reduce(sum)).to.equal([5, 6, 5, 3, 4, 5, 6, 7, 7, 8].length)
104+
efficientSchool.advance()
105+
expect(efficientSchool.state.reduce(sum)).to.equal([4, 5, 4, 2, 3, 4, 5, 6, 6, 7].length)
106+
efficientSchool.advance()
107+
expect(efficientSchool.state.reduce(sum)).to.equal([3, 4, 3, 1, 2, 3, 4, 5, 5, 6].length)
108+
efficientSchool.advance()
109+
expect(efficientSchool.state.reduce(sum)).to.equal([2, 3, 2, 0, 1, 2, 3, 4, 4, 5].length)
110+
efficientSchool.advance()
111+
expect(efficientSchool.state.reduce(sum)).to.equal([1, 2, 1, 6, 0, 1, 2, 3, 3, 4, 8].length)
112+
efficientSchool.advance()
113+
expect(efficientSchool.state.reduce(sum)).to.equal([0, 1, 0, 5, 6, 0, 1, 2, 2, 3, 7, 8].length)
114+
efficientSchool.advance()
115+
expect(efficientSchool.state.reduce(sum)).to.equal([6, 0, 6, 4, 5, 6, 0, 1, 1, 2, 6, 7, 8, 8, 8].length)
116+
efficientSchool.advance()
117+
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)
118+
efficientSchool.advance()
119+
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)
120+
efficientSchool.advance()
121+
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)
122+
efficientSchool.advance()
123+
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)
124+
efficientSchool.advance()
125+
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)
126+
efficientSchool.advance()
127+
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)
128+
efficientSchool.advance()
129+
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)
130+
})
131+
it('advances efficiently for a large number of days', () => {
132+
efficientSchool.state = [3, 4, 3, 1, 2]
133+
for (let d = 1; d <= 256; d++) {
134+
efficientSchool.advance()
135+
}
136+
const sum = (x, y) => x + y
137+
efficientSchool.state.reduce(sum)
75138
})
76139
})
77140
})

2021/day-06/solution.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const fs = require('fs')
22
const path = require('path')
33
const filePath = path.join(__dirname, 'input.txt')
44
const { parseData } = require('../../2018/inputParser')
5-
const { school } = require('./fish')
5+
const { school, efficientSchool } = require('./fish')
66

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

2828
const part2 = () => {
2929
const data = resetInput()
30-
console.debug(data)
31-
return 'No answer yet'
30+
efficientSchool.state = data
31+
// Advance the designated time
32+
for (let x = 0; x < 256; x++) {
33+
efficientSchool.advance()
34+
}
35+
// Count how many fish we have
36+
const sum = (x, y) => x + y
37+
return efficientSchool.state.reduce(sum)
3238
}
3339
const answers = []
3440
answers.push(part1())

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy