in snake-dqn/snake_game.js [122:187]
step(action) {
const [headY, headX] = this.snakeSquares_[0];
// Calculate the coordinates of the new head and check whether it has
// gone off the board, in which case the game will end.
let done;
let newHeadY;
let newHeadX;
this.updateDirection_(action);
if (this.snakeDirection_ === 'l') {
newHeadY = headY;
newHeadX = headX - 1;
done = newHeadX < 0;
} else if (this.snakeDirection_ === 'u') {
newHeadY = headY - 1;
newHeadX = headX;
done = newHeadY < 0
} else if (this.snakeDirection_ === 'r') {
newHeadY = headY;
newHeadX = headX + 1;
done = newHeadX >= this.width_;
} else if (this.snakeDirection_ === 'd') {
newHeadY = headY + 1;
newHeadX = headX;
done = newHeadY >= this.height_;
}
// Check if the head goes over the snake's body, in which case the
// game will end.
for (let i = 1; i < this.snakeSquares_.length; ++i) {
if (this.snakeSquares_[i][0] === newHeadY &&
this.snakeSquares_[i][1] === newHeadX) {
done = true;
}
}
let fruitEaten = false;
if (done) {
return {reward: DEATH_REWARD, done, fruitEaten};
}
// Update the position of the snake.
this.snakeSquares_.unshift([newHeadY, newHeadX]);
// Check if a fruit is eaten.
let reward = NO_FRUIT_REWARD;
for (let i = 0; i < this.fruitSquares_.length; ++i) {
const fruitYX = this.fruitSquares_[i];
if (fruitYX[0] === newHeadY && fruitYX[1] === newHeadX) {
reward = FRUIT_REWARD;
fruitEaten = true;
this.fruitSquares_.splice(i, 1);
this.makeFruits_();
break;
}
}
if (!fruitEaten) {
// Pop the tail off if and only if the snake didn't eat a fruit in this
// step.
this.snakeSquares_.pop();
}
const state = this.getState();
return {reward, state, done, fruitEaten};
}