Skip to content

Commit d9d8489

Browse files
feat(2018 day-13): individual cart movement
1 parent dbec37c commit d9d8489

File tree

2 files changed

+241
-3
lines changed

2 files changed

+241
-3
lines changed

2018/day-13/tracks.js

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,77 @@ class Track {
33
this.layout = []
44
this.carts = []
55
this.cartDirections = ['^', '>', 'v', '<']
6+
this.trackTurns = ['\\', '/']
7+
this.trackTypes = this.trackTurns.concat(['-', '|', '+'])
8+
this.collision = false
69
this.frame = 0
710
this.setLayout(track)
811
}
912

13+
_isCollision (x, y) { return (this.carts.filter((c) => c.x === x && c.y === y).length > 1) }
14+
_isIntersection (s) { return s === '+' }
15+
_isTurn (s) { return this.trackTurns.indexOf(s) >= 0 }
16+
17+
/**
18+
* Determines the next direction for a cart rotating at an intersection
19+
* Order of rotations is left (counterclockwise), right (clockwise), straight
20+
* @private
21+
* @param {Object} cart the cart being turned
22+
* @returns {String} value of new direction
23+
*/
24+
_intersect (cart) {
25+
let r = 0
26+
if (typeof cart.lastIntersection === 'undefined') {
27+
r = -1
28+
}
29+
if (cart.lastIntersection === -1) {
30+
r = 1
31+
}
32+
33+
cart.lastIntersection = r
34+
return this.cartDirections[this._roationDirection(this.cartDirections.indexOf(cart.direction), r)]
35+
}
36+
37+
/**
38+
* Rotates the cart
39+
* @private
40+
* @param {String} s track segment the cart is now on
41+
* @param {String} a x||y axis of travel
42+
* @param {Number} d Index of absolute cart direction
43+
* @returns {String} value of new direction
44+
*/
45+
_rotate (s, a, d) {
46+
// Determine which way we're rotating
47+
let r = (
48+
(this.trackTurns.indexOf(s) === 1 && a === 'y') || // vertical turns clockwise
49+
(this.trackTurns.indexOf(s) === 0 && a === 'x') // horizontal turns clockwise
50+
// (this.trackTurns.indexOf(s) === 0 && a === 'x') // horizontal turns counter-clockwise
51+
// (this.trackTurns.indexOf(s) === 1 && a === 'y') // vertical turns counter-clockwise
52+
) ? 1 : -1
53+
console.log(`${s} for ${a} is turning ${r}`)
54+
// Find the value of the new direction
55+
return this.cartDirections[this._roationDirection(d, r)]
56+
}
57+
58+
/**
59+
* Determines the next clockwise or counter-clockwise direction
60+
* @private
61+
* @param {Number} d Index of current direction
62+
* @param {Number} r +1 for clockwise (turn right), -1 for counterclockwise (turn left)
63+
* @returns {Number} Index of new direction
64+
*/
65+
_roationDirection (d, r) {
66+
console.log(`rotating ${d}, ${r}`)
67+
if (d + r > this.cartDirections.length - 1) {
68+
return 0
69+
}
70+
if (d + r < 0) {
71+
return this.cartDirections.length - 1
72+
}
73+
console.log(`new direction is ${d + r}`)
74+
return d + r
75+
}
76+
1077
/**
1178
* Displays the current state of the track with the carts placed
1279
*/
@@ -61,6 +128,45 @@ class Track {
61128
return this.layout[y][x]
62129
}
63130

