Skip to content

Commit efdafde

Browse files
authored
Merge pull request #90 from Sumandeep-Kaur/tic-tac-toe
Tic tac toe game
2 parents 5c50038 + 75da7e5 commit efdafde

File tree

4 files changed

+353
-0
lines changed

4 files changed

+353
-0
lines changed

Games/Game_03/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
## Tic Tac Toe
2+
3+
<h3> Tech Stack Used <img src = "https://media2.giphy.com/media/QssGEmpkyEOhBCb7e1/giphy.gif?cid=ecf05e47a0n3gi1bfqntqmob8g9aid1oyj2wr3ds3mg700bl&rid=giphy.gif" width = 32px> </h3>
4+
<p align="left"> <a href="https://www.w3.org/html/" target="_blank"> <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/html5/html5-original-wordmark.svg" alt="html5" width="40" height="40"/> </a> <a href="https://www.w3schools.com/css/" target="_blank"> <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/css3/css3-original-wordmark.svg" alt="css3" width="40" height="40"/> </a> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" target="_blank"> <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/javascript/javascript-original.svg" alt="javascript" width="40" height="40"/> </a> </p>
5+
6+
### Preview

Games/Game_03/code/index.html

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
8+
<link rel="stylesheet" href="style.css">
9+
<title>Tic Tac Toe</title>
10+
</head>
11+
12+
<body class="body-container">
13+
<section class="selectSym container">
14+
<h1 class="heading">TIC TAC TOE</h1>
15+
<h2 class="pick-msg">Pick your side</h2>
16+
<div class="pick-options">
17+
<button class="pick-x" onClick="selectSym('X')">x</button>
18+
<button class="pick-o" onClick="selectSym('O')">o</button>
19+
</div>
20+
</section>
21+
22+
<section class="game-container container">
23+
<h1 class="heading">TIC TAC TOE</h1>
24+
<div class="board">
25+
<div class="cell" id="0"></div>
26+
<div class="cell" id="1"></div>
27+
<div class="cell" id="2"></div>
28+
<div class="cell" id="3"></div>
29+
<div class="cell" id="4"></div>
30+
<div class="cell" id="5"></div>
31+
<div class="cell" id="6"></div>
32+
<div class="cell" id="7"></div>
33+
<div class="cell" id="8"></div>
34+
</div>
35+
36+
<div class="endgame">
37+
<div class="message">
38+
<span class="text"></span>
39+
<button id="restart" onClick="location.reload();">Play Again</button>
40+
</div>
41+
</div>
42+
</section>
43+
44+
<script src="script.js"></script>
45+
</body>
46+
47+
</html>

