8000 Merge pull request #204 from amclin/feat/2021-day-06 · developher-net/advent-of-code@62cd42a · GitHub
[go: up one dir, main page]

Skip to content

Commit 62cd42a

Browse files
Merge pull request #204 from amclin/feat/2021-day-06
Feat/2021 day 06
2 parents 6272342 + f46f23a commit 62cd42a

File tree

6 files changed

+268
-1
lines changed

6 files changed

+268
-1
lines changed

2021/day-06/fish.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
let _fishes = []
3+
const NewFishAge = 8 // age of newly spawned fish
4+
const FishSpawnAge = 0 // age when the fish spawns
5+
const ResetFishAge = 6 // age of the original fish after spawning
6+
7+
// allocate an empty big school
8+
const _newBigSchool = () => [...new Array(NewFishAge + 1)].map(() => 0)
9+
let _bigSchool = _newBigSchool()
10+
11+
const ageFish = (age) => {
12+
if (age > NewFishAge) { throw new Error('Fish is too young') }
13+
if (age < FishSpawnAge) { throw new Error('Fish is too old') }
14+
if (age === FishSpawnAge) { return ResetFishAge }
15+
return age - 1
16+
}
17+
18+
const spawn = (qty) => {
19+
console.debug(`spawning ${qty} fish`)
20+
const newFishes = [...new Array(qty)].map(() => NewFishAge)
21+
_fishes.push(...newFishes)
22+
}
23+
24+
const efficientSpawn = (qty) => {
25+
console.debug(`spawning ${qty} fish`)
26+
_bigSchool[NewFishAge] = qty
27+
}
28+
29+
const school = {
30+
get state () {
31+
return _fishes
32+
},
33+
set state (state) {
34+
_fishes = state
35+
},
36+
37+
advance: () => {
38+
// Calculate how many will spawn
39+
const toSpawn = _fishes.filter((x) => x === FishSpawnAge).length
40+
// Iterate each fish
41+
_fishes = _fishes.map(ageFish)
42+
// Spawn the new fish
43+
spawn(toSpawn)
44+
}
45+
}
46+
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+
69+
module.exports = {
70+
school,
71+
efficientSchool,
72+
ageFish,
73+
spawn,
74+
efficientSpawn
75+
}

2021/day-06/fish.test.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/* eslint-env mocha */
2+
const { expect } = require('chai')
3+
const { school, ageFish, spawn, efficientSchool, efficientSpawn } = require('./fish')
4+
5+
describe('--- Day 6: Lanternfish ---', () => {
6+
describe('Part 1', () => {
7+
beforeEach(() => {
8+
// ensure flushed state
9+
school.state = [3, 4, 3, 1, 2]
10+
expect(school.state).to.deep.equal([3, 4, 3, 1, 2])
11+
})
12+
describe('spawn()', () => {
13+
it('adds new fish to the end of the list', () => {
14+
spawn(4)
15+
expect(school.state).to.deep.equal([3, 4, 3, 1, 2, 8, 8, 8, 8])
16+
})
17+
})
18+
describe('ageFish()', () => {
19+
it('ages a particular fish', () => {
20+
expect(ageFish(6)).to.equal(5)
21+
expect(ageFish(5)).to.equal(4)
22+
expect(ageFish(4)).to.equal(3)
23+
expect(ageFish(3)).to.equal(2)
24+
expect(ageFish(2)).to.equal(1)
25+
expect(ageFish(1)).to.equal(0)
26+
expect(ageFish(0)).to.equal(6)
27+
expect(ageFish(8)).to.equal(7)
28+
expect(ageFish(7)).to.equal(6)
29+
})
30+
it('throws an error if the fish is out of range', () => {
31+
expect(() => { ageFish(9) }).to.throw('Fish is too young')
32+
expect(() => { ageFish(-1) }).to.throw('Fish is too old')
33+
})
34+
})
35+
describe('advance()', () => {
36+
it('advances one day', () => {
37+
school.state = [3, 4, 3, 1, 2]
38+
school.advance()
39+
expect(school.state).to.deep.equal([2, 3, 2, 0, 1])
40+
school.advance()
41+
expect(school.state).to.deep.equal([1, 2, 1, 6, 0, 8])
42+
school.advance()
43+
expect(school.state).to.deep.equal([0, 1, 0, 5, 6, 7, 8])
44+
school.advance()
45+
expect(school.state).to.deep.equal([6, 0, 6, 4, 5, 6, 7, 8, 8])
46+
school.advance()
47+
expect(school.state).to.deep.equal([5, 6, 5, 3, 4, 5, 6, 7, 7, 8])
48+
school.advance()
49+
expect(school.state).to.deep.equal([4, 5, 4, 2, 3, 4, 5, 6, 6, 7])
50+
school.advance()
51+
expect(school.state).to.deep.equal([3, 4, 3, 1, 2, 3, 4, 5, 5, 6])
52+
school.advance()
53+
expect(school.state).to.deep.equal([2, 3, 2, 0, 1, 2, 3, 4, 4, 5])
54+
school.advance()
55+
expect(school.state).to.deep.equal([1, 2, 1, 6, 0, 1, 2, 3, 3, 4, 8])
56+
school.advance()
57+
expect(school.state).to.deep.equal([0, 1, 0, 5, 6, 0, 1, 2, 2, 3, 7, 8])
58+
school.advance()
59+
expect(school.state).to.deep.equal([6, 0, 6, 4, 5, 6, 0, 1, 1, 2, 6, 7, 8, 8, 8])
60+
school.advance()
61+
expect(school.state).to.deep.equal([5, 6, 5, 3, 4, 5, 6, 0, 0, 1, 5, 6, 7, 7, 7, 8, 8])
62+
school.advance()
63+
expect(school.state).to.deep.equal([4, 5, 4, 2, 3, 4, 5, 6, 6, 0, 4, 5, 6, 6, 6, 7, 7, 8, 8])
64+
school.advance()
65+
expect(school.state).to.deep.equal([3, 4, 3, 1, 2, 3, 4, 5, 5, 6, 3, 4, 5, 5, 5, 6, 6, 7, 7, 8])
66+
school.advance()
67+
expect(school.state).to.deep.equal([2, 3, 2, 0, 1, 2, 3, 4, 4, 5, 2, 3, 4, 4, 4, 5, 5, 6, 6, 7])
68+
school.advance()
69+
expect(school.state).to.deep.equal([1, 2, 1, 6, 0, 1, 2, 3, 3, 4, 1, 2, 3, 3, 3, 4, 4, 5, 5, 6, 8])
70+
school.advance()
71+
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])
72+
school.advance()
73+
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+
})
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)
138+
})
139+
})
140+
})
141+
})

