Gomoku ★★★ (Tic Tac Toe)
There are many Gomoku (5 in a row) game projects on the Internet. The scripts of these projects are freely available. Having analyzed them, I created my own
game code based on algorithms taken from the Internet. I have a simple script. The rules of the game are almost the same, that is, the winner is the one who collects 5 letters in a row (either vertically, horizontally, or diagonally). In case of winning, a winner's line is drawn connecting 5 letters. I would like experienced programmers to point out my mistakes.
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Gomoku game 5 in a row</title> <style> body { text-align: center; } #canvas { border: 2px solid green; background-color: lightblue; } </style> </head> <body> <h1>Gomoku game 5 in a row. Javascript simple game Canvas.</h1> <p id="gameStateEl"></p> <p id="gameStateE2"></p> <canvas id="mycanvas"></canvas> <div> <button id="ReStart"type="button" onclick="ReStart();">ReStart</button> </div> <script> const canvas = document.getElementById('mycanvas'); const ctx = canvas.getContext("2d"); const CELL_SIZE = 50; const ROWS = 15, COLS = 15; const CELL_COUNT = ROWS * COLS; const PLAY_COLOR = "teal"; var cellCol = PLAY_COLOR; //Positions on the board const boardPosition = {x: 0, y: 0, w: COLS * CELL_SIZE, h: ROWS * CELL_SIZE}; canvas.width = boardPosition.x + boardPosition.w; canvas.height = boardPosition.y + boardPosition.h; var count_1 = 0; var count_2 = 0; var count_3 = 0; const cells = []; var num = ROWS + 5; //Determine whether the current click is X or O var coords = []; //Save the clicked coordinates record = []; var isWin = false, a1, a2, a3, a4, a5; //Define the unplaced state of the chessboard as 0 for(var i = 0; i<num; i++){ var arr = []; for(var j = 0; j < num; j++){ arr.push(0); } record.push(arr); } var isChangePlayer = false; var first_X = 0; var first_Y = 0; var last_X = 0; var last_Y = 0; function setFont() { ctx.font = "60px Arial"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; } //The initBoard method initializes the game board by //setting the height and width of the board, //creating an array to represent the board, and filling the array with zeros. function initBoard() { var cellIdx = 0; cellCol = PLAY_COLOR; //game State elements gameStateEl.textContent = "Player_1 no moves."; gameStateE2.textContent = "Player_2 no moves."; } //Drawing board background function drawBoardBackground() { ctx.beginPath(); //Nicknames for ease of reading const bP = boardPosition; /* BM67 local alias */ ctx.rect(bP.x, bP.y, bP.w, bP.h); ctx.fillStyle = "rgba(0,122,0, 0.2)"; ctx.strokeStyle = "fuchsia"; ctx.fill(); ctx.beginPath(); for (let i = 0; i <= COLS; i++) { ctx.moveTo(bP.x, bP.y + i * CELL_SIZE); ctx.lineTo(bP.x + bP.w, bP.y + i * CELL_SIZE); ctx.moveTo(bP.x + i * CELL_SIZE, bP.y); ctx.lineTo(bP.x + i * CELL_SIZE, bP.y + bP.h); } ctx.stroke(); } //draw a cell function drawCell(cellIdx) { let val = ""; const x = (cellIdx % COLS) * CELL_SIZE; const y = (cellIdx / COLS | 0) * CELL_SIZE; ctx.fillStyle = "blue"; ctx.shadowColor = '#000'; ctx.fillRect(x, y, CELL_SIZE, CELL_SIZE); ctx.fillStyle = cellCol; ctx.shadowBlur = 4; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 2; ctx.fillRect(x + 5, y + 5, CELL_SIZE - 10, CELL_SIZE - 10); ctx.fillText(val, x + CELL_SIZE * 0.5, y + CELL_SIZE * 0.5); } //let's draw a game function drawGame() { setFont(); var cellIdx = 0; ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); drawBoardBackground(); while (cellIdx < CELL_COUNT) { drawCell(cellIdx ++); } } //Cell pressed function cellClicked(clickIdx) { /* BM67 returns true if board needs redraw */ const x = clickIdx % COLS; const y = clickIdx / COLS | 0; if(coords.length === 0){ draw_X(x, y ,ctx); isChangePlayer = true; addCoords(x, y, 1); }else{ if(verdictCoords(x, y)){ if(!isChangePlayer){ draw_X(x, y); addCoords(x, y, 1); isChangePlayer = true; }else { draw_O(x, y); addCoords(x, y, 2); isChangePlayer = false; } console.log('isVictory() = ' + isVictory()); if(isVictory() && isChangePlayer === true){ drawLine(x, y); my_color = "blue"; <!-- alert("GAME OVER --- blue"); --> //game over console.log("GAME OVER --- Winner blue"); gameStateEl.textContent = "Player_1 Winner blue " + count_1 + " moves."; } if(isVictory() && isChangePlayer === false){ drawLine(x, y); my_color = "red"; <!-- alert("GAME OVER --- red"); --> //game over console.log("GAME OVER --- Winner red" ); gameStateE2.textContent = "Player_2 Winner red " + count_2 + " moves."; } } } } //Adding an onClick handler to a canvas element canvas.addEventListener("mousedown", function (e) { //Nicknames for ease of reading const bP = boardPosition; /* BM67 local alias */ const x = Math.floor((e.offsetX - bP.x) / CELL_SIZE); /* 0 - 3 on board cell */ const y = Math.floor((e.offsetY - bP.y) / CELL_SIZE); /* 0 - 3 on board cell */ if(isChangePlayer === false){ count_1 += 1; gameStateEl.textContent = "Player_1 - " + count_1 + " moves."; } if(isChangePlayer === true){ count_2 += 1; gameStateE2.textContent = "Player_2 - " + count_2 + " moves."; } if (cellClicked(x + y * COLS)) { moveCount += 1; drawGame(); } if (isVictory() === true) { count_3 += 1; } if (count_3 === 2) { ReStart(); } console.log('count_3 = ' + count_3); }); //Draw a X function draw_X(x, y){ editRecord(x, y, 1); ctx.fillStyle = "blue"; ctx.beginPath(); ctx.font = "40px Verdana"; ctx.fillText("X", x * CELL_SIZE + 25, y * CELL_SIZE + 27); ctx.closePath(); ctx.fill(); } //Draw a O function draw_O(x, y){ editRecord(x, y, 2); ctx.fillStyle = "red"; ctx.beginPath(); ctx.font = "40px Verdana"; ctx.fillText("O", x * CELL_SIZE + 25, y * CELL_SIZE + 27); ctx.closePath(); ctx.fill(); } //Let's draw the winner's line. function drawLine(x, y){ editRecord(x, y, 1); ctx.beginPath(); ctx.moveTo(first_X * CELL_SIZE + 25, first_Y * CELL_SIZE + 25); ctx.lineTo(last_X * CELL_SIZE + 25, last_Y * CELL_SIZE + 25); if(isChangePlayer === true){ ctx.strokeStyle = "blue"; } else{ ctx.strokeStyle = "red"; } ctx.lineWidth = 11; ctx.stroke(); ctx.closePath(); } //Add mark to clicked function addCoords(x, y, num){ coords.push({ x: x, y: y, num: num }) } //Edit the marks on the board, //1 represents the red move, 2 represents the black move function editRecord(x, y, num){ record.forEach(function(item, index){ if(index === y){ item.forEach(function(item, index){ if(x === index){ record[y][x] = num; } }) } }) } //Determine whether the current position is placed function verdictCoords(x, y){ var isTrue = true; coords.forEach(function(item, index){ if(item.x === x && item.y === y){ isTrue = false; } }) return isTrue } //Determine whether the mark on the board //meets the victory condition function isVictory(){ var len = record.length; for(var i = 0; i < record.length; i++){ for(var j=0; j<record[i].length; j++){ if(record[i][j] !==0 ){ if(j < len && i - 1 < len){ //Determine the horizontal direction a1 = record[i][j]; a2 = record[i][j + 1]; a3 = record[i][j + 2]; a4 = record[i][j + 3]; a5 = record[i][j + 4]; if(isEqual(a1, a2, a3, a4, a5)){ first_X = j; first_Y = i; last_X = j + 4; last_Y = i; console.log('first_X = ' + first_X); console.log('first_Y = ' + first_Y); console.log('last_X = ' + last_X); console.log('last_Y = ' + last_Y); isWin = true; } //Determine the direction of the forward slash a1 = record[i][j]; a2 = record[i + 1][j + 1]; a3 = record[i + 2][j + 2]; a4 = record[i + 3][j + 3]; a5 = record[i + 4][j + 4]; if(isEqual(a1, a2, a3, a4, a5)){ first_X = j; first_Y = i; last_X = j + 4; last_Y = i + 4; console.log('first_X = ' + first_X); console.log('first_Y = ' + first_Y); console.log('last_X = ' + last_X); console.log('last_Y = ' + last_Y); isWin = true; } //Judging the vertical direction a1 = record[i][j]; a2 = record[i + 1][j]; a3 = record[i + 2][j]; a4 = record[i + 3][j]; a5 = record[i + 4][j]; if(isEqual(a1, a2, a3, a4, a5)){ first_X = j; first_Y = i; last_X = j; last_Y = i + 4; console.log('first_X = ' + first_X); console.log('first_Y = ' + first_Y); console.log('last_X = ' + last_X); console.log('last_Y = ' + last_Y); isWin = true; } //Determine the direction of the backslash a1 = record[i][j]; a2 = record[i + 1][j - 1]; a3 = record[i + 2][j - 2]; a4 = record[i + 3][j - 3]; a5 = record[i + 4][j - 4]; if(isEqual(a1, a2, a3, a4, a5)){ first_X = j; first_Y = i; last_X = j - 4; last_Y = i + 4; console.log('first_X = ' + first_X); console.log('first_Y = ' + first_Y); console.log('last_X = ' + last_X); console.log('last_Y = ' + last_Y); isWin = true; } } } } } return isWin; } isVictory(); //Determine whether the adjacent 5 numbers are equal, //if they are equal, it means that the winner has been divided function isEqual(a1, a2, a3, a4, a5){ if(a1 == a2 && a2==a3 && a3==a4 && a4 == a5){ return true; }else { return false; } } initBoard(); drawGame(); function ReStart() { document.location.reload(); } </script> </body> </html>