From 0fe44d68347aa583bd4ed39e1229a5ebf25c8d54 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Fri, 20 Jun 2025 15:53:49 +0200 Subject: [PATCH] feat: Implement tic-tac-toe game with cat cartoon background - Created a playable tic-tac-toe game supporting two players or AI mode. - Added a "Brno scrum workshop" banner and a "New Game" button. - Included a mode selector for two players or AI opponent. - Styled the interface with a cat cartoon image as the background. - Ensured responsive and visually appealing layout for all devices. --- game.js | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ index.html | 21 +++++++++++++ style.css | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 game.js create mode 100644 index.html create mode 100644 style.css diff --git a/game.js b/game.js new file mode 100644 index 0000000..484057e --- /dev/null +++ b/game.js @@ -0,0 +1,89 @@ +const boardElem = document.getElementById('board'); +const newGameBtn = document.getElementById('newGameBtn'); +const modeSelect = document.getElementById('modeSelect'); + +let board = Array(9).fill(null); +let currentPlayer = 'X'; +let gameActive = true; +let mode = '2p'; + +function renderBoard() { + boardElem.innerHTML = ''; + board.forEach((cell, idx) => { + const cellElem = document.createElement('div'); + cellElem.className = 'cell'; + cellElem.textContent = cell || ''; + cellElem.addEventListener('click', () => handleCellClick(idx)); + boardElem.appendChild(cellElem); + }); +} + +function handleCellClick(idx) { + if (!gameActive || board[idx]) return; + board[idx] = currentPlayer; + renderBoard(); + if (checkWin(currentPlayer)) { + setTimeout(() => alert(`${currentPlayer} wins!`), 100); + gameActive = false; + return; + } + if (board.every(cell => cell)) { + setTimeout(() => alert('Draw!'), 100); + gameActive = false; + return; + } + if (mode === 'ai' && currentPlayer === 'X') { + currentPlayer = 'O'; + setTimeout(aiMove, 400); + } else { + currentPlayer = currentPlayer === 'X' ? 'O' : 'X'; + } +} + +function aiMove() { + // Simple AI: pick random empty cell + const empty = board.map((cell, i) => cell ? null : i).filter(i => i !== null); + if (empty.length === 0) return; + const move = empty[Math.floor(Math.random() * empty.length)]; + board[move] = 'O'; + renderBoard(); + if (checkWin('O')) { + setTimeout(() => alert('O wins!'), 100); + gameActive = false; + return; + } + if (board.every(cell => cell)) { + setTimeout(() => alert('Draw!'), 100); + gameActive = false; + return; + } + currentPlayer = 'X'; +} + +function checkWin(player) { + const wins = [ + [0,1,2],[3,4,5],[6,7,8], // rows + [0,3,6],[1,4,7],[2,5,8], // cols + [0,4,8],[2,4,6] // diags + ]; + return wins.some(line => line.every(i => board[i] === player)); +} + +function newGame() { + board = Array(9).fill(null); + currentPlayer = 'X'; + gameActive = true; + renderBoard(); + if (mode === 'ai' && currentPlayer === 'O') { + setTimeout(aiMove, 400); + } +} + +newGameBtn.addEventListener('click', newGame); +modeSelect.addEventListener('change', e => { + mode = e.target.value; + newGame(); +}); + +// Initial render +renderBoard(); \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 0000000..ecc469a --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + + + + Tic-Tac-Toe - Brno Scrum Workshop + + + + +
+ + +
+
+ + + \ No newline at end of file diff --git a/style.css b/style.css new file mode 100644 index 0000000..f0f8679 --- /dev/null +++ b/style.css @@ -0,0 +1,80 @@ +body { + margin: 0; + padding: 0; + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: url('https://cdn.pixabay.com/photo/2017/01/06/19/15/cat-1958376_1280.png') no-repeat center center fixed; + background-size: cover; +} + +.banner { + background: rgba(255, 255, 255, 0.85); + text-align: center; + font-size: 2.2rem; + font-weight: bold; + padding: 1rem 0; + margin-bottom: 1.5rem; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); +} + +.controls { + display: flex; + justify-content: center; + gap: 1rem; + margin-bottom: 2rem; +} + +#newGameBtn, #modeSelect { + font-size: 1rem; + padding: 0.5rem 1rem; + border-radius: 5px; + border: 1px solid #888; + background: #fff; + cursor: pointer; +} + +.board { + display: grid; + grid-template-columns: repeat(3, 80px); + grid-template-rows: repeat(3, 80px); + gap: 10px; + justify-content: center; + margin: 0 auto; + background: rgba(255,255,255,0.7); + border-radius: 12px; + padding: 20px; + width: max-content; +} + +.cell { + width: 80px; + height: 80px; + background: #f9f9f9; + border: 2px solid #333; + display: flex; + align-items: center; + justify-content: center; + font-size: 2.5rem; + font-weight: bold; + cursor: pointer; + transition: background 0.2s; +} + +.cell:hover { + background: #e0e0e0; +} + +@media (max-width: 600px) { + .board { + grid-template-columns: repeat(3, 50px); + grid-template-rows: repeat(3, 50px); + padding: 10px; + } + .cell { + width: 50px; + height: 50px; + font-size: 1.5rem; + } + .banner { + font-size: 1.2rem; + } +} \ No newline at end of file