Skip to content

Commit 6d82e4c

Browse files
committed
All files were added
0 parents  commit 6d82e4c

File tree

3 files changed

+269
-0
lines changed

3 files changed

+269
-0
lines changed

index.html

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Tic Tac Toe</title>
7+
<link rel="stylesheet" href="/style.css">
8+
<script src="/script.js" defer></script>
9+
</head>
10+
<body>
11+
<h1>Tic-Tac-Toe</h1>
12+
13+
<div class="game-container">
14+
<div class="board">
15+
<div class="cell" data-index="0"></div>
16+
<div class="cell" data-index="1"></div>
17+
<div class="cell" data-index="2"></div>
18+
<div class="cell" data-index="3"></div>
19+
<div class="cell" data-index="4"></div>
20+
<div class="cell" data-index="5"></div>
21+
<div class="cell" data-index="6"></div>
22+
<div class="cell" data-index="7"></div>
23+
<div class="cell" data-index="8"></div>
24+
</div>
25+
<label for="difficulty" style="display:block;text-align:center;margin:10px 0;color:white;font-family:Poppins">Select Difficulty:</label>
26+
<select id="difficulty" style="display:block;margin:0 auto 20px auto;padding:8px;border-radius:8px;font-size:1em;">
27+
<option value="hard">Hard (Unbeatable)</option>
28+
<option value="medium">Medium</option>
29+
<option value="easy">Easy</option>
30+
</select>
31+
32+
<p id="status">Player X's turn</p>
33+
<button id="reset">Reset Game</button>
34+
</div>
35+
</body>
36+
</html>

script.js

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
const cells = document.querySelectorAll('.cell');
2+
const statusText = document.getElementById('status');
3+
const resetButton = document.getElementById('reset');
4+
const difficultySelect = document.getElementById('difficulty');
5+
6+
let currentPlayer = 'X';
7+
let board = ["", "", "", "", "", "", "", "", ""];
8+
let gameActive = true;
9+
10+
const winConditions = [
11+
[0,1,2], [3,4,5], [6,7,8],
12+
[0,3,6], [1,4,7], [2,5,8],
13+
[0,4,8], [2,4,6]
14+
];
15+
16+
function handleCellClick(e) {
17+
const index = e.target.getAttribute('data-index');
18+
19+
if (board[index] !== "" || !gameActive || currentPlayer !== 'X') return;
20+
21+
makeMove(index, 'X');
22+
23+
if (gameActive) {
24+
setTimeout(() => {
25+
const botIndex = getBotMove();
26+
makeMove(botIndex, 'O');
27+
}, 500);
28+
}
29+
}
30+
31+
function makeMove(index, player) {
32+
board[index] = player;
33+
cells[index].textContent = player;
34+
35+
if (checkWin(player)) {
36+
statusText.textContent = `${player} wins! 🎉`;
37+
gameActive = false;
38+
return;
39+
}
40+
41+
if (board.every(cell => cell !== "")) {
42+
statusText.textContent = "It's a draw! 🤝";
43+
gameActive = false;
44+
return;
45+
}
46+
47+
currentPlayer = player === 'X' ? 'O' : 'X';
48+
statusText.textContent = `Player ${currentPlayer}'s turn`;
49+
}
50+
51+
function checkWin(player) {
52+
return winConditions.some(condition =>
53+
condition.every(index => board[index] === player)
54+
);
55+
}
56+
57+
function getBotMove() {
58+
const difficulty = difficultySelect.value;
59+
60+
const emptyIndices = board.map((val, i) => val === "" ? i : null).filter(v => v !== null);
61+
62+
if (difficulty === 'easy') {
63+
// Random move
64+
return emptyIndices[Math.floor(Math.random() * emptyIndices.length)];
65+
}
66+
67+
if (difficulty === 'medium') {
68+
// 50% chance minimax, 50% random
69+
if (Math.random() < 0.5) {
70+
return getBestMove();
71+
} else {
72+
return emptyIndices[Math.floor(Math.random() * emptyIndices.length)];
73+
}
74+
}
75+
76+
// Hard: Always use MiniMax
77+
return getBestMove();
78+
}
79+
80+
function getBestMove() {
81+
let bestScore = -Infinity;
82+
let move;
83+
84+
board.forEach((cell, index) => {
85+
if (cell === "") {
86+
board[index] = 'O';
87+
let score = minimax(board, 0, false);
88+
board[index] = "";
89+
if (score > bestScore) {
90+
bestScore = score;
91+
move = index;
92+
}
93+
}
94+
});
95+
96+
return move;
97+
}
98+
99+
function minimax(newBoard, depth, isMaximizing) {
100+
if (checkWin('O')) return 10 - depth;
101+
if (checkWin('X')) return depth - 10;
102+
if (newBoard.every(cell => cell !== "")) return 0;
103+
104+
if (isMaximizing) {
105+
let bestScore = -Infinity;
106+
newBoard.forEach((cell, index) => {
107+
if (cell === "") {
108+
newBoard[index] = 'O';
109+
let score = minimax(newBoard, depth + 1, false);
110+
newBoard[index] = "";
111+
bestScore = Math.max(score, bestScore);
112+
}
113+
});
114+
return bestScore;
115+
} else {
116+
let bestScore = Infinity;
117+
newBoard.forEach((cell, index) => {
118+
if (cell === "") {
119+
newBoard[index] = 'X';
120+
let score = minimax(newBoard, depth + 1, true);
121+
newBoard[index] = "";
122+
bestScore = Math.min(score, bestScore);
123+
}
124+
});
125+
return bestScore;
126+
}
127+
}
128+
129+
function resetGame() {
130+
board = ["", "", "", "", "", "", "", "", ""];
131+
gameActive = true;
132+
currentPlayer = 'X';
133+
statusText.textContent = "Player X's turn";
134+
cells.forEach(cell => cell.textContent = '');
135+
}
136+
137+
cells.forEach(cell => cell.addEventListener('click', handleCellClick));
138+
resetButton.addEventListener('click', resetGame);

