diff --git a/src/App.svelte b/src/App.svelte index 9efb012..92e101d 100755 --- a/src/App.svelte +++ b/src/App.svelte @@ -5,10 +5,12 @@ import GameOverModal from "./GameOverModal.svelte"; import { DIRECTION_VECTORS, + DIRECTION_NAMES, getNewApplePosition, getNewDirectionFromEventKey, getNextSnake, - is180Turn, + isStraightOr180Turn, + getNextHeadDirectionAndQueue, isEqual, isInsideBoard, isSnakeEatingItself, @@ -34,6 +36,7 @@ let score; let snake; let willGrow; + let headDirectionQueue; function resetGame() { const initialSnake = [ @@ -43,16 +46,23 @@ ]; apple = getNewApplePosition(BOARD_DIMENSIONS, initialSnake); gameState = GAME_STATES.START_SCREEN; - headDirection = "SOUTH"; + headDirection = DIRECTION_NAMES.SOUTH; score = 0; snake = initialSnake; willGrow = false; + headDirectionQueue = []; } resetGame(); // Snake logic function moveSnake() { + const [nextQueue, nextDirection] = getNextHeadDirectionAndQueue( + headDirectionQueue, + headDirection + ); + headDirectionQueue = nextQueue; + headDirection = nextDirection; snake = getNextSnake(snake, DIRECTION_VECTORS[headDirection], willGrow); willGrow = false; } @@ -95,10 +105,7 @@ if (!keyDirection) { return; } - - if (!is180Turn(snake, keyDirection)) { - headDirection = keyDirection; - } + headDirectionQueue = [...headDirectionQueue, keyDirection]; } } diff --git a/src/utils.js b/src/utils.js index f75c52f..d1de527 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,8 +1,20 @@ +export const DIRECTION_NAMES = Object.freeze({ + NORTH: "NORTH", + EAST: "EAST", + SOUTH: "SOUTH", + WEST: "WEST", +}); + +const OPPOSITE_DIRECTIONS = [ + [DIRECTION_NAMES.NORTH, DIRECTION_NAMES.SOUTH], + [DIRECTION_NAMES.EAST, DIRECTION_NAMES.WEST], +]; + export const DIRECTION_VECTORS = Object.freeze({ - NORTH: { x: 0, y: -1 }, - SOUTH: { x: 0, y: 1 }, - EAST: { x: 1, y: 0 }, - WEST: { x: -1, y: 0 }, + [DIRECTION_NAMES.NORTH]: { x: 0, y: -1 }, + [DIRECTION_NAMES.SOUTH]: { x: 0, y: 1 }, + [DIRECTION_NAMES.EAST]: { x: 1, y: 0 }, + [DIRECTION_NAMES.WEST]: { x: -1, y: 0 }, }); export function add(coordinateA, coordinateB) { @@ -48,14 +60,12 @@ export function isSnakeEatingItself(snake) { return snake.slice(1).some((snakeSpace) => isEqual(snakeSpace, headPosition)); } -export function is180Turn(snake, newDirectionFromEventKey) { - const head = snake[0]; - const neck = snake[1]; - const headWouldEatNeck = isEqual( - add(head, DIRECTION_VECTORS[newDirectionFromEventKey]), - neck +export function isStraightOr180Turn(currentDirection, nextDirection) { + return OPPOSITE_DIRECTIONS.some( + (directionAndOpposite) => + directionAndOpposite.includes(currentDirection) && + directionAndOpposite.includes(nextDirection) ); - return headWouldEatNeck; } export function getNewDirectionFromEventKey(key) { @@ -64,19 +74,32 @@ export function getNewDirectionFromEventKey(key) { case "ArrowUp": case "w": case ",": - return "NORTH"; + return DIRECTION_NAMES.NORTH; case "ArrowDown": case "s": case "o": - return "SOUTH"; + return DIRECTION_NAMES.SOUTH; case "ArrowLeft": case "a": - return "WEST"; + return DIRECTION_NAMES.WEST; case "ArrowRight": case "d": case "e": - return "EAST"; + return DIRECTION_NAMES.EAST; default: return null; } } + +export function getNextHeadDirectionAndQueue(queue, currentDirection) { + const foundIndex = queue.findIndex( + (direction) => !isStraightOr180Turn(currentDirection, direction) + ); + + const noNextDirectionFound = foundIndex === -1; + if (noNextDirectionFound) { + return [[], currentDirection]; + } else { + return [queue.slice(foundIndex + 1), queue[foundIndex]]; + } +}