Snake6 is a version of the classic Snake game played on a hexagonal grid: every tile has six sides, so the snake can face six directions. It is built with Angular 22.
npm install
npm startnpm test # unit tests (Karma), then browser tests (Playwright)
npm run test:unit # unit tests only, re-running on every change
npm run e2e # browser tests only (Playwright, uses the installed Chrome)The Playwright tests in e2e start the app themselves, fix Math.random() so the game always begins with the same snake and fruit, and use Playwright's fake clock so the timer only ticks when a test runs it.
Click the game area to give it keyboard focus, then:
| Key | Effect |
|---|---|
| any arrow | Start the game (the snake stands still until then) |
| ← / → | Choose a left or right turn; press twice for a stronger turn |
| ↓ | Cancel the chosen turn |
| ↑ (hold) | Move twice as fast while held |
| Space | Pause / resume |
| Enter | After game over: start a new game (same as the "Opnieuw" button) |
The snake moves by itself, one tile per step. The head turns as soon as you press ← or →, so it always points where the next step goes. The game starts at one step per 500 ms; every point makes it 5% faster, down to 150 ms per step.
The field is a regular hexagon, made of regular hexagonal tiles, with 7 tiles from the middle to each edge. The snake never leaves it:
- On the edge you cannot turn towards the outside; a turn that would leave the board is skipped.
- If straight ahead would leave the board, the snake turns along the edge by itself, taking the mildest turn that stays on the board.
- The dark purple tiles are portals. When the head moves onto a portal, its next step lands on the light purple exit tile with the same number, on the opposite edge.
- Fruit: there is always one fruit on a random free tile. Eating it (moving the head onto it) makes a new fruit appear at once.
- Mice: when there has been no mouse for 20 steps, one appears on a free edge tile. A mouse moves every 2nd step: it flees when the head is within 3 tiles, otherwise it walks towards the fruit. Mice never walk through the snake or each other and do not use portals. A mouse that reaches the fruit eats it and gets fat; 4 steps later it splits into two mice (at most 6) and only then does a new fruit appear. A mouse that has not eaten for 30 steps starves. The snake can eat mice too.
- Digestion: eaten food shows as a bulge in the segment just behind the head and moves one segment towards the tail every 2 steps. When it reaches the tail the snake grows by one segment and you get the point. Several pieces can be digested at the same time.
- Collisions: moving the head into your own body is game over, except into a segment with food in it, which can be crossed. The head may enter the tail tile, because the tail moves away in the same step, unless the snake grows in that step.
-
Model (src/Snake.ts): positions use hex coordinates (
x6,y6) and arotationfrom 0 to 5 (steps of 60°). The snake is stored as a tail position plus the direction of each following segment. The change in direction between two segments (twist) decides which piece is drawn:0: straight piece (rechtdoor)±1: sharp bend (bocht1)±2: gentle bend (bocht2)- the head (
kop)
A negative twist is a left turn and is drawn mirrored.
moveForwardremoves a segment at the tail and adds one at the head;growonly adds one at the head. -
Drawing (src/app/game/game.component.html, src/app/snake/snake.component.html): the game is one SVG. The segment shapes are defined once and placed on each tile with the right rotation.
-
Board (src/Board.ts): which tiles are on the field, where the portals are, and which tile a step leads to. The snake model uses it to follow portals and to block or adjust turns at the edge.
-
Game rules (src/Game.ts): the state of one game (fruit, mice, food being digested, score and
ready/running/paused/over) andstep(), which moves the whole world one tick. It has no timer, keys or drawing, so it is unit-tested on its own (src/Game.spec.ts); the header comment lists the order of operations in a step. -
Game component (src/app/game/game.component.ts): handles the keys and calls
game.step()with asetTimeoutchain while the game runs, re-reading the interval on every tick. It draws the fruit, mice and bulges with thevrucht,muis,dikke-muisandbultshapes, and shows the score and the game-over overlay. -
Start (src/app/snake.service.ts): every game starts with a random snake of 7 segments near the middle of the board, placed completely on the board.
- The settings panel (src/app/snake6config), which is now only a placeholder button