Files
Luncher/server/src/tests/snakeGame.test.ts
T
batmanisko 6cb1214f08
CI / Generate TypeScript types (push) Canceled after 7s
CI / Server unit tests (push) Canceled after 0s
CI / Build server (push) Canceled after 0s
CI / Build client (push) Canceled after 0s
CI / Playwright E2E tests (push) Canceled after 0s
CI / Build and push Docker image (push) Canceled after 0s
CI / Notify (push) Canceled after 0s
feat: skryté multiplayerové minihry přes websocket
Minihry se otevírají trojklikem na logo a napsáním kódu hry
("help" vypíše seznam do konzole prohlížeče):
- reakce: reakční hra, 3 kola, pořadí podle součtu časů
- snake: had pro více hráčů, simulaci drží server
- tetris: battle Tetris s odpadními řádky a lokálním tréninkem
- pong: Pong 1v1, ovládání myší i klávesami, bot se 4 obtížnostmi
- kresleni: kreslení a hádání jídel z dnešních menu

Ikony her se řídí zvoleným vzhledem. Stav her je v paměti serveru,
předpokládá se jedna replika.
2026-10-12 14:25:45 +02:00

103 lines
4.0 KiB
TypeScript

import { SnakeGame, SnakeState, TICK_MS, COUNTDOWN_SECONDS, WIDTH, HEIGHT } from '../snakeGame';
import { GameError } from '../minigames';
import { fakeClock } from './helpers/fakeClock';
/** Náhoda vracející zadané hodnoty a pak nuly (jídlo pak padá do rohu [0,0]). */
const sequence = (...values: number[]) => () => values.length ? values.shift()! : 0;
/** Hodnoty náhody, které umístí jídlo na danou buňku. */
const foodAt = (x: number, y: number) => [x / WIDTH, y / HEIGHT];
function setup(random?: () => number) {
const clock = fakeClock(random);
const states: SnakeState[] = [];
const game = new SnakeGame(s => states.push(s), s => states.push(s), 1, clock);
const last = () => states[states.length - 1];
const player = (login: string) => last().players.find(p => p.login === login)!;
const startGame = (...logins: string[]) => {
logins.forEach(l => game.join(l));
game.start(logins[0]);
clock.advance(COUNTDOWN_SECONDS * 1000);
};
const ticks = (n: number) => clock.advance(n * TICK_MS);
return { game, clock, last, player, startGame, ticks };
}
describe('had', () => {
test('po odpočtu začne hra a had se posouvá o políčko za tick', () => {
const ctx = setup();
ctx.startGame('alice');
expect(ctx.last().phase).toBe('playing');
expect(ctx.player('alice').body).toEqual([[5, 10], [4, 10], [3, 10]]);
ctx.ticks(2);
expect(ctx.player('alice').body).toEqual([[7, 10], [6, 10], [5, 10]]);
});
test('zatáčí podle směru a obrat o 180° ignoruje', () => {
const ctx = setup();
ctx.startGame('alice');
ctx.game.turn('alice', 'left'); // obrat — ignoruje se
ctx.ticks(1);
expect(ctx.player('alice').body[0]).toEqual([6, 10]);
ctx.game.turn('alice', 'up');
ctx.ticks(1);
expect(ctx.player('alice').body[0]).toEqual([6, 9]);
});
test('nesmyslný směr se ignoruje', () => {
const ctx = setup();
ctx.startGame('alice');
ctx.game.turn('alice', 'diagonal');
ctx.ticks(1);
expect(ctx.player('alice').body[0]).toEqual([6, 10]);
});
test('sněděné jídlo prodlouží hada a přidá bod', () => {
const ctx = setup(sequence(...foodAt(7, 10)));
ctx.startGame('alice');
expect(ctx.last().food).toEqual([[7, 10]]);
ctx.ticks(2);
expect(ctx.player('alice').score).toBe(1);
expect(ctx.player('alice').body).toHaveLength(4);
expect(ctx.last().food).not.toContainEqual([7, 10]);
});
test('náraz do zdi ukončí sólo hru', () => {
const ctx = setup();
ctx.startGame('alice');
ctx.ticks(WIDTH);
expect(ctx.last().phase).toBe('finished');
expect(ctx.player('alice')).toMatchObject({ alive: false, place: 1 });
});
test('ve hře více hráčů vyhrává poslední přeživší', () => {
const ctx = setup();
ctx.startGame('alice', 'bob');
// alice startuje v řádku 6, nahoru do zdi dorazí v 7. ticku
ctx.game.turn('alice', 'up');
ctx.ticks(7);
expect(ctx.last().phase).toBe('finished');
expect(ctx.player('bob')).toMatchObject({ alive: true, place: 1 });
expect(ctx.player('alice')).toMatchObject({ alive: false, place: 2 });
});
test('čelní srážka zabije oba hady', () => {
const ctx = setup();
ctx.startGame('alice', 'bob');
// alice (5,6)→ doprava, bob (26,13)← doleva; po 7 tickách alice zatočí dolů
// a po dalších 7 se obě hlavy potkají na (12,13)
ctx.ticks(7);
ctx.game.turn('alice', 'down');
ctx.ticks(7);
const state = ctx.last();
expect(state.phase).toBe('finished');
expect(state.players.every(p => !p.alive)).toBe(true);
});
test('do běžící hry se nelze připojit', () => {
const ctx = setup();
ctx.startGame('alice');
expect(() => ctx.game.join('bob')).toThrow(GameError);
});
});