two-player game
grid traversal
board game design
game strategy
interactive gameplay

Two player grid traversal game

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

Introduction

A two-player grid traversal game looks simple on the surface: two tokens move on a board, and each turn changes only one square. Underneath, it is usually a graph problem. The right solution depends on whether the players are merely racing to a goal or can actively interfere with each other.

Model the Grid First

Start by treating every walkable cell as a node in a graph. A move from one cell to an adjacent cell becomes an edge. Walls, blocked cells, or one-way movement rules change which edges exist.

That modeling step matters because it tells you which algorithm to use:

  • If both players independently race to the same destination, shortest-path search is often enough.
  • If players can block, capture, or deny squares, you need game-state search, not just pathfinding.

For a race variant, the quickest useful question is: how many turns does each player need to reach the goal if the other player does not interfere?

Solving the Race Variant with BFS

On an unweighted grid, breadth-first search gives the shortest number of moves from a start cell to a target. Once you know both distances, deciding the winner is straightforward.

python
1from collections import deque
2
3DIRS = [(1, 0), (-1, 0), (0, 1), (0, -1)]
4
5
6def bfs_distance(grid, start, goal):
7    rows, cols = len(grid), len(grid[0])
8    q = deque([(start[0], start[1], 0)])
9    seen = {start}
10
11    while q:
12        r, c, d = q.popleft()
13        if (r, c) == goal:
14            return d
15
16        for dr, dc in DIRS:
17            nr, nc = r + dr, c + dc
18            inside = 0 <= nr < rows and 0 <= nc < cols
19            if inside and grid[nr][nc] != "#" and (nr, nc) not in seen:
20                seen.add((nr, nc))
21                q.append((nr, nc, d + 1))
22
23    return None
24
25
26grid = [
27    "....#",
28    ".#...",
29    "..#..",
30    "...#.",
31    ".....",
32]
33
34p1 = (0, 0)
35p2 = (4, 4)
36goal = (2, 4)
37
38d1 = bfs_distance(grid, p1, goal)
39d2 = bfs_distance(grid, p2, goal)
40
41if d1 is None and d2 is None:
42    print("Nobody can reach the goal")
43elif d2 is None or (d1 is not None and d1 <= d2):
44    print("Player 1 wins")
45else:
46    print("Player 2 wins")

This works because BFS explores positions in increasing distance order. If both players need the same number of moves, turn order becomes the tiebreaker. In a game where Player 1 moves first, equal distances usually favor Player 1.

When Shortest Path Is Not Enough

Many real two-player games are adversarial. A player may be able to occupy a cell that the opponent needs, force a detour, or move onto the opponent’s square to win immediately. Once that happens, each turn depends on both positions and whose turn it is.

For those cases, represent a state as:

  • Player 1 position
  • Player 2 position
  • current turn

Then search that state space with memoization. On small boards, a minimax-style recursion is enough.

python
1from functools import lru_cache
2
3DIRS = [(1, 0), (-1, 0), (0, 1), (0, -1)]
4
5
6def legal_moves(grid, pos, other):
7    rows, cols = len(grid), len(grid[0])
8    for dr, dc in DIRS:
9        nr, nc = pos[0] + dr, pos[1] + dc
10        inside = 0 <= nr < rows and 0 <= nc < cols
11        if inside and grid[nr][nc] != "#" and (nr, nc) != other:
12            yield (nr, nc)
13
14
15def player1_can_force_win(grid, p1, p2, goal):
16    @lru_cache(maxsize=None)
17    def solve(p1, p2, turn):
18        if p1 == goal:
19            return True
20        if p2 == goal:
21            return False
22
23        if turn == 0:
24            moves = list(legal_moves(grid, p1, p2))
25            return any(solve(nxt, p2, 1) for nxt in moves)
26
27        moves = list(legal_moves(grid, p2, p1))
28        return all(solve(p1, nxt, 0) for nxt in moves)
29
30    return solve(p1, p2, 0)

The interpretation is standard minimax logic. On Player 1's turn, finding one winning move is enough. On Player 2's turn, Player 1 only has a forced win if every response still leads to a win. This exact approach is practical only for small boards, because the number of states grows quickly.

Designing Fair Rules

If you are building the game rather than solving a puzzle, fairness matters as much as algorithm choice. Symmetric starting positions, identical move sets, and a clearly defined tie rule keep the game understandable. If you add random obstacles or power-ups, check whether the first mover now has a consistent advantage.

A useful design habit is to simulate a few thousand random boards and compare win rates. If one side wins far more often, the problem may be in the map layout or in the turn-order rule rather than in player skill.

Common Pitfalls

  • Treating a competitive game like a plain shortest-path problem. BFS alone is only correct when players do not affect each other.
  • Ignoring turn order. Equal path lengths do not imply a tie.
  • Forgetting unreachable states. A blocked goal should return "no path", not a very large number.
  • Building recursive game search without memoization. The same board state appears many times and will make a naive solver too slow.
  • Mixing game rules. If crossing through an occupied cell is illegal, enforce that consistently in move generation.

Summary

  • A grid traversal game is usually a graph problem in disguise.
  • Use BFS for a race on an unweighted board with no real player interaction.
  • Use state-based minimax or dynamic programming when players can block or capture.
  • Track positions and turn order explicitly, because they determine the true game state.
  • Good game design needs fair start positions, clear tie rules, and tested balance.

Related reading
Course
Intermediate
27 lessons
15 hours
DSA Fundamentals

Master algorithmic patterns and data structures through hands-on LeetCode-style problems - from arrays and hashing to dynamic programming and advanced graphs.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

Data Structures & Algorithms practice on Codemia

Step through 300 algorithm problems with animated visualisers that show the data structure changing as the code runs.

Practice algorithms

All Rights Reserved.