Matua Doc

Matua Doc

Battleships with 2D arrays

Learning intentions

In this lesson, you will build a simple Battleships-style game using 2D arrays.

  • Create and update a 2D grid of cells,
  • place ships using row and column indexes,
  • and process guesses safely without index errors.

You will also practise decomposing the game into functions.

  • Write helpers for printing the board,
  • and use parameters and return values to keep logic reusable.

Game overview

Battleships is a guessing game on a grid.

  • One grid stores your hidden ships,
  • another grid stores the player’s guesses,
  • and each guess reveals a hit or a miss.

We will use two 2D arrays of String symbols:

  • "~" for empty water,
  • "S" for a ship,
  • "X" for a hit,
  • "O" for a miss.

Step 1: Create the grid

Start with a 6 by 6 grid of water.

  • A 2D array is an array of rows,
  • so each row is an array of symbols.
let size = 6
var ocean = Array(repeating: Array(repeating: "~", count: size), count: size)
var guesses = Array(repeating: Array(repeating: "~", count: size), count: size)

Step 2: Place ships

For a starter version, place ships manually so you can test easily.

  • A ship is a symbol stored in the grid,
  • so you just assign a value at a row and column.
ocean[1][3] = "S"
ocean[2][3] = "S"
ocean[4][0] = "S"
ocean[5][4] = "S"

Step 3: Print a grid for the player

The player should only see their guesses, not the ships.

  • Print row and column labels to help choose coordinates,
  • and display one symbol per cell.

Suggested function signature (adjust as needed):

/// Parameter:
/// - board: The 2D grid to display.
func printBoard(_ board: [[String]])

Step 4: Check a guess safely

When the player enters a row and column, you need to validate and update.

  • Use guard checks to avoid out-of-range indexes,
  • print a message and return the updated guesses grid.

Suggested function signature (adjust as needed):

/// Parameters:
/// - row: The row index for the guess.
/// - col: The column index for the guess.
/// - ocean: The hidden ships grid.
/// - guesses: The player's current guesses grid.
///
/// Returns: The updated guesses grid after the guess is applied.
func processGuess(row: Int, col: Int, ocean: [[String]], guesses: [[String]]) -> [[String]]

Step 5: Count remaining ships

Track when the game ends by counting ships.

  • Each hit reduces the number of ships left,
  • and you stop when it reaches zero.

Suggested function signature (adjust as needed):

/// Parameters:
/// - ocean: The hidden ships grid.
/// - guesses: The player's current guesses grid.
/// 
/// Returns: How many ships remain unhit.
func remainingShips(in ocean: [[String]], guesses: [[String]]) -> Int

Task A

Create a 6 by 6 ocean grid and a 6 by 6 guesses grid.

Place 4 ships at different coordinates.

Print the empty guesses board using printBoard.

Task B

Write a loop that allows the player to make 5 guesses.

For each guess:

  1. Ask for row and column input.
  2. Call processGuess.
  3. Save the updated guesses grid (the function prints the message).
  4. Print the guesses board.

Task C

Add a win condition.

Requirements:

  1. After each guess, compute the remaining ships with remainingShips.
  2. If the result is 0, print a victory message and end the loop early.
  3. If the loop ends with ships remaining, print a “Game over” message.

Task D

Write a helper called randomShipPlacement that returns a new ocean grid with 4 ships.

Suggested function signature (adjust as needed):

/// Parameters:
/// - size: The width and height of the square grid.
/// - shipCount: How many ships to place.
///
/// Returns: A new ocean grid with ships placed.
func randomShipPlacement(size: Int, shipCount: Int) -> [[String]]

Requirements:

  1. Ships must not overlap.
  2. The function should return the updated grid instead of using inout.
  3. Test by printing the ocean grid once at the start (for debugging), then comment that line out.

Extension for Super Players!

Add one or more improvements.

  • Let the player choose the grid size.
  • Add ship sizes (length 2 or 3) instead of only single cells.
  • and create a displayOcean function that shows ships for a “reveal” mode at the end.

Summary

Battleships is a great practice project for 2D arrays.

  • You store ships in one grid and guesses in another,
  • use row and column indexes to access cells,
  • and write functions to keep the logic clean and safe.

Review

Check your understanding with these prompts.

  • Why do we use two separate grids?
  • What does processGuess return and why?
  • How do you keep your guesses grid updated without inout?
  • and how do you avoid index-out-of-range errors?