This article will demonstrate the development of a simple backgammon web application using JavaScript. Backgammon is a classic board game that presents interesting AI and strategy challenges. The game logic and UI implemented will allow two players to compete against each other and record the winner.
Game Components
- Board: The main backgammon board, consisting of a 19x19 grid of intersections where pieces can be placed
- Players: There are two players - the user as white pieces, and the AI opponent as black pieces.
- Start button: Clicking start begins a new game, clearing the board.
- Turns: Players take alternating turns placing one piece on an empty intersection per turn.
- Win condition: When either player connects 5 pieces in a row horizontally, vertically or diagonally, they win. The game ends.
- UI display: The UI will display the game board, current player turn, and win/lose outcome.
Implementing the Frontend
Setting up the HTML Structure
First we'll create the basic HTML page with placeholders for the game board and controls.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Backgammon Game</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="board"></div>
<button id="start">Start</button>
<script src="script.js"></script>
</body>
</html>
The key parts are:
- The with id "board" - this will hold the game board grid.
- The Start button - clicking this will restart the game.
- Link to the CSS stylesheet for styling.
- Script tag to import the game logic JavaScript.
In the CSS we'll set up:
#board {
height: 500px;
margin: 0 auto;
background-color: beige;
}
.dot {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: black;
position: absolute;
}
.white {
background-color: white;
}
Drawing The Chessboard
Next, I'll use JavaScript to draw the chessboard. In script.js the file we will take the chessboard elements and generate the mesh. I'll define a global variable board to store the current game state.
// Board size constant
const boardSize = 15;
// Get board container element
const boardElement = document.getElementById('board');
// 2D array to store board state
let board = [];
// Function to generate the grid
function createBoard() {
// Nested loops to iterate through rows and columns
for (let i = 0; i < boardSize; i++) {
board[i] = [];
for (let j = 0; j < boardSize; j++) {
// Create div for each grid point
const dot = document.createElement('div');
// Set dot class and position
dot.className = 'dot';
dot.style.top = (i * 30 + 10) + 'px';
dot.style.left = (j * 30 + 10) + 'px';
// Add dot to board
boardElement.appendChild(dot);
// Initialize board state
board[i][j] = null;
}
}
}
// Call function to draw board
createBoard();
In the code above, we use two nested for loops to iterate through each row and column of the game board grid. This allows us to traverse the entire 2D array representing the board.
Inside these loops, we create a new
element to represent each intersection point on the grid. We set the CSS class to "dot" so it will be styled properly.We also dynamically set the top and left position styling for each
based on the row and column indexes. This handles the layout and spacing for the grid points.After creating each point
, we append it to the boardElement container which will display them.Finally, as we iterate through the grid, we initialize the 2D board array to store the game state. Each index is set to null initially to indicate it is empty.
Implementing Game Logic
The core game logic will handle player turns, moves, win condition checking, and switching between players.
Handling Player Turns
We'll attach a click event listener to the board to handle player moves.
const startButton = document.getElementById('start');
let currentPlayer = 'white';
boardElement.addEventListener('click', handleClick);
function handleClick(event) {
const dot = event.target;
const row = Math.floor((dot.offsetTop - 10) / 30);
const col = Math.floor((dot.offsetLeft - 10) / 30);
if (board[row][col] === null) {
dot.classList.add(currentPlayer);
board[row][col] = currentPlayer;
// Checks if any player has five pieces in a row
if (checkWin(row, col)) {
endGame(currentPlayer + ' win!');
} else {
currentPlayer = 'black';
setTimeout(systemPlay, 1000); // The system moves automatically to the next move
}
}
}
Implementing Computer Opponent
Next, we need the AI opponent to place pieces during its turn.
function systemPlay() {
// System randomly selects empty intersection
let emptyDots = [];
for (let i = 0; i < boardSize; i++) {
for (let j = 0; j < boardSize; j++) {
if (board[i][j] === null) {
emptyDots.push([i, j]);
}
}
}
const randomIndex = Math.floor(Math.random() * emptyDots.length);
const [row, col] = emptyDots[randomIndex];
const dot = boardElement.children[row * boardSize + col];
dot.classList.add(currentPlayer);
board[row][col] = currentPlayer;
// Checks if any player has five pieces in a row
if (checkWin(row, col)) {
endGame(currentPlayer + ' win!');
} else {
currentPlayer = 'white';
}
}
Win Or Lose Judgement
We first get the clicked element and calculate its row and column. We then check to see if that intersection is empty, and if so, add the current player's piece to it and update the board
array. Next, we use checkWin
function to check if the player has five pieces in a row, and if so, we end the game.
function checkWin(row, col) {
// Check row
let count = 1;
for (let i = col - 1; i >= 0; i--) {
if (board[row][i] === currentPlayer) {
count++;
} else {
break;
}
}
for (let i = col + 1; i < boardSize; i++) {
if (board[row][i] === currentPlayer) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
// Check column
count = 1;
for (let i = row - 1; i >= 0; i--) {
if (board[i][col] === currentPlayer) {
count++;
} else {
break;
}
}
for (let i = row + 1; i < boardSize; i++) {
if (board[i][col] === currentPlayer) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
// Check main diagonal
count = 1;
for (let i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
if (board[i][j] === currentPlayer) {
count++;
} else {
break;
}
}
for (let i = row + 1, j = col + 1; i < boardSize && j < boardSize; i++, j++) {
if (board[i][j] === currentPlayer) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
// Check secondary diagonal
count = 1;
for (let i = row - 1, j = col + 1; i >= 0 && j < boardSize; i--, j++) {
if (board[i][j] === currentPlayer) {
count++;
} else {
break;
}
}
for (let i = row + 1, j = col - 1; i < boardSize && j >= 0; i++, j--) {
if (board[i][j] === currentPlayer) {
count++;
} else {
break;
}
}
if (count >= 5) {
return true;
}
return false;
}
// End game
function endGame(message) {
alert(message);
boardElement.removeEventListener('click', handleClick);
}
Restart The Game
If you want to restart the game, click the start button to restart the game. The main logic is as follows:
startButton.addEventListener('click', resetGame);
function resetGame() {
boardElement.innerHTML = '';
board = [];
createBoard();
currentPlayer = 'white';
}
While basic, this project shows how JavaScript can be used to develop interactive web-based games. Possible enhancements could include undo moves, suggest next moves, etc.
Top comments (1)
I wish I knew JS existed when I started learning how to code. I had to do this kind of learning projects in Java 🥹 Keep up the good work @shingaiz, keep learning and keep posting on dev.to 🙌