Games/Game_03/code/script.js

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
let origBoard;
2+
let huPlayer = 'O';
3+
let aiPlayer = 'X';
4+
const winCombos = [
5+
[0, 1, 2],
6+
[3, 4, 5],
7+
[6, 7, 8],
8+
[0, 4, 8],
9+
[6, 4, 2],
10+
[2, 5, 8],
11+
[1, 4, 7],
12+
[0, 3, 6]
13+
];
14+
15+
const cells = document.querySelectorAll('.cell');
16+
17+
function selectSym(sym) {
18+
huPlayer = sym;
19+
aiPlayer = sym === 'O' ? 'X' : 'O';
20+
origBoard = Array.from(Array(9).keys());
21+
for (let i = 0; i < cells.length; i++) {
22+
cells[i].addEventListener('click', turnClick, false);
23+
}
24+
if (aiPlayer === 'X') {
25+
turn(bestSpot(), aiPlayer);
26+
}
27+
document.querySelector('.selectSym').style.display = "none";
28+
document.querySelector('.game-container').style.display = "flex";
29+
}
30+
31+
function turnClick(square) {
32+
if (typeof origBoard[square.target.id] === 'number') {
33+
turn(square.target.id, huPlayer);
34+
if (!checkWin(origBoard, huPlayer) && !checkTie())
35+
turn(bestSpot(), aiPlayer);
36+
}
37+
}
38+
39+
function turn(squareId, player) {
40+
origBoard[squareId] = player;
41+
if (player == "X") {
42+
document.getElementById(squareId).innerHTML = "x";
43+
document.getElementById(squareId).classList.add("x");
44+
} else {
45+
document.getElementById(squareId).innerHTML = "o";
46+
document.getElementById(squareId).classList.add("o");
47+
}
48+
let gameWon = checkWin(origBoard, player);
49+
if (gameWon) gameOver(gameWon);
50+
checkTie();
51+
}
52+
53+
function checkWin(board, player) {
54+
let plays = board.reduce((a, e, i) => (e === player) ? a.concat(i) : a, []);
55+
let gameWon = null;
56+
for (let [index, win] of winCombos.entries()) {
57+
if (win.every(elem => plays.indexOf(elem) > -1)) {
58+
gameWon = { index: index, player: player };
59+
break;
60+
}
61+
}
62+
return gameWon;
63+
}
64+
65+
function gameOver(gameWon) {
66+
for (let index of winCombos[gameWon.index]) {
67+
document.getElementById(index).style.backgroundColor =
68+
gameWon.player === "X" ? "red" : "grey";
69+
}
70+
declareWinner(gameWon.player === huPlayer ? "You Win! 🎉" : "You Lose! 💔");
71+
}
72+
73+
function declareWinner(who) {
74+
document.querySelector(".endgame").style.display = "flex";
75+
document.querySelector(".endgame .text").innerText = who;
76+
}
77+
function emptySquares() {
78+
return origBoard.filter((elm, i) => i === elm);
79+
}
80+
81+
function bestSpot() {
82+
return minimax(origBoard, aiPlayer).index;
83+
}
84+
85+
function checkTie() {
86+
if (emptySquares().length === 0) {
87+
declareWinner("Draw!");
88+
return true;
89+
}
90+
return false;
91+
}
92+
93+
function minimax(newBoard, player) {
94+
var availSpots = emptySquares(newBoard);
95+
96+
if (checkWin(newBoard, huPlayer)) {
97+
return { score: -10 };
98+
} else if (checkWin(newBoard, aiPlayer)) {
99+
return { score: 10 };
100+
} else if (availSpots.length === 0) {
101+
return { score: 0 };
102+
}
103+
104+
var moves = [];
105+
for (let i = 0; i < availSpots.length; i++) {
106+
var move = {};
107+
move.index = newBoard[availSpots[i]];
108+
newBoard[availSpots[i]] = player;
109+
110+
if (player === aiPlayer)
111+
move.score = minimax(newBoard, huPlayer).score;
112+
else
113+
move.score = minimax(newBoard, aiPlayer).score;
114+
newBoard[availSpots[i]] = move.index;
115+
if ((player === aiPlayer && move.score === 10) || (player === huPlayer && move.score === -10))
116+
return move;
117+
else
118+
moves.push(move);
119+
}
120+
121+
let bestMove, bestScore;
122+
if (player === aiPlayer) {
123+
bestScore = -1000;
124+
for (let i = 0; i < moves.length; i++) {
125+
if (moves[i].score > bestScore) {
126+
bestScore = moves[i].score;
127+
bestMove = i;
128+
}
129+
}
130+
} else {
131+
bestScore = 1000;
132+
for (let i = 0; i < moves.length; i++) {
133+
if (moves[i].score < bestScore) {
134+
bestScore = moves[i].score;
135+
bestMove = i;
136+
}
137+
}
138+
}
139+
140+
return moves[bestMove];
141+
}

