Python Arena
Step 5 of 5

A grid as a game board

Many games are played on a grid: chess, tic-tac-toe, minesweeper, sudoku, battleship. A matrix is a natural way to keep such a board in a program. Each item is one square, and its two indexes are the square's row and column.

Here is a small sea for a game of battleship, where 0 is water and 1 is part of a ship. The program prints it with symbols a player can read:

sea = [
    [0, 0, 0, 0, 0],
    [0, 1, 1, 1, 0],
    [0, 0, 0, 0, 0],
    [1, 0, 0, 0, 0],
    [1, 0, 0, 1, 1],
]

for row in sea:
    for square in row:
        if square == 1:
            print("#", end="")
        else:
            print("~", end="")
    print()
Output
~~~~~
~###~
~~~~~
#~~~~
#~~##

end="" keeps the squares of a row on the same line, and the print() after the inner loop ends the row.

Asking the board

Questions about the game become small functions. How many ship squares are there, and does a shot at a given row and column hit?

def ship_squares(sea: list) -> int:
    count = 0
    for row in sea:
        count += row.count(1)
    return count


def is_hit(sea: list, row_index: int, column_index: int) -> bool:
    return sea[row_index][column_index] == 1


sea = [
    [0, 0, 0, 0, 0],
    [0, 1, 1, 1, 0],
    [0, 0, 0, 0, 0],
    [1, 0, 0, 0, 0],
    [1, 0, 0, 1, 1],
]
print("Ship squares:", ship_squares(sea))
print(is_hit(sea, 1, 2))
print(is_hit(sea, 2, 2))
Output
Ship squares: 7
True
False

Strings on the board

For some games, strings say more than numbers. This tic-tac-toe board holds "X", "O" and "." for an empty square. A row is a win when its three squares hold the same piece, and that piece isn't the empty ".":

def row_winner(board: list, row_index: int) -> str:
    row = board[row_index]
    if row[0] != "." and row[0] == row[1] and row[1] == row[2]:
        return row[0]
    return ""


board = [
    ["O", "X", "."],
    ["X", "X", "X"],
    ["O", ".", "O"],
]
print(row_winner(board, 1))
print(row_winner(board, 2) == "")
Output
X
True

The function returns the winning piece, or an empty string when the row isn't a win. Printing an empty string prints an empty line, so the example compares it with "" instead.

Your task

Challenge 1 of 3

Write a function column_winner(board, column_index) that does the same for a column: it returns the piece ("X" or "O") when every square of the column holds that piece, and "" otherwise. A column of empty squares "." is not a win.

For the board [["X", "O", "."], ["X", "O", "X"], ["X", ".", "O"]], column 0 gives "X" and column 1 gives "". Your function should work for a board of any number of rows.

Challenge 2

What does this program print? Type each line it prints.

Challenge 3

Write a function diagonal_winner(board) for a 3 by 3 tic-tac-toe board. A diagonal runs from one corner through the middle square to the opposite corner, and there are two of them. If all three squares of a diagonal hold the same piece ("X" or "O"), the function returns that piece. Otherwise it returns "". Empty squares are ".".

For example, for [["X", "O", "."], [".", "X", "O"], ["O", ".", "X"]] it returns "X".