Find the minimum number of moves needed to move from one cell of matrix to another in Python

Finding the minimum number of moves to navigate from one cell to another in a matrix is a classic pathfinding problem. We can solve this using Breadth-First Search (BFS) algorithm by treating the matrix as a graph where each cell is a node.

Problem Understanding

In this problem, we have an N × N matrix with specific cell values ?

  • Cell with value 1 indicates Source

  • Cell with value 2 indicates Destination

  • Cell with value 3 indicates Blank cell (walkable)

  • Cell with value 0 indicates Wall (blocked)

We can move in four directions: up, down, left, and right. Each move counts as 1 step.

Example Matrix

3 3 1 0
3 0 3 3
3 3 0 3
0 3 2 3

The shortest path from source (1) to destination (2) takes 5 moves.

Solution Using BFS

We'll create a graph where each valid cell is a node, then use BFS to find the shortest path ?

from collections import deque

class Graph:
    def __init__(self, nodes):
        self.nodes = nodes
        self.adj = [[] for i in range(nodes)]
    
    def insert_edge(self, src, dest):
        self.adj[src].append(dest)
        self.adj[dest].append(src)
    
    def BFS(self, src, dest):
        if src == dest:
            return 0
        
        level = [-1] * self.nodes
        queue = deque([src])
        level[src] = 0
        
        while queue:
            current = queue.popleft()
            
            for neighbor in self.adj[current]:
                if level[neighbor] == -1:  # Not visited
                    level[neighbor] = level[current] + 1
                    queue.append(neighbor)
                    
                    if neighbor == dest:
                        return level[neighbor]
        
        return -1  # No path found

def is_valid(i, j, matrix, order):
    return (0 <= i < order and 0 <= j < order and matrix[i][j] != 0)

def get_min_moves(matrix):
    order = len(matrix)
    src, dest = None, None
    nodes = order * order + 2
    graph = Graph(nodes)
    
    # Map each cell to a node number
    k = 1
    for i in range(order):
        for j in range(order):
            if matrix[i][j] != 0:
                # Connect to adjacent valid cells
                if is_valid(i, j + 1, matrix, order):  # Right
                    graph.insert_edge(k, k + 1)
                if is_valid(i, j - 1, matrix, order):  # Left
                    graph.insert_edge(k, k - 1)
                if is_valid(i + 1, j, matrix, order):  # Down
                    graph.insert_edge(k, k + order)
                if is_valid(i - 1, j, matrix, order):  # Up
                    graph.insert_edge(k, k - order)
                
                # Mark source and destination
                if matrix[i][j] == 1:
                    src = k
                elif matrix[i][j] == 2:
                    dest = k
            
            k += 1
    
    return graph.BFS(src, dest)

# Test the solution
matrix = [
    [3, 3, 1, 0],
    [3, 0, 3, 3],
    [3, 3, 0, 3],
    [0, 3, 2, 3]
]

result = get_min_moves(matrix)
print(f"Minimum moves required: {result}")
Minimum moves required: 5

How It Works

The algorithm works in these steps ?

  1. Graph Construction: Each valid cell (not a wall) becomes a node in the graph

  2. Edge Creation: Connect adjacent walkable cells with edges

  3. BFS Traversal: Use BFS to find the shortest path from source to destination

  4. Level Tracking: Track the distance (number of moves) from the source

Alternative Direct BFS Approach

Here's a simpler approach that works directly on the matrix ?

from collections import deque

def find_min_moves_direct(matrix):
    if not matrix or not matrix[0]:
        return -1
    
    rows, cols = len(matrix), len(matrix[0])
    src_pos = dest_pos = None
    
    # Find source and destination positions
    for i in range(rows):
        for j in range(cols):
            if matrix[i][j] == 1:
                src_pos = (i, j)
            elif matrix[i][j] == 2:
                dest_pos = (i, j)
    
    if not src_pos or not dest_pos:
        return -1
    
    # BFS
    queue = deque([(src_pos[0], src_pos[1], 0)])  # (row, col, moves)
    visited = set([src_pos])
    directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]  # right, left, down, up
    
    while queue:
        row, col, moves = queue.popleft()
        
        if (row, col) == dest_pos:
            return moves
        
        for dr, dc in directions:
            new_row, new_col = row + dr, col + dc
            
            if (0 <= new_row < rows and 0 <= new_col < cols and
                matrix[new_row][new_col] != 0 and
                (new_row, new_col) not in visited):
                
                visited.add((new_row, new_col))
                queue.append((new_row, new_col, moves + 1))
    
    return -1  # No path found

# Test with the same matrix
matrix = [
    [3, 3, 1, 0],
    [3, 0, 3, 3],
    [3, 3, 0, 3],
    [0, 3, 2, 3]
]

result = find_min_moves_direct(matrix)
print(f"Minimum moves required: {result}")
Minimum moves required: 5

Comparison

Approach Time Complexity Space Complexity Implementation
Graph-based BFS O(N²) O(N²) More complex
Direct BFS on Matrix O(N²) O(N²) Simpler

Conclusion

Both approaches use BFS to find the shortest path, but the direct matrix approach is simpler and more intuitive. The key insight is treating the matrix as a graph where each valid cell connects to its adjacent walkable neighbors.

Updated on: 2026-03-25T09:33:55+05:30

466 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements