Skip to content

Commit

Permalink
refactor: merged conflicts with refactored code
Browse files Browse the repository at this point in the history
  • Loading branch information
mrdcvlsc committed Jul 3, 2023
2 parents ce4f406 + 9f7b8c9 commit cf235e8
Show file tree
Hide file tree
Showing 11 changed files with 213 additions and 97 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
lib/Minimax.md
lib/ProjectExplanation.md

# Logs
logs
*.log
Expand Down
35 changes: 0 additions & 35 deletions app.js

This file was deleted.

52 changes: 52 additions & 0 deletions dev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/** This file is only added to run a development static server. */

import path from 'path';
import { fileURLToPath } from 'url';
import os from 'os';
import fastify from 'fastify';
import fastifyStatic from '@fastify/static';

const networkInterfaces = os.networkInterfaces();
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const PORT = process.env.PORT || 3000;
const app = fastify({
logger: false,
});

app.register(fastifyStatic.default, {
root: path.join(__dirname, 'lib'),
});

app.get('/register', (req, res) => {
res.sendFile('index.html');
});

start();
showlocalNetAddress(PORT);

function showlocalNetAddress(PORT) {
console.log(`local : localhost:${PORT}/`);

const localNetAddress =
networkInterfaces?.wlp2s0?.[0]?.address ||
networkInterfaces?.enp3s0f1?.[0]?.address ||
networkInterfaces?.['Wi-Fi']?.[1]?.address ||
networkInterfaces?.Ethernet?.[1]?.address ||
null;

if (localNetAddress) {
console.log(`network : ${localNetAddress}:${PORT}/`);
} else {
console.log('network : Not Available');
}
}

async function start () {
try {
await app.listen({ port: PORT, host: '::' });
} catch (err) {
app.log.error(err);
process.exit(1);
}
};
102 changes: 72 additions & 30 deletions public/TicTacToe.js → lib/TicTacToe.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ function randomInteger(min, max) {
return Math.round(Math.random() * (max - min) + min);
}

/** A single thread tic-tac-toe game representation that can uses
* `minimax` algorithm to search for the best possible move.
function intSum(min, max) {
return ((max - min) + 1) * (min + max) / 2;
}

/** A single thread, blocking, **tic-tac-toe** class game representation that
* can use the **`minimax`** algorithm to search for the best possible move.
*/
class TicTacToe {
constructor(options = { gridLength, winCount, player }) {
Expand Down Expand Up @@ -51,7 +55,7 @@ class TicTacToe {
this.computerAutoPlay = this.computerAutoPlay.bind(this);
this.generateMoves = this.generateMoves.bind(this);
this.minimax = this.minimax.bind(this);
this.checkWinner = this.checkWinner.bind(this);
this.evaluate = this.evaluate.bind(this);
this.isFinish = this.isFinish.bind(this);

this.display = this.display.bind(this);
Expand All @@ -68,7 +72,7 @@ class TicTacToe {
* @description **WARNING**: This method will always **make a move** on an **NA square**
* regardless **even** if the **game has already ended** with a winning player or a draw.
*
* It is advice to use `this.checkWinner()` and/or `this.isFinish()` first before calling this method.
* It is advice to use `this.evaluate()` and/or `this.isFinish()` first before calling this method.
* @param {Number} i row index of the board.
* @param {Number} j column index of the row.
* @returns `MOVE_INVALID = 0`, `MOVE_SUCCESS = 1`. */
Expand Down Expand Up @@ -119,7 +123,7 @@ class TicTacToe {
const moves = this.generateMoves();
const bestMove = { score: 0, idx_i: null, idx_j: null };

const winning = this.checkWinner();
const winning = this.evaluate();
if (winning === P1) {
bestMove.score = 1 * (this.turns <= 0 ? 1 : this.turns);
return bestMove;
Expand Down Expand Up @@ -191,7 +195,7 @@ class TicTacToe {
* In other board game engines like; chess and GO the evaluation function might be separated.
* @returns no winner `0` | player X `1` | player O `2`.
*/
checkWinner() {
evaluate() {
// check row -
for (let i = 0; i < this.grid; ++i) {
let samePiece = 1;
Expand Down Expand Up @@ -231,34 +235,72 @@ class TicTacToe {
}

// check diag \
let samePieceSecondLastDiag = 1;
for (let i = 0; i < this.grid - 1; ++i) {
if (
this.board[i * this.grid + i] === this.board[(i + 1) * this.grid + (i + 1)] &&
this.board[i * this.grid + i] !== NA
) {
samePieceSecondLastDiag++;
if (samePieceSecondLastDiag === this.pieceWinCount) {
this.winner = this.board[i * this.grid + i];
return this.board[i * this.grid + i];
for (let i = 0; i < this.grid; ++i) {
let samePiece = 1, prevPiece = null;
for (let j = 0; j < i + 1; ++j) {
const CURRENT_INDEX = (this.grid - i) + ((this.grid + 1) * j) - 1;
if (prevPiece === this.board[CURRENT_INDEX] && this.board[CURRENT_INDEX] !== NA) {
samePiece++;
if (samePiece === this.pieceWinCount) {
this.winner = this.board[CURRENT_INDEX];
return this.board[CURRENT_INDEX];
}
} else {
samePiece = 1;
}
} else {
samePieceSecondLastDiag = 1;
prevPiece = this.board[CURRENT_INDEX];
}
}

for (let i = 1; i < this.grid; ++i) {
let samePiece = 1, prevPiece = null;
for (let j = 0; this.grid - i - j > 0; ++j) {
const CURRENT_INDEX = (i * this.grid) + ((this.grid + 1) * j);
if (prevPiece === this.board[CURRENT_INDEX] && this.board[CURRENT_INDEX] !== NA) {
samePiece++;
if (samePiece === this.pieceWinCount) {
this.winner = this.board[CURRENT_INDEX];
return this.board[CURRENT_INDEX];
}
} else {
samePiece = 1;
}
prevPiece = this.board[CURRENT_INDEX];
}
}

// check diag /
const diagStep = this.grid - 1;
let samePieceLastDiag = 1;
for (let i = 0; i < this.grid; ++i) {
let samePiece = 1, prevPiece = null;
for (let j = 0; j < i + 1; ++j) {
const CURRENT_INDEX = i + (j * this.grid) - j;
if (prevPiece === this.board[CURRENT_INDEX] && this.board[CURRENT_INDEX] !== NA) {
samePiece++;
if (samePiece === this.pieceWinCount) {
this.winner = this.board[CURRENT_INDEX];
return this.board[CURRENT_INDEX];
}
} else {
samePiece = 1;
}
prevPiece = this.board[CURRENT_INDEX];
}
}

for (let i = 1; i < this.grid; ++i) {
if (this.board[i * diagStep] === this.board[(i + 1) * diagStep] && this.board[i * diagStep] !== NA) {
samePieceLastDiag++;
if (samePieceLastDiag === this.pieceWinCount) {
this.winner = this.board[i * diagStep];
return this.board[i * diagStep];
let samePiece = 1, prevPiece = null;
for (let j = 0; this.grid - i - j > 0; ++j) {
const CURRENT_INDEX = ((this.grid * (i + 1)) - 1) + ((this.grid - 1) * j);
if (prevPiece === this.board[CURRENT_INDEX] && this.board[CURRENT_INDEX] !== NA) {
samePiece++;
if (samePiece === this.pieceWinCount) {
this.winner = this.board[CURRENT_INDEX];
return this.board[CURRENT_INDEX];
}
} else {
samePiece = 1;
}
} else {
samePieceLastDiag = 1;
prevPiece = this.board[CURRENT_INDEX];
}
}

Expand Down Expand Up @@ -290,7 +332,7 @@ class TicTacToe {
* **This method will also update the `this.winner` member when called**.
* @returns `true` if game ended, `false` if not. */
isFinish() {
const hasWinner = this.checkWinner();
const hasWinner = this.evaluate();
if (hasWinner === P1 || hasWinner === P2) {
return true;
}
Expand Down Expand Up @@ -346,15 +388,15 @@ class TicTacToe {
}

/** This test will only work for a 3x3 initialized board. */
testCheckWinner(boardStates, winners) {
testEvaluation(boardStates, winners) {
let failedTests = 0;

for (let i = 0; i < boardStates.length; ++i) {
for (let j = 0; j < this.board.length; ++j) {
this.board[j] = boardStates[i][j];
}

if (this.checkWinner() === winners[i]) {
if (this.evaluate() === winners[i]) {
console.log('test ', i + 1, ' : PASSED');
} else {
console.log('test ', i + 1, ' : FAILED');
Expand Down
4 changes: 3 additions & 1 deletion public/index.html → lib/index.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- this file is only added to show the minimax-tic-tac-toe in action -->

<!DOCTYPE html>
<html>
<head>
Expand Down Expand Up @@ -53,7 +55,7 @@ <h2>MiniMax - TicTacToe</h2>
<div id="board" class="board"></div>
<button class="new-game">New Game</button>
<p class="message"></p>
<a class="ghlink" href="https://github.com/mrdcvlsc/minimax-tic-tac-toe">source code - licence MIT</a>
<a class="ghlink" href="https://github.com/mrdcvlsc/minimax-tic-tac-toe/blob/main/lib/TicTacToe.js">source code</a>
</div>
</body>
</html>
10 changes: 6 additions & 4 deletions public/script.js → lib/script.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// this file is only added to show how to use the TicTacToe.js

// =================== html initialization ===================

const PIECE = [' ', '&#10005;', '&#9711;'];
Expand Down Expand Up @@ -77,9 +79,9 @@ SELECT_GRID.addEventListener('change', () => {

setNewGame(
'The depth has been optimized in relation to the grid value to ' +
'improve calculation speed. You can easily adjust the depth setting, ' +
'but keep in mind that higher values for "depth and grid" will ' +
'increase the move time of the computer and will use more resources.'
'improve the calculation speed. You can adjust the depth value, ' +
'but keep in mind that higher values for "depth and grid" will ' +
'will take more time to calculate or might even crash the page.'
);
});

Expand Down Expand Up @@ -125,7 +127,7 @@ function generateCells() {
for (let j = 0; j < Game.grid; ++j) {
const square = document.createElement('span');
square.className = 'cell';
square.style.animationDelay = `${i * 0.125 + j * 0.125 + 0.125}s`;
square.style.animationDelay = `${(i * 0.1) + (j * 0.1) + 0.1}s`;

square.addEventListener('click', () => makeMove(i, j));

Expand Down
2 changes: 2 additions & 0 deletions public/style.css → lib/style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
/* this file is only added to show the minimax-tic-tac-toe in action */

* {
padding: 0px;
margin: 0px;
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
"name": "tic-tac-toe-minimax",
"version": "1.0.1",
"description": "A tic-tac-toe web application that has a computer player that uses the minimax algorithm to make moves.",
"main": "tests.js",
"main": "lib/TicTacToe.js",
"scripts": {
"dev": "node dev",
"format": "npx prettier --write \"./**/*.{js,jsx,ts,tsx,json,css,scss,md}\""
},
"keywords": [
Expand Down
18 changes: 14 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,25 @@
![tests](https://github.com/mrdcvlsc/minimax-tic-tac-toe/actions/workflows/tests.yml/badge.svg)
![linter](https://github.com/mrdcvlsc/minimax-tic-tac-toe/actions/workflows/linter.yml/badge.svg)

A simple project showcasing my **naive implementation** of [**minimax**](https://en.wikipedia.org/wiki/Minimax#Pseudocode) algorithm for a **tic-tac-toe** web application game.
A simple project showcasing my **naive implementation** of the [**minimax**](https://en.wikipedia.org/wiki/Minimax#Pseudocode) algorithm for an N x N board, **tic-tac-toe** web application game.

- [SEE DEMO](https://minimax-tic-tac-toe-demo.vercel.app/)
## **Test it over the internet :**

**Run locally**
_If you have an internet connection, you can test my Tic-Tac-Toe web application that uses my `minimax-tic-tac-toe` algorithm implementation_.

- [Click here to view the DEMO](https://minimax-tic-tac-toe-demo.vercel.app/)
- **Demo raw link** - https://minimax-tic-tac-toe-demo.vercel.app/

## **To run it locally :**

_You need to have `git` and `node` installed in your device as a requirement_.

```shell
git clone https://github.com/mrdcvlsc/minimax-tic-tac-toe.git
cd minimax-tic-tac-toe
npm install
node app
node dev
```

Then open `localhost:3000` in your browser.

20 changes: 0 additions & 20 deletions shownet.js

This file was deleted.

Loading

0 comments on commit cf235e8

Please sign in to comment.