7 days
- JavaScript (ES6)
- HTML5/HTML5 audio
- CSS/Flexbox
- GitHub
Battleship - made using vanilla JavaScript
The game can be found on this GitHub repo and can be played by cloning the repo and opening the index.html
file in a browser.
Alternatively, you can play the game using this hosted version on GitHub Pages.
This version is a single player game against the computer. The objective of the game is to find and destroy all of the computer ships before yours are found and destroyed.
The player and computer get seven ships to place on a 10 x 10 grid. Each side has the following ships (length of squares in brackets):
- 1 x Aircraft Carrier (5 squares)
- 1 x Battleship (4 squares)
- 1 x Cruiser (3 squares)
- 2 x Destroyer (2 squares)
- 2 x Submarine (1 square)
When the game starts, the computer grid is set up and the computer ships are placed randomly on the board and hidden from view.
There are two important things to remember:
- Ships cannot run over the sides of the grid and must be on one row or column
- There needs to be one square between each ship. Ships cannot be placed immediately next to each other. This exclusion zone will be marked by light grey squares on the player grid.
Remember these points when you are guessing where the computer ships are placed!
Placing your ships
- Make a choice from horizontal or vertical.
- Choose from the available ships.
- Click on a square on the player grid.
The choice of ship button will be greyed out once you have placed it.
Once all of you ships are placed, you can make a choice on the computer grid. The game will indicate whether this is a hit or a miss and then the computer will take it's turn.
When all squares for a ship are hit, the number of ships left will go down by one.
The first player to get the opponents ships to zero is the winner.
The greatest challenge in this game, is the random placement of the ships, ensuring that the ships remain on one row or column and do not overlap each other.
As such, my project plan to get to MVP started with setting up the grid and designing a way to place the ships.
There are two 10 x 10 grids. These are created in JavaScript on page load.
function createGrid() {
for (let i = 0; i < (width * width); i++) {
const compGridSquare = document.createElement('div')
document.querySelector('.grid').appendChild(compGridSquare)
compGridSquare.classList.add('square')
computerSquares.push(compGridSquare) //Array of computer grid
}
for (let i = 0; i < (width * width); i++) {
const playerGridSquare = document.createElement('div')
document.querySelector('.player-grid').appendChild(playerGridSquare)
playerGridSquare.classList.add('player-square')
playerSquares.push(playerGridSquare) // Array of player grid
}
shipsToPlace.innerText = playerShips
computerPlaceShips()
addEventListeners()
}
The function computerPlaceShips()
iterates over a shipType
array attempting to place the ships on the computer grid. Horizontal or vertical orientations are selected randomly.
Computer ships are placed on the grid with a class of ship
and a data parameter. For example:
<div class="square ship" data-computership="submarine2">
</div>
These values are used to mark the squares to indicate a hit and also to monitor whether a ship is destroyed.
A number of while
loops run until the all ships are in place. The conditions in these loops check whether the ship will go off the board or overlap another ship. For example:
while ((width - columnIndex) < shipLength) {
randomIndex = Math.floor(Math.random() * computerSquares.length)
columnIndex = (randomIndex % width)
}
Two functions blockAroundHorizontalShip()
and blockAroundVerticalShip()
generate an additional class of block
around the ship which prevents overlap. These functions are repurposed when the player places ships.
The challenge within this process was to take in to consideration starting indices which where on the edges or corners of the grid. In these instances the blockade needed to be customised. This was achieved through a series of conditional statements. For example:
if (columnIndex === 0 && rowIndex !== 0 && rowIndex !== width - shipLength) {
endOfBlockade = startOfBlockade
// If vertical ship against right
} else if (columnIndex === 9 && rowIndex !== 0 && rowIndex !== (width - shipLength)) {
startOfBlockade = endOfBlockade
// If vertical ship on bottom row
} else if (columnIndex !== width - width && columnIndex !== width - 1 && rowIndex === (width - shipLength)) {
bottomBlockade = topBlockade
lengthOfBlockade--
The player placement of ships is achieved through taking the ids of the ship type buttons, for example:
<div class="ship-button" id="carrier" data-shipsize='5'>Aircraft carrier</div>
The method find()
selects the ship size from the array of ship objects.
On click, the code checks whether the player could place the ship in that spot, checking for columnIndex
and rowIndex
and whether the ship would overlap another. If these tests are passed, the ship is placed on the player grid.
On creation of the computer and player ships, each ship is pushed in to an object, creating a series of key value pairs where the key is the name of the ship and the values are the indices. For example:
computerShipsObject = {
cruiser: [12,13,14]
destroyer1: [55,65]
}
When clicking a square on the computer grid, the code checks whether the square contains ship
. If it does, a class of hit
is added. If not then miss
is added. The front end reflects this and a sound is played.
A setTimeout()
method is used to ensure that the audio did not cut out and after a period of time the function computerGuess
is called for the computer to take a turn.
After each turn the function isShipDestroyed()
is called to check whether all indices have a class of hit for that ship. If this is true then the number of ships left for that player is reduced.
Placing the ships on the board and recording whether a ship is destroyed was a challenging process.
Developing a function which triggers a more educated guess by the computer if a hit is achieved.