From d039451659700244d22a34a08ea1f30e0d3df04b Mon Sep 17 00:00:00 2001 From: Markus Tacker Date: Sat, 15 Dec 2018 12:53:33 +0100 Subject: [PATCH] day 9, part 2 --- day9.js | 48 ++++++++++++++++++++++++++++++++---------------- day9.spec.js | 37 +++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 34 deletions(-) diff --git a/day9.js b/day9.js index 25aa7bd..e47b751 100644 --- a/day9.js +++ b/day9.js @@ -1,6 +1,5 @@ class Circle { constructor (numPlayers) { - this.marbles = [] this.numPlayers = numPlayers this.scores = {} for (let i = 0; i < numPlayers; i++) { @@ -10,35 +9,52 @@ class Circle { placeMarble () { if (this.currentMarble === undefined) { - this.currentMarble = 0 + const marble = {n: 0} + marble.next = marble + marble.prev = marble + this.currentMarble = marble + this.firstMarble = marble this.placements = 0 - this.marbles.push(this.currentMarble) } else { - const marbleToBePlaced = ++this.placements + const marbleToBePlacedValue = ++this.placements const currentPlayer = this.placements % this.numPlayers - if (marbleToBePlaced % 23 === 0) { + if (marbleToBePlacedValue % 23 === 0) { // However, if the marble that is about to be placed has a number which is a multiple of 23, something entirely different happens: // First, the current player keeps the marble they would have placed, adding it to their score. - this.scores[currentPlayer] += marbleToBePlaced + this.scores[currentPlayer] += marbleToBePlacedValue // In addition, the marble 7 marbles counter-clockwise from the current marble is removed from the circle - let idx = (this.marbles.indexOf(this.currentMarble) - 7) % this.marbles.length - // Correct negative offset - if (idx < 0) { - idx = this.marbles.length + idx + let marbleToRemove = this.currentMarble + for (let i = 0; i < 7; i++) { + marbleToRemove = marbleToRemove.prev } + marbleToRemove.prev.next = marbleToRemove.next // The marble located immediately clockwise of the marble that was removed becomes the new current marble. - this.currentMarble = this.marbles[(idx + 1) % this.marbles.length] + this.currentMarble = marbleToRemove.next // and also added to the current player's score. - this.scores[currentPlayer] += this.marbles[idx] - this.marbles.splice(idx, 1) + this.scores[currentPlayer] += marbleToRemove.n } else { - const idx = (this.marbles.indexOf(this.currentMarble) + 1) % this.marbles.length - this.marbles.splice(idx + 1, 0, marbleToBePlaced) - this.currentMarble = marbleToBePlaced + const marble = { + n: marbleToBePlacedValue, + prev: this.currentMarble.next, + next: this.currentMarble.next.next + } + this.currentMarble.next.next = marble + this.currentMarble.next.next.next.prev = marble + this.currentMarble = marble } } } + marbles () { + const marbles = [] + let marble = this.firstMarble + do { + marbles.push(marble.n) + marble = marble.next + } while (marble !== this.firstMarble) + return marbles + } + winningScore () { return Object.keys(this.scores).reduce((max, player) => this.scores[player] > max ? this.scores[player] : max, 0) } diff --git a/day9.spec.js b/day9.spec.js index bbafe26..3f1542d 100644 --- a/day9.spec.js +++ b/day9.spec.js @@ -9,41 +9,41 @@ describe('marble mania', () => { it('should calculate the winning score', () => { const c = new Circle(5) c.placeMarble() - expect(c.currentMarble).toEqual(0) - expect(c.marbles).toEqual([0]) + expect(c.currentMarble.n).toEqual(0) + expect(c.marbles()).toEqual([0]) c.placeMarble() - expect(c.currentMarble).toEqual(1) - expect(c.marbles).toEqual([0, 1]) + expect(c.currentMarble.n).toEqual(1) + expect(c.marbles()).toEqual([0, 1]) c.placeMarble() - expect(c.currentMarble).toEqual(2) - expect(c.marbles).toEqual([0, 2, 1]) + expect(c.currentMarble.n).toEqual(2) + expect(c.marbles()).toEqual([0, 2, 1]) c.placeMarble() - expect(c.currentMarble).toEqual(3) - expect(c.marbles).toEqual([0, 2, 1, 3]) + expect(c.currentMarble.n).toEqual(3) + expect(c.marbles()).toEqual([0, 2, 1, 3]) c.placeMarble() - expect(c.currentMarble).toEqual(4) - expect(c.marbles).toEqual([0, 4, 2, 1, 3]) + expect(c.currentMarble.n).toEqual(4) + expect(c.marbles()).toEqual([0, 4, 2, 1, 3]) for (let i = 0; i < 18; i++) { c.placeMarble() } - expect(c.currentMarble).toEqual(22) - expect(c.marbles).toEqual([ + expect(c.currentMarble.n).toEqual(22) + expect(c.marbles()).toEqual([ 0, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 1, 12, 6, 13, 3, 14, 7, 15 ]) // Rule 23 c.placeMarble() - expect(c.currentMarble).toEqual(19) - expect(c.marbles).toEqual([ + expect(c.currentMarble.n).toEqual(19) + expect(c.marbles()).toEqual([ 0, 16, 8, 17, 4, 18, 19, 2, 20, 10, 21, 5, 22, 11, 1, 12, 6, 13, 3, 14, 7, 15 ]) c.placeMarble() - expect(c.currentMarble).toEqual(24) - expect(c.marbles).toEqual([ + expect(c.currentMarble.n).toEqual(24) + expect(c.marbles()).toEqual([ 0, 16, 8, 17, 4, 18, 19, 2, 24, 20, 10, 21, 5, 22, 11, 1, 12, 6, 13, 3, 14, 7, 15 ]) c.placeMarble() - expect(c.currentMarble).toEqual(25) - expect(c.marbles).toEqual([ + expect(c.currentMarble.n).toEqual(25) + expect(c.marbles()).toEqual([ 0, 16, 8, 17, 4, 18, 19, 2, 24, 20, 25, 10, 21, 5, 22, 11, 1, 12, 6, 13, 3, 14, 7, 15 ]) expect(c.winningScore()).toEqual(32) @@ -57,5 +57,6 @@ describe('marble mania', () => { }) it('should calculate the puzzle', () => { expect(getWinningScore(413, 71082)).toEqual(416424) + expect(getWinningScore(413, 7108200)).toEqual(3498287922) }) })