131+
/**
132+
* Moves the specified cart in the direction of travel, observing all rules
133+
* @param {Objc} cart from the list of carts
134+
*/
135+
moveCart (cart) {
136+
// Determine the direction of travel
137+
const d = this.cartDirections.indexOf(cart.direction) // Absolute direction
138+
const a = (d % 2 === 0) ? 'y' : 'x' // axis of travel
139+
const l = (d % 3 === 0) ? -1 : 1 // (+/-) distance of travel on the axis
140+
// move the cart
141+
cart[a] = cart[a] + l
142+
const s = this.layout[cart.y][cart.x] // Segment of track the cart is now on
143+
144+
// Make sure cart hasn't run off the rails
145+
if (this.trackTypes.indexOf(this.layout[cart.y][cart.x]) < 0) {
146+
return new Error(`cart ran off the track at ${cart.x}, ${cart.y}`)
147+
}
148+
// Check for collision
149+
if (this._isCollision(cart.x, cart.y)) {
150+
this.collision = { x: cart.x, y: cart.y }
151+
return new Error(`collision at ${cart.x}, ${cart.y}`) // Stop everything
152+
}
153+
// rotate the cart when entering a turn
154+
if (this._isTurn(s)) {
155+
console.log(`Cart direction was ${cart.direction}`)
156+
cart.direction = this._rotate(s, a, d)
157+
console.log(`Cart direction is ${cart.direction}`)
158+
return
159+
}
160+
// rotate (or not) the cart when entering an intersection
161+
if (this._isIntersection(s)) {
162+
cart.direction = this._intersect(cart)
163+
}
164+
}
165+
166+
/**
167+
* Stores the provided track
168+
* @param {String} track
169+
*/
64170
setLayout (track) {
65171
this.layout = track.split('\n')
66172
this.layout = this.layout.map((e) => { return e.split('') })

2018/day-13/tracks.test.js

Lines changed: 135 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const data = `/->-\\
99
| /-+--+-\\ |
1010
| | | | v |
1111
\\-+-/ \\-+--/
12-
\\------/ `.trim()
12+
\\------/ `
1313

1414
describe('--- Day 13: Mine Cart Madness ---', () => {
1515
describe('Part 1:', () => {
@@ -34,11 +34,143 @@ describe('--- Day 13: Mine Cart Madness ---', () => {
3434
})
3535
})
3636
describe('advance()', () => {
37-
it.skip('iterates the state of the track')
37+
it('moves forward all carts on the layout', () => {
38+
const test = `/---v
39+
| | /----\\
40+
| /-+--+-\\ |
41+
| | | | | |
42+
\\-+-/ \\-+>-/
43+
\\------/ `
44+
const expected = `/---\
45+
| v /----\\
46+
| /-+--+-\\ |
47+
| | | | | |
48+
\\-+-/ \\-+->/
49+
\\------/ `.trim()
50+
const track = new Track(test)
51+
track.moveCart()
52+
const actual = track.display()
53+
expect(actual).to.equal(expected)
54+
})
55+
})
56+
describe('moveCart(cart)', () => {
57+
it('moves an individual cart right', () => {
58+
const test = `->--`
59+
const track = new Track(test)
60+
const expected = `-->-`
61+
track.moveCart(track.carts[0])
62+
const actual = track.display()
63+
expect(actual).to.equal(expected)
64+
})
65+
it('moves an individual cart left', () => {
66+
const test = `--<-`
67+
const track = new Track(test)
68+
const expected = `-<--`
69+
track.moveCart(track.carts[0])
70+
const actual = track.display()
71+
expect(actual).to.equal(expected)
72+
})
73+
it('moves an individual cart down', () => {
74+
const test = `|\nv\n|\n|`
75+
const track = new Track(test)
76+
const expected = `|\n|\nv\n|`
77+
track.moveCart(track.carts[0])
78+
const actual = track.display()
79+
expect(actual).to.equal(expected)
80+
})
81+
it('moves an individual cart up', () => {
82+
const test = `|\n|\n^\n|`
83+
const track = new Track(test)
84+
const expected = `|\n^\n|\n|`
85+
track.moveCart(track.carts[0])
86+
const actual = track.display()
87+
expect(actual).to.equal(expected)
88+
})
89+
it('rotates a cart when it enters turns', () => {
90+
const tests = [
91+
`->-\\-`,
92+
`->-/-`,
93+
`-/-<-`,
94+
`-\\-<-`,
95+
`|\nv\n|\n\\\n|`,
96+
`|\nv\n|\n/\n|`,
97+
`|\n/\n|\n^\n|`,
98+
`|\n\\\n|\n^\n|`
99+
]
100+
const expected = [
101+
`---v-`,
102+
`---^-`,
103+
`-v---`,
104+
`-^---`,
105+
`|\n|\n|\n>\n|`,
106+
`|\n|\n|\n<\n|`,
107+
`|\n>\n|\n|\n|`,
108+
`|\n<\n|\n|\n|`
109+
]
110+
tests.forEach((test, idx) => {
111+
const track = new Track(test)
112+
track.moveCart(track.carts[0])
113+
track.moveCart(track.carts[0])
114+
const actual = track.display()
115+
expect(actual).to.equal(expected[idx])
116+
})
117+
})
118+
it('rotates a cart when it enters an intersection', () => {
119+
const test = `->-+-`
120+
const track = new Track(test)
121+
const expected = `---^-`
122+
track.moveCart(track.carts[0])
123+
track.moveCart(track.carts[0])
124+
const actual = track.display()
125+
expect(actual).to.equal(expected)
126+
})
127+
it('tracks the direction through multiple intersections following the sequential rotation rules: left, straight, right', () => {
128+
const test = `
129+
|
130+
-+-+--
131+
|
132+
->-+-`
133+
const track = new Track(test)
134+
const expected = `
135+
|
136+
-+-+->
137+
|
138+
---+-`.trim()
139+
for (let i = 0; i < 8; i++) {
140+
track.moveCart(track.carts[0])
141+
}
142+
const actual = track.display()
143+
expect(actual).to.equal(expected)
144+
})
145+
it('only moves the specified cart', () => {
146+
const test = `->--<-`
147+
const expected = `---><-`
148+
const track = new Track(test)
149+
track.moveCart(track.carts[0])
150+
track.moveCart(track.carts[0])
151+
const actual = track.display()
152+
expect(actual).to.equal(expected)
153+
})
154+
it('throws an error if the cart runs off the rails', () => {
155+
const test = `->- -`
156+
const track = new Track(test)
157+
track.moveCart(track.carts[0])
158+
expect(track.moveCart(track.carts[0])).to.be.an('error')
159+
})
160+
it('registers a collision', () => {
161+
const test = `->-<-`
162+
const expected = `---X-`
163+
const track = new Track(test)
164+
track.moveCart(track.carts[0])
165+
track.moveCart(track.carts[0])
166+
const actual = track.display()
167+
expect(actual).to.equal(expected)
168+
expect(track.collision).to.deep.equal({ x: 3, y: 0 })
169+
})
38170
})
39171
describe('display()', () => {
40172
it('renders the current track state', () => {
41-
const expected = data
173+
const expected = data.trim()
42174
const track = new Track(data)
43175
const actual = track.display()
44176
expect(actual).to.equal(expected)

0 commit comments

Comments
 (0)