diff --git a/client/src/games/tetrisEngine.ts b/client/src/games/tetrisEngine.ts index 3ef4817..63bbdf0 100644 --- a/client/src/games/tetrisEngine.ts +++ b/client/src/games/tetrisEngine.ts @@ -10,23 +10,32 @@ export const GARBAGE = 8; type Point = [number, number]; -/** Kostky I, O, T, S, Z, J, L ve výchozí rotaci a velikost jejich čtverce pro rotaci. */ -const SHAPES: { cells: Point[], box: number }[] = [ - { cells: [[0, 1], [1, 1], [2, 1], [3, 1]], box: 4 }, - { cells: [[0, 0], [1, 0], [0, 1], [1, 1]], box: 2 }, - { cells: [[1, 0], [0, 1], [1, 1], [2, 1]], box: 3 }, - { cells: [[1, 0], [2, 0], [0, 1], [1, 1]], box: 3 }, - { cells: [[0, 0], [1, 0], [1, 1], [2, 1]], box: 3 }, - { cells: [[0, 0], [0, 1], [1, 1], [2, 1]], box: 3 }, - { cells: [[2, 0], [0, 1], [1, 1], [2, 1]], box: 3 }, +/** + * Kostky I, O, T, S, Z, J, L ve výchozí rotaci, velikost jejich čtverce pro rotaci + * a počet různých poloh (O jedna; I, S, Z jen dvě, aby se při otáčení neposouvaly). + */ +const SHAPES: { cells: Point[], box: number, states: 1 | 2 | 4 }[] = [ + { cells: [[0, 1], [1, 1], [2, 1], [3, 1]], box: 4, states: 2 }, + { cells: [[0, 0], [1, 0], [0, 1], [1, 1]], box: 2, states: 1 }, + { cells: [[1, 0], [0, 1], [1, 1], [2, 1]], box: 3, states: 4 }, + { cells: [[1, 0], [2, 0], [0, 1], [1, 1]], box: 3, states: 2 }, + { cells: [[0, 0], [1, 0], [1, 1], [2, 1]], box: 3, states: 2 }, + { cells: [[0, 0], [0, 1], [1, 1], [2, 1]], box: 3, states: 4 }, + { cells: [[2, 0], [0, 1], [1, 1], [2, 1]], box: 3, states: 4 }, ]; -/** Předpočítané rotace (po směru hodinových ručiček) pro každou kostku. */ -const ROTATIONS: Point[][][] = SHAPES.map(({ cells, box }) => { +/** + * Předpočítané rotace pro každou kostku; rot + 1 = otočení proti směru hodinových ručiček. + * T, J, L se otáčí kolem prostředního políčka. I, S, Z jen přepínají mezi vodorovnou + * a svislou polohou (svislá = vodorovná otočená po směru, stejná osa jako v klasickém Tetrisu). + */ +const ROTATIONS: Point[][][] = SHAPES.map(({ cells, box, states }) => { + const ccw = (pts: Point[]) => pts.map(([x, y]) => [y, box - 1 - x] as Point); + const cw = (pts: Point[]) => pts.map(([x, y]) => [box - 1 - y, x] as Point); + if (states === 1) return [cells, cells, cells, cells]; + if (states === 2) return [cells, cw(cells), cells, cw(cells)]; const result = [cells]; - for (let r = 1; r < 4; r++) { - result.push(result[r - 1].map(([x, y]) => [box - 1 - y, x] as Point)); - } + for (let r = 1; r < 4; r++) result.push(ccw(result[r - 1])); return result; }); @@ -164,7 +173,9 @@ export class TetrisSession { private spawn() { const type = this.nextType; this.nextType = this.draw(); - const piece: Piece = { type, rot: 0, x: type === 1 ? 4 : 3, y: type === 0 ? -1 : 0 }; + // Kostka se objeví celá nad deskou, aby ji šlo otočit dřív, než vjede do hrací plochy + const bottom = Math.max(...ROTATIONS[type][0].map(([, y]) => y)); + const piece: Piece = { type, rot: 0, x: type === 1 ? 4 : 3, y: -bottom - 1 }; if (!this.fits(piece)) { this.active = null; this.die(); diff --git a/server/changelogs/2026-10-20.json b/server/changelogs/2026-10-20.json new file mode 100644 index 0000000..892d27f --- /dev/null +++ b/server/changelogs/2026-10-20.json @@ -0,0 +1,4 @@ +[ + "Tetris: kostky se otáčí proti směru hodinových ručiček kolem svého středu, tyčka a S/Z kostky už jen přepínají mezi vodorovnou a svislou polohou", + "Tetris: nová kostka se objeví nad hrací plochou, takže ji jde otočit dřív, než do plochy vjede" +]