Skip to content

Commit 53c46c0

Browse files
Merge pull request #122 from Arpitawork24/fix-tictactoe-game
Add Tic-Tac-Toe game with AI mode and improved UI
2 parents 1051a97 + 13ee9e7 commit 53c46c0

2 files changed

Lines changed: 185 additions & 0 deletions

File tree

web-app/css/styles.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,3 +1151,6 @@ body {
11511151
transform: none;
11521152
}
11531153
}
1154+
1155+
/* =========================
1156+
TIC TAC TOE

web-app/js/projects.js

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
function getProjectHTML(projectName) {
55
const projects = {
6+
'tic-tac-toe': getTicTacToeHTML(),
67
'rock-paper-scissor': getRockPaperScissorHTML(),
78
'dice-rolling': getDiceRollingHTML(),
89
'coin-flip': getCoinFlipHTML(),
@@ -34,6 +35,7 @@ function getProjectHTML(projectName) {
3435

3536
function initializeProject(projectName) {
3637
const initializers = {
38+
'tic-tac-toe': initTicTacToe,
3739
'rock-paper-scissor': initRockPaperScissor,
3840
'dice-rolling': initDiceRolling,
3941
'coin-flip': initCoinFlip,
@@ -297,6 +299,186 @@ function initRockPaperScissor() {
297299
}
298300
}
299301

302+
// ============================================
303+
// Tic Tac Toe
304+
// ============================================
305+
306+
function getTicTacToeHTML() {
307+
return `
308+
<div class="project-content">
309+
<h2>🧩 Tic-Tac-Toe</h2>
310+
<div class="ttt-mode-buttons">
311+
<button id="pvpMode" class="mode-btn active-mode">
312+
👥 2 Players
313+
</button>
314+
315+
<button id="aiMode" class="mode-btn">
316+
you vs Computer
317+
</button>
318+
</div>
319+
<div class="game-container">
320+
<div class="tic-tac-toe-board" id="ticTacToeBoard">
321+
<button class="cell" data-cell="0"></button>
322+
<button class="cell" data-cell="1"></button>
323+
<button class="cell" data-cell="2"></button>
324+
<button class="cell" data-cell="3"></button>
325+
<button class="cell" data-cell="4"></button>
326+
<button class="cell" data-cell="5"></button>
327+
<button class="cell" data-cell="6"></button>
328+
<button class="cell" data-cell="7"></button>
329+
<button class="cell" data-cell="8"></button>
330+
</div>
331+
332+
<p id="ticTacToeStatus">Player X's turn</p>
333+
334+
<button id="restartTicTacToe" class="game-btn">
335+
🔄 Restart Game
336+
</button>
337+
</div>
338+
</div>
339+
`;
340+
}
341+
342+
function initTicTacToe() {
343+
const cells = document.querySelectorAll('.cell');
344+
const statusText = document.getElementById('ticTacToeStatus');
345+
const restartBtn = document.getElementById('restartTicTacToe');
346+
const twoPlayerBtn = document.getElementById('twoPlayerMode');
347+
const computerBtn = document.getElementById('computerMode');
348+
349+
let vsComputer = false;
350+
let currentPlayer = 'X';
351+
let board = ['', '', '', '', '', '', '', '', ''];
352+
let gameActive = true;
353+
354+
355+
356+
const pvpBtn = document.getElementById('pvpMode');
357+
const aiBtn = document.getElementById('aiMode');
358+
359+
pvpBtn.addEventListener('click', () => {
360+
vsComputer = false;
361+
362+
pvpBtn.classList.add('active-mode');
363+
aiBtn.classList.remove('active-mode');
364+
365+
resetGame();
366+
statusText.textContent = "2 Player Mode";
367+
});
368+
369+
aiBtn.addEventListener('click', () => {
370+
vsComputer = true;
371+
372+
aiBtn.classList.add('active-mode');
373+
pvpBtn.classList.remove('active-mode');
374+
375+
resetGame();
376+
statusText.textContent = "Playing vs Computer";
377+
});
378+
379+
const winningCombinations = [
380+
[0,1,2],
381+
[3,4,5],
382+
[6,7,8],
383+
[0,3,6],
384+
[1,4,7],
385+
[2,5,8],
386+
[0,4,8],
387+
[2,4,6]
388+
];
389+
390+
function checkWinner() {
391+
for (let combo of winningCombinations) {
392+
const [a, b, c] = combo;
393+
394+
if (
395+
board[a] &&
396+
board[a] === board[b] &&
397+
board[a] === board[c]
398+
) {
399+
statusText.textContent = `🎉 Player ${board[a]} wins!`;
400+
gameActive = false;
401+
return;
402+
}
403+
}
404+
405+
if (!board.includes('')) {
406+
statusText.textContent = "🤝 It's a draw!";
407+
gameActive = false;
408+
}
409+
}
410+
411+
cells.forEach(cell => {
412+
cell.addEventListener('click', () => {
413+
const index = cell.dataset.cell;
414+
415+
if (board[index] || !gameActive) return;
416+
417+
board[index] = currentPlayer;
418+
cell.textContent = currentPlayer;
419+
420+
checkWinner();
421+
422+
if (vsComputer && gameActive && currentPlayer === 'X') {
423+
currentPlayer = 'O';
424+
statusText.textContent = "Computer's turn";
425+
426+
setTimeout(() => {
427+
computerMove();
428+
}, 500);
429+
430+
return;
431+
}
432+
433+
if (gameActive) {
434+
currentPlayer = currentPlayer === 'X' ? 'O' : 'X';
435+
statusText.textContent = `Player ${currentPlayer}'s turn`;
436+
}
437+
});
438+
});
439+
440+
function resetGame() {
441+
board = ['', '', '', '', '', '', '', '', ''];
442+
gameActive = true;
443+
currentPlayer = 'X';
444+
445+
cells.forEach(cell => {
446+
cell.textContent = '';
447+
});
448+
449+
statusText.textContent = "Player X's turn";
450+
}
451+
452+
function computerMove() {
453+
let emptyCells = [];
454+
455+
board.forEach((cell, index) => {
456+
if (cell === '') {
457+
emptyCells.push(index);
458+
}
459+
});
460+
461+
if (emptyCells.length === 0) return;
462+
463+
const randomIndex =
464+
emptyCells[Math.floor(Math.random() * emptyCells.length)];
465+
466+
board[randomIndex] = 'O';
467+
cells[randomIndex].textContent = 'O';
468+
469+
checkWinner();
470+
471+
if (gameActive) {
472+
currentPlayer = 'X';
473+
statusText.textContent = "Player X's turn";
474+
}
475+
}
476+
477+
restartBtn.addEventListener('click', resetGame);
478+
}
479+
480+
481+
300482
// ============================================
301483
// DICE ROLLING
302484
// ============================================

0 commit comments

Comments
 (0)