style.css

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
body {
2+
margin: 0;
3+
padding: 0;
4+
background: linear-gradient(-45deg, #a1c4fd, #c2e9fb, #252525, #101010);
5+
background-size: 400% 400%;
6+
animation: gradientBG 15s ease infinite;
7+
font-family: Poppins, sans-serif;
8+
text-align: center;
9+
color: white;
10+
}
11+
12+
@keyframes gradientBG {
13+
0% { background-position: 0% 50%; }
14+
50% { background-position: 100% 50%; }
15+
100% { background-position: 0% 50%; }
16+
}
17+
18+
h1 {
19+
color: #2c2c2c;
20+
background-color: rgb(227, 167, 55);
21+
border: 2px solid #2c2c2c;
22+
border-radius: 16px;
23+
display: inline-block;
24+
padding: 10px 30px;
25+
margin: 30px auto;
26+
font-size: 2.5em;
27+
}
28+
29+
.game-container {
30+
display: flex;
31+
flex-direction: column;
32+
align-items: center;
33+
}
34+
35+
.board {
36+
display: grid;
37+
grid-template-columns: repeat(3, 100px);
38+
grid-template-rows: repeat(3, 100px);
39+
gap: 8px;
40+
margin: 20px 0;
41+
}
42+
43+
.cell {
44+
background-color: #fff;
45+
color: black;
46+
font-size: 2.5em;
47+
display: flex;
48+
align-items: center;
49+
justify-content: center;
50+
border-radius: 12px;
51+
cursor: pointer;
52+
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
53+
user-select: none;
54+
transition: transform 0.1s;
55+
}
56+
57+
.cell:hover {
58+
background-color: #eee;
59+
transform: scale(1.05);
60+
}
61+
62+
#status {
63+
font-size: 1.4em;
64+
margin: 15px 0;
65+
}
66+
67+
#reset {
68+
font-size: 1em;
69+
padding: 10px 20px;
70+
background-color: #ff9800;
71+
color: white;
72+
border: none;
73+
border-radius: 8px;
74+
cursor: pointer;
75+
transition: background-color 0.2s ease;
76+
}
77+
78+
#reset:hover {
79+
background-color: #e68a00;
80+
}
81+
82+
#difficulty {
83+
font-size: 1em;
84+
padding: 8px 12px;
85+
border-radius: 6px;
86+
margin-bottom: 10px;
87+
background-color: #ffffff;
88+
color: black;
89+
border: none;
90+
box-shadow: 0 2px 6px rgba(0,0,0,0.2);
91+
}
92+
93+
#difficulty:focus {
94+
outline: none;
95+
}

0 commit comments

Comments
 (0)