2021/day-06/index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// eslint-disable-next-line no-unused-vars
2+
const console = require('../helpers')
3+
require('./solution')

2021/day-06/input.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1,1,3,5,1,3,2,1,5,3,1,4,4,4,1,1,1,3,1,4,3,1,2,2,2,4,1,1,5,5,4,3,1,1,1,1,1,1,3,4,1,2,2,5,1,3,5,1,3,2,5,2,2,4,1,1,1,4,3,3,3,1,1,1,1,3,1,3,3,4,4,1,1,5,4,2,2,5,4,5,2,5,1,4,2,1,5,5,5,4,3,1,1,4,1,1,3,1,3,4,1,1,2,4,2,1,1,2,3,1,1,1,4,1,3,5,5,5,5,1,2,2,1,3,1,2,5,1,4,4,5,5,4,1,1,3,3,1,5,1,1,4,1,3,3,2,4,2,4,1,5,5,1,2,5,1,5,4,3,1,1,1,5,4,1,1,4,1,2,3,1,3,5,1,1,1,2,4,5,5,5,4,1,4,1,4,1,1,1,1,1,5,2,1,1,1,1,2,3,1,4,5,5,2,4,1,5,1,3,1,4,1,1,1,4,2,3,2,3,1,5,2,1,1,4,2,1,1,5,1,4,1,1,5,5,4,3,5,1,4,3,4,4,5,1,1,1,2,1,1,2,1,1,3,2,4,5,3,5,1,2,2,2,5,1,2,5,3,5,1,1,4,5,2,1,4,1,5,2,1,1,2,5,4,1,3,5,3,1,1,3,1,4,4,2,2,4,3,1,1

2021/day-06/solution.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
const fs = require('fs')
2+
const path = require('path')
3+
const filePath = path.join(__dirname, 'input.txt')
4+
const { parseData } = require('../../2018/inputParser')
5+
const { school, efficientSchool } = require('./fish')
6+
7+
fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => {
8+
if (err) throw err
9+
10+
initData = parseData(initData.trim())
11+
12+
const resetInput = () => {
13+
// Deep copy to ensure we aren't mutating the original data
14+
return JSON.parse(JSON.stringify(initData))
15+
}
16+
17+
const part1 = () => {
18+
const data = resetInput()
19+
school.state = data
20+
// Advance the designated time
21+
for (let x = 0; x < 80; x++) {
22+
school.advance()
23+
}
24+
// Count how many fish we have
25+
return school.state.length
26+
}
27+
28+
const part2 = () => {
29+
const data = resetInput()
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)
38+
}
39+
const answers = []
40+
answers.push(part1())
41+
answers.push(part2())
42+
43+
answers.forEach((ans, idx) => {
44+
console.info(`-- Part ${idx + 1} --`)
45+
console.info(`Answer: ${ans}`)
46+
})
47+
})

index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
require('./2021/day-05/solution')
1+
require('./2021/day-06/solution')

0 commit comments

Comments
 (0)
0