Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(book/queue): add solution for queue question
- Loading branch information
1 parent
04aa9db
commit 9a88766
Showing
6 changed files
with
227 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
const { Queue } = require('../../src/index'); | ||
|
||
// tag::description[] | ||
/** | ||
* The snake game stars with a snake of length 1 at postion 0,0. | ||
* Only one food position is shown at a time. Once it's eaten the next one shows up. | ||
* The snake can move in four directions up, down, left and right. | ||
* If the snake go out of the boundaries (width x height) the game is over. | ||
* If the snake hit itself the game is over. | ||
* When the game is over, the `move` method returns -1 otherwise, return the current score. | ||
* | ||
* @example | ||
* const snakeGame = new SnakeGame(3, 2, [[1, 2], [0, 1]]); | ||
* snakeGame.move('R'); // 0 | ||
* snakeGame.move('D'); // 0 | ||
* snakeGame.move('R'); // 0 | ||
* snakeGame.move('U'); // 1 (ate the food1) | ||
* snakeGame.move('L'); // 2 (ate the food2) | ||
* snakeGame.move('U'); // -1 (hit the upper wall) | ||
*/ | ||
class SnakeGame { | ||
// end::description[] | ||
// tag::solution[] | ||
|
||
// end::solution[] | ||
// tag::description[] | ||
/** | ||
* Initialize game with grid's dimension and food order. | ||
* @param {number} width - The screen width (grid's columns) | ||
* @param {number} height - Screen height (grid's rows) | ||
* @param {number[]} food - Food locations. | ||
*/ | ||
constructor(width, height, food) { | ||
// end::description[] | ||
// tag::solution[] | ||
this.width = width; | ||
this.height = height; | ||
this.food = new Queue(food); | ||
this.snake = new Queue([[0, 0]]); | ||
this.tail = new Set([[0, 0]]); | ||
this.dirs = { | ||
U: [-1, 0], D: [1, 0], R: [0, 1], L: [0, -1], | ||
}; | ||
// end::solution[] | ||
// tag::description[] | ||
} | ||
// end::description[] | ||
|
||
// tag::description[] | ||
/** | ||
* Move snake 1 position into the given direction. | ||
* It returns the score or game over (-1) if the snake go out of bound or hit itself. | ||
* @param {string} direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down. | ||
* @returns {number} - The current score (snake.length - 1). | ||
*/ | ||
move(direction) { | ||
// end::description[] | ||
// tag::solution[] | ||
let [r, c] = this.snake.back(); // head of the snake | ||
[r, c] = [r + this.dirs[direction][0], c + this.dirs[direction][1]]; | ||
|
||
// check wall collision | ||
if (r < 0 || c < 0 || r >= this.height || c >= this.width) return -1; | ||
|
||
const [fr, fc] = this.food.front() || []; // peek | ||
if (r === fr && c === fc) { | ||
this.food.dequeue(); // remove eaten food. | ||
} else { | ||
this.snake.dequeue(); // remove snake's if not food was eaten | ||
this.tail.delete(this.tail.keys().next().value); | ||
} | ||
|
||
// check collision with snake's tail | ||
if (this.tail.has(`${r},${c}`)) return -1; // O(1) | ||
|
||
this.snake.enqueue([r, c]); // add new position | ||
this.tail.add(`${r},${c}`); | ||
|
||
return this.snake.size - 1; // return score (length of the snake - 1) | ||
// end::solution[] | ||
// tag::description[] | ||
} | ||
} | ||
// end::description[] | ||
|
||
module.exports = { SnakeGame }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
const { SnakeGame } = require('./design-snake-game'); | ||
|
||
describe('Queue: Design Snake Game', () => { | ||
it('should game over when hits wall', () => { | ||
const snakeGame = new SnakeGame(4, 2, [[1, 2], [0, 1]]); | ||
expect(snakeGame.move('R')).toEqual(0); // 0 | ||
expect(snakeGame.move('D')).toEqual(0); // 0 | ||
expect(snakeGame.move('R')).toEqual(1); // 1 (ate food1) | ||
expect(snakeGame.move('U')).toEqual(1); // 1 | ||
expect(snakeGame.move('L')).toEqual(2); // 2 (ate food2) | ||
expect(snakeGame.move('U')).toEqual(-1); // -1 (hit wall) | ||
}); | ||
|
||
it('should circle around without eating itself', () => { | ||
const snakeGame = new SnakeGame(2, 2, [[0, 1], [1, 1], [1, 0]]); | ||
expect(snakeGame.move('R')).toEqual(1); | ||
expect(snakeGame.move('D')).toEqual(2); | ||
expect(snakeGame.move('L')).toEqual(3); | ||
expect(snakeGame.move('U')).toEqual(3); | ||
expect(snakeGame.move('R')).toEqual(3); | ||
}); | ||
|
||
it('should game over when hit itself', () => { | ||
const snakeGame = new SnakeGame(3, 2, [[0, 1], [0, 2], [1, 2], [1, 1]]); | ||
expect(snakeGame.move('R')).toEqual(1); | ||
expect(snakeGame.move('R')).toEqual(2); | ||
expect(snakeGame.move('D')).toEqual(3); | ||
expect(snakeGame.move('L')).toEqual(4); | ||
expect(snakeGame.move('U')).toEqual(-1); | ||
}); | ||
}); |