Skip to main content
Code Review

Return to Question

Became Hot Network Question
added gomoku reference
Source Link
tdy
  • 2.3k
  • 1
  • 10
  • 21

GomokuGomoku ★★★ (Tic Tac Toe)

Gomoku ★★★ (Tic Tac Toe)

Gomoku ★★★ (Tic Tac Toe)

Source Link

Gomoku game 5 in a row. Javascript simple game Canvas

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>
default

AltStyle によって変換されたページ (->オリジナル) /