Games/Game_03/code/style.css

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
@import url('https://fonts.googleapis.com/css2?family=Luckiest+Guy&display=swap');
2+
* {
3+
margin: 0;
4+
padding: 0;
5+
box-sizing: border-box;
6+
}
7+
.body-container {
8+
height: 100vh;
9+
width: 100vw;
10+
display: flex;
11+
flex-direction: column;
12+
justify-content: space-around;
13+
align-items: center;
14+
background: -webkit-linear-gradient(135deg, #fff6b7 10%, #f6416c 100%);
15+
}
16+
.container {
17+
height: 100%;
18+
display: flex;
19+
flex-direction: column;
20+
align-items: center;
21+
justify-content: space-evenly;
22+
}
23+
.heading {
24+
font-size: 70px;
25+
color: white;
26+
font-family: "Courier New", Courier, monospace;
27+
}
28+
.pick-msg {
29+
font-size: 40px;
30+
color: #fff6b7;
31+
font-family: "Courier New", Courier, monospace;
32+
}
33+
.pick-x, .pick-o {
34+
height: 180px;
35+
width: 180px;
36+
font-size: 9em;;
37+
text-align: center;
38+
line-height: 180px;
39+
border-radius: 15px;
40+
cursor: pointer;
41+
border: none;
42+
outline: none;
43+
background-color: rgba(255, 255, 255, 0.25);
44+
font-family: 'Luckiest Guy', cursive;
45+
}
46+
.pick-x:hover, .pick-o:hover {
47+
background-color: rgba(255, 255, 255, 0.5);
48+
box-shadow: 15px 15px 40px -6px rgba(0, 0, 0, 0.2);
49+
}
50+
.pick-x {
51+
margin-right: 20px;
52+
color: #F85032;
53+
text-shadow: 3px 8px 10px #da4a08;
54+
}
55+
.pick-o {
56+
color: grey;
57+
text-shadow: 3px 8px 5px #474747;
58+
}
59+
.game-container {
60+
display: none;
61+
}
62+
.board {
63+
width: 350px;
64+
height: 350px;
65+
display: grid;
66+
grid-template-columns: repeat(3, 1fr);
67+
grid-gap: 8px;
68+
cursor: pointer;
69+
}
70+
.cell {
71+
height: 110px;
72+
font-size: 70px;
73+
font-family: 'Luckiest Guy', cursive;
74+
border-radius: 15px;
75+
background-color: rgba(255, 255, 255, 0.25);
76+
text-align: center;
77+
line-height: 110px;
78+
}
79+
.cell:hover {
80+
background-color: rgba(255, 255, 255, 0.5);
81+
border-left: 2px solid rgba(255, 255, 255, 0.8);
82+
border-right: 2px solid rgba(255, 255, 255, 0.8);
83+
box-shadow: 15px 15px 40px -6px rgba(0, 0, 0, 0.2);
84+
}
85+
.cell.x {
86+
color: #F85032;
87+
text-shadow: 3px 5px 5px #da4a08;
88+
cursor: not-allowed;
89+
}
90+
.cell.o {
91+
color: grey;
92+
text-shadow: 3px 5px 5px #474747;
93+
cursor: not-allowed;
94+
}
95+
.endgame {
96+
height: 100vh;
97+
width: 100vw;
98+
display: flex;
99+
justify-content: center;
100+
align-items: center;
101+
position: absolute;
102+
background: rgba(255, 255, 255, 0.4);
103+
backdrop-filter: blur(5px);
104+
-webkit-backdrop-filter: blur(5px);
105+
display: none;
106+
}
107+
.message {
108+
display: flex;
109+
justify-content: center;
110+
align-items: center;
111+
flex-direction: column;
112+
font-size: 30px;
113+
width: 300px;
114+
height: 200px;
115+
border-radius: 30px;
116+
background-color: linen;
117+
box-shadow: 6px 7px 42px 0px rgba(0, 0, 0, 0.9);
118+
font-weight: bold;
119+
text-shadow: 1px 1px 3px rgba(82, 80, 80, 0.473);
120+
}
121+
.endgame .text{
122+
color: maroon;
123+
font-family: "Courier New", Courier, monospace;
124+
}
125+
.message button {
126+
color: rgb(141, 41, 41);
127+
margin-top: 30px;
128+
padding: 10px 12px;
129+
font-size: 20px;
130+
font-weight: bold;
131+
border-radius: 10px;
132+
cursor: pointer;
133+
}
134+
.endgame button {
135+
background: -webkit-linear-gradient(100deg, #fff6b7 10%, #f6416c 150%);
136+
box-shadow: 1px 1px 5px 2px rgba(128, 128, 128, 0.596);
137+
border: none;
138+
}
139+
.endgame button:active {
140+
transform: scale(0.8);
141+
}
142+
@media screen and (max-width: 550px) {
143+
.heading {
144+
font-size: 50px;
145+
}
146+
.pick-msg {
147+
font-size: 30px;
148+
}
149+
.pick-options {
150+
flex-direction: column;
151+
}
152+
.pick-x, .pick-o {
153+
height: 160px;
154+
width: 160px;
155+
font-size: 7em;
156+
line-height: 160px;
157+
margin-bottom: 20px;
158+
}
159+
}

0 commit comments

Comments
 (0)