From 8761287a617cda2c09dcb14b10e02e53a168dbbb Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 24 Dec 2018 13:54:42 -0800 Subject: [PATCH 1/4] test(2018 day-15): Stub in unit tests for the cave system --- 2018/day-15/caves.test.js | 81 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 2018/day-15/caves.test.js diff --git a/2018/day-15/caves.test.js b/2018/day-15/caves.test.js new file mode 100644 index 0000000..c90e5df --- /dev/null +++ b/2018/day-15/caves.test.js @@ -0,0 +1,81 @@ +/* eslint-env mocha */ +const expect = require('chai').expect +const { + Cave +} = require('./recipes') + +describe('--- Day 15: Beverage Bandits ---', () => { + describe('Part 1:', () => { + describe('new Cave()', () => { + it('initializes a cave with elves and goblins', () => { + const test = ` + ####### + #.G.E.# + #E.G.E# + #.G.E.# + ####### + ` + const cave = new Cave(test) + expect(cave.rounds).to.equal(0) + expect(cave.outcome).to.equal(null) + expect(cave.filter((unit) => unit.type === 'elves').length).to.equal(4) + expect(cave.filter((unit) => unit.type === 'goblins').length).to.equal(3) + expect(cave.filter((unit) => unit.type === 'elves')[0].location).to.deep.equal([5, 1]) + expect(cave.filter((unit) => unit.type === 'goblins')[3].location).to.deep.equal([2, 3]) + expect(cave.map[4][4]).to.equal('#') + expect(cave.map[3][4]).to.equal('.') + }) + describe('advance()', () => { + it('advances the cave combat cycle', () => { + + }) + }) + describe('findPath(origin, target)', () => { + it('determines a path from the origin to the target', () => { + + }) + it('returns null when the path is blocked by cave', () => { + + }) + it('returns null when the path is blocked by other units', () => { + + }) + }) + describe('display()', () => { + it('renders the current cave state', () => { + + }) + }) + }) + describe('new Unit()', () => { + it('initializes an elf or a goblin', () => { + const expected = { hp: 200, ap: 3, location: [3, 4] } + }) + describe('attack()', () => { + it('attacks the closest oponent', () => { + + }) + }) + describe('findClosestOponent()', () => { + it('finds the unit\'s closest oponent', () => { + + }) + }) + describe('move()', () => { + it('moves the unit towards the closest oponent', () => { + const test = ` + ####### + #.E...# + #.....# + #...G.# + #######` + const expected = [3, 1] + const cave = new Cave(test) + cave.units[0].move() + const actual = cave.units[0].location + expect(actual).to.deep.equal(expected) + }) + }) + }) + }) +}) From 9d9f40246052264612fd6f7b5e50eb2576c44704 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 24 Dec 2018 14:13:05 -0800 Subject: [PATCH 2/4] test(2018 day-15): setup unit tests --- 2018/day-15/caves.test.js | 58 +++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 17 deletions(-) diff --git a/2018/day-15/caves.test.js b/2018/day-15/caves.test.js index c90e5df..90a7e15 100644 --- a/2018/day-15/caves.test.js +++ b/2018/day-15/caves.test.js @@ -1,8 +1,9 @@ /* eslint-env mocha */ const expect = require('chai').expect const { - Cave -} = require('./recipes') + Cave, + Unit +} = require('./caves') describe('--- Day 15: Beverage Bandits ---', () => { describe('Part 1:', () => { @@ -18,51 +19,74 @@ describe('--- Day 15: Beverage Bandits ---', () => { const cave = new Cave(test) expect(cave.rounds).to.equal(0) expect(cave.outcome).to.equal(null) - expect(cave.filter((unit) => unit.type === 'elves').length).to.equal(4) - expect(cave.filter((unit) => unit.type === 'goblins').length).to.equal(3) - expect(cave.filter((unit) => unit.type === 'elves')[0].location).to.deep.equal([5, 1]) - expect(cave.filter((unit) => unit.type === 'goblins')[3].location).to.deep.equal([2, 3]) + expect(cave.map.length).to.equal(5) // 5 rows + expect(cave.map[4].length).to.equal(7) // 7 columns + expect(cave.units.filter((unit) => unit.type === 'elves').length).to.equal(4) + expect(cave.units.filter((unit) => unit.type === 'goblins').length).to.equal(3) + expect(cave.units.filter((unit) => unit.type === 'elves')[0].location).to.deep.equal([4, 1]) + expect(cave.units.filter((unit) => unit.type === 'goblins')[2].location).to.deep.equal([2, 3]) expect(cave.map[4][4]).to.equal('#') expect(cave.map[3][4]).to.equal('.') }) describe('advance()', () => { - it('advances the cave combat cycle', () => { + it.skip('advances the cave combat cycle', () => { }) }) describe('findPath(origin, target)', () => { - it('determines a path from the origin to the target', () => { + it.skip('determines a path from the origin to the target', () => { }) - it('returns null when the path is blocked by cave', () => { + it.skip('returns null when the path is blocked by cave', () => { }) - it('returns null when the path is blocked by other units', () => { + it.skip('returns null when the path is blocked by other units', () => { }) }) describe('display()', () => { - it('renders the current cave state', () => { - + it.skip('renders the current cave state', () => { + const test = ` + ####### + #.G.E.# + #E.G.E# + #.G.E.# + ####### + ` + const expected = test.split('\n').map((row) => row.trim()).join('\n').trim() + const actual = new Cave(test).display() + expect(actual).to.equal(expected) }) }) }) - describe('new Unit()', () => { + describe('new Unit(x, y, type)', () => { it('initializes an elf or a goblin', () => { - const expected = { hp: 200, ap: 3, location: [3, 4] } + const expected = { + ap: 3, + hp: 200, + location: [3, 4], + type: 'elves' + } + const actual = new Unit(3, 4, 'elves') + expect(actual.ap).to.equal(expected.ap) + expect(actual.hp).to.equal(expected.hp) + expect(actual.location).to.deep.equal(expected.location) + expect(actual.type).to.equal(expected.type) + expect(typeof actual.attack).to.equal('function') + expect(typeof actual.move).to.equal('function') }) describe('attack()', () => { - it('attacks the closest oponent', () => { + it.skip('attacks the closest oponent', () => { }) }) describe('findClosestOponent()', () => { - it('finds the unit\'s closest oponent', () => { + it.skip('finds the unit\'s closest oponent', () => { }) }) describe('move()', () => { - it('moves the unit towards the closest oponent', () => { + it.skip('moves the unit towards the closest oponent', () => { const test = ` ####### #.E...# From 4eb3c144db739a94c28781108e3079929ba0d81b Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 24 Dec 2018 14:13:37 -0800 Subject: [PATCH 3/4] feat(2018 day-15): structure solution for Part 1 --- 2018/day-15/solution.js | 19 +++++++++++++++++++ index.js | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 2018/day-15/solution.js diff --git a/2018/day-15/solution.js b/2018/day-15/solution.js new file mode 100644 index 0000000..40200b5 --- /dev/null +++ b/2018/day-15/solution.js @@ -0,0 +1,19 @@ +const { loadInput } = require('./helpers') +const { Cave } = require('./caves') + +const init = (data) => { + const cave = new Cave(data) + while (cave.outcome === null) { + cave.advance() + } + // Get total hitpoints of winning army X the number of completed rounds + const answer = cave.rounds * cave.units.filter((unit) => unit.type === cave.outcome).reduce((hp, unit) => hp + unit.hp, 0) + + const answer2 = '' + console.log(`-- Part 1 --`) + console.log(`Answer: ${answer}`) + console.log(`-- Part 2 --`) + console.log(`Answer: ${answer2}`) +} + +loadInput(init) diff --git a/index.js b/index.js index dcb17cf..6349b90 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -require('./2018/day-14/solution') +require('./2018/day-15/solution') From b5639c094d823b5a21922a7a6764cac16e65f182 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 24 Dec 2018 14:14:10 -0800 Subject: [PATCH 4/4] feat(2018 day-15): intializes cave system with elves and goblins --- 2018/day-15/caves.js | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 2018/day-15/caves.js diff --git a/2018/day-15/caves.js b/2018/day-15/caves.js new file mode 100644 index 0000000..9436c9c --- /dev/null +++ b/2018/day-15/caves.js @@ -0,0 +1,43 @@ +class Cave { + constructor (data) { + this.outcome = null + this.rounds = 0 + this.units = [] + this.setMap(data) + } + + /** + * Parses the map string and stores as an addressable object + * @param {String} data map + */ + setMap (data) { + this.map = data.trim().split('\n').map((row, idy) => { + return row.trim().split('').map((point, idx) => { + if (point === 'E' || point === 'G') { + const army = (point === 'E') ? 'elves' : 'goblins' + this.units.push(new Unit(idx, idy, army)) + } + return (point === '#') ? '#' : '.' + }) + }) + } +} + +class Unit { + constructor (x, y, type) { + this.ap = 3 + this.hp = 200 + this.location = [x, y] + this.type = type + } + move () { + } + attack () { + + } +} + +module.exports = { + Cave, + Unit +}