Commit e9cec6d
Changed files (4)
005.MiniMax
005.MiniMax/index.html
@@ -21,6 +21,36 @@
<h2>005.MiniMax</h2>
<p class="modal__p">
<ul>
+ <li>An unbeatable Tic-Tac-Toe game which uses the concept of
+ <span style="color:var(--lightGold)">
+ MiniMax Algorithm
+ </span>
+ </li>
+ <li>
+ It is a decision rule used for minimizing the possible loss for a
+ <span style="color:var(--lightGold)">
+ worst case scenario.
+ </span>
+ </li>
+ <li>
+ The algorithm considers
+ <span style="color:var(--lightGold)">
+ all possible moves
+ </span>
+ that can be made by the computer and human (optimal moves).
+ </li>
+ <li>
+ Then it concludes the best move for the computer player by
+ <span style="color:var(--lightGold)">
+ minimizing the maximum loss.
+ </span>
+ </li>
+ <li>
+ Refer to
+ <a href="https://en.wikipedia.org/wiki/Minimax" target="_blank" style="color:var(--lightGold)">
+ MiniMax Algorithm
+ </a>
+ </li>
</ul>
</p>
</div>
@@ -30,6 +60,7 @@
<h1>MiniMax</h1>
<p id="tooltip"></p>
<div class="grid">
+ <div id="strikeline" class="strike-line"></div>
<div class="cell" data-value="1"></div>
<div class="cell" data-value="2"></div>
<div class="cell" data-value="3"></div>
005.MiniMax/script.js
@@ -1,6 +1,9 @@
// Initial game state setup
let currentPlayer = Math.random() < 0.5 ? "X" : "O";
let isGameOver = false;
+let winningIndexes = [];
+let winningStrike = "";
+const tooltip = document.getElementById("tooltip");
const GameState = {
X: -10,
O: 10,
@@ -25,6 +28,13 @@ function checkWinner(player) {
// Check diagonals
if (diag1_check || diag2_check) {
+ if (diag1_check) {
+ winningIndexes = [0, 4, 8];
+ winningStrike = "backward";
+ } else {
+ winningIndexes = [2, 4, 6];
+ winningStrike = "forward";
+ }
return true;
}
@@ -33,6 +43,13 @@ function checkWinner(player) {
const rows_check = board[i].every(cell => cell === player);
const cols_check = board.every(row => row[i] === player);
if (rows_check || cols_check) {
+ if (rows_check) {
+ winningIndexes = [i * 3, i * 3 + 1, i * 3 + 2];
+ winningStrike = `vertical.row${i}`
+ } else {
+ winningIndexes = [i, i + 3, i + 6];
+ winningStrike = `horizontal.col${i}`
+ }
return true;
}
}
@@ -105,7 +122,7 @@ function machinePlays() {
if ((currentPlayer === "O" && score > bestScore) || (currentPlayer === "X" && score < bestScore)) {
bestScore = score;
bestMoves = [{ i, j }];
- }else{
+ } else if (score === bestScore) {
bestMoves.push({ i, j });
}
}
@@ -123,11 +140,30 @@ function machinePlays() {
}
}
+function changeColorForWinnerIndexes(indexes) {
+ indexes.forEach(index => {
+ document.querySelector(`.cell[data-value="${index + 1}"]`).style.color = "var(--gold)";
+ });
+ winningStrike.split(".").forEach(cls => {
+ document.getElementById("strikeline").classList.add(cls);
+ });
+ console.log(winningStrike);
+}
+
function checkGameOver() {
- if (checkWinner(currentPlayer) || checkTie()) {
+ if (checkWinner(currentPlayer)) {
+ changeColorForWinnerIndexes(winningIndexes);
+ tooltip.textContent = `Press F5 to play again.`;
+ isGameOver = true;
+ return true;
+ }
+
+ if (checkTie()) {
+ tooltip.textContent = "It's a tie!.\nPress F5 to play again.";
isGameOver = true;
+ return true;
}
- return isGameOver;
+ return false;
}
// User makes a move by clicking a cell
@@ -147,4 +183,10 @@ document.querySelectorAll(".cell").forEach(cell => {
if (currentPlayer === "O") {
console.log("AI starts the game!");
machinePlays();
-}
\ No newline at end of file
+}
+
+document.addEventListener("keydown", event => {
+ if (event.key === "F5") {
+ window.location.reload();
+ }
+});
\ No newline at end of file
005.MiniMax/style.css
@@ -1,8 +1,9 @@
.grid{
display: grid;
+ position: relative;
grid-template-columns: repeat(3, 1fr);
grid-gap: 1px;
- margin-top: 50px;
+ margin-top: 20px;
height: 300px;
width: 300px;
background-color: white;
@@ -10,6 +11,7 @@
}
.cell{
+ position: relative;
display: flex;
justify-content: center;
align-items: center;
@@ -20,5 +22,82 @@
}
#tooltip{
+ margin-top: 20px;
color: var(--gold);
+}
+
+.strike-line{
+ position: absolute;
+ border: 3px solid var(--gold);
+ height: 100%;
+ background-color: var(--gold);
+ opacity: 0.5;
+ z-index: 1;
+ visibility: hidden;
+}
+
+.strike-line.horizontal, .strike-line.vertical, .strike-line.forward, .strike-line.backward{
+ animation: strike 0.5s ease;
+}
+
+.strike-line.horizontal{
+ rotate: 0deg;
+ margin-left: 47px;
+ visibility: visible;
+}
+
+.strike-line.horizontal.col0{
+ left: 0;
+}
+
+.strike-line.horizontal.col1{
+ left: 100px;
+}
+
+.strike-line.horizontal.col2{
+ left: 200px;
+}
+
+.strike-line.vertical{
+ rotate: 90deg;
+ margin-top: 50px;
+ left: 150px;
+ visibility: visible;
+}
+
+.strike-line.vertical.row0{
+ top: -150px;
+}
+
+.strike-line.vertical.row1{
+ top: -50px;
+}
+
+.strike-line.vertical.row2{
+ top: 50px;
+}
+
+.strike-line.forward{
+ height: 130%;
+ top: -50px;
+ left: 150px;
+ rotate: 45deg;
+ visibility: visible;
+}
+
+.strike-line.backward{
+ height: 130%;
+ top: -40px;
+ left: 150px;
+ rotate: -45deg;
+ visibility: visible;
+}
+
+@keyframes strike{
+ 0%{
+ transform: scale(0);
+ }
+ 100%{
+ transform: scale(1);
+ }
}
\ No newline at end of file
index.html
@@ -14,7 +14,7 @@
<body class="h-screen flex items-center justify-center bg-black flex flex-col font-black">
<!-- Warning Modal Section -->
- <input class="modal-state" id="warning" type="checkbox"/>
+ <input class="modal-state" id="warning" type="checkbox" />
<div class="modal">
<div class="modal__inner">
<h2 style="text-align: center;">101 - Warning</h2>
@@ -32,6 +32,7 @@
<a href="./002.TOTP/" class="opacity-75 hover:opacity-100 hover:text-yellow-400">002.TOTP</a>
<a href="./003.3n+1/" class="opacity-75 hover:opacity-100 hover:text-yellow-400">003.3n+1</a>
<a href="./004.Maze-Runner/" class="opacity-75 hover:opacity-100 hover:text-yellow-400">004.Maze-Runner</a>
+ <a href="./005.MiniMax/" class="opacity-75 hover:opacity-100 hover:text-yellow-400">005.MiniMax</a>
</div>
</body>