Portfolio
Projekt: Piškvorky

Projekt: Piškvorky

Leden 2026

Zatímco v projektu Knihovna jsem se učil používat třídy a konstruktory, projekt Piškvorky měl jiný cíl: naučit se organizovat kód tak, aby neznečišťoval globální prostor. Hlavním tématem byly Factory Functions a Module Pattern.

Co projekt dělá

Klasická hra pro dva hráče v prohlížeči:

  • Hráči (X a O) se střídají v tazích klikáním do mřížky 3x3.
  • Hra automaticky detekuje vítězství (řádek, sloupec, diagonála) nebo remízu.
  • Zobrazuje, kdo je na řadě.
  • Umožňuje restartovat hru bez obnovení stránky.
  • Možnost zadat jména hráčů.

Změna myšlení: Moduly vs. Továrny

Nejtěžší částí nebylo naprogramovat logiku hry, ale správně ji rozdělit. Použil jsem dva hlavní koncepty:

  1. Module Pattern (IIFE): Pro věci, které ve hře existují jen jednou (herní deska, ovládání displeje).
  2. Factory Function: Pro věci, kterých může být více (hráči).

Herní deska (Gameboard)

Deska je jen jedna, takže jsem použil Modul. Pole board je schované uvnitř funkce a není přístupné přímo z konzole (zapouzdření):

const Gameboard = (() => {
	let board = ["", "", "", "", "", "", "", "", ""];

	const getBoard = () => board;

	const setMark = (index, mark) => {
		if (board[index] === "") {
			board[index] = mark;
			return true;
		}
		return false;
	};

	const reset = () => {
		board = board.map(() => "");
	};

	return { getBoard, setMark, reset };
})();

Hráči (Players)

Hráči jsou dva, takže potřebuji továrnu na jejich výrobu:

const Player = (name, mark) => {
	return { name, mark };
};

const player1 = Player("Marek", "X");
const player2 = Player("PC", "O");

Logika hry a kontrola výhry

Řízení hry (GameController) je také modul. Drží informaci o tom, kdo je na řadě, a po každém tahu kontroluje výhru.

Výherní kombinace jsem uložil jako pole indexů:

const winningCombinations = [
	[0, 1, 2],
	[3, 4, 5],
	[6, 7, 8], // Řádky
	[0, 3, 6],
	[1, 4, 7],
	[2, 5, 8], // Sloupce
	[0, 4, 8],
	[2, 4, 6], // Diagonály
];

function checkWin(board) {
	return winningCombinations.some((combination) => {
		return combination.every((index) => {
			return board[index] === currentPlayer.mark;
		});
	});
}

Použití metod some() a every() udělá kontrolu mnohem elegantnější než hromada if podmínek.

Propojení s HTML (DOM)

Zde jsem se snažil striktně oddělit logiku od vykreslování. Modul DisplayController se stará pouze o DOM.

  • Poslouchá kliknutí na buňky.
  • Získá index kliknuté buňky (e.target.dataset.index).
  • Pošle tento index do GameController.
  • Pokud je tah platný, GameController aktualizuje data a řekne DisplayController, ať se překreslí.

GitHub: projekt piškvorky