input: Write a python function to find the shortest path in a matrix from a start point to an end point.
  assert shortest_path([[0, 1, 0, 0], [0, 1, 0, 1], [0, 0, 0, 1], [1, 1, 0, 0]], (0, 0), (3, 3))==7
  assert shortest_path([[0, 0, 0, 0], [1, 1, 1, 0], [0, 0, 0, 0], [1, 1, 1, 0]], (0, 0), (3, 3))==6
  assert shortest_path([[0, 1, 1, 1], [0, 0, 0, 1], [1, 1, 0, 1], [0, 0, 0, 0]], (0, 0), (3, 3))==6
output: def shortest_path(matrix, start, end):
      from collections import deque
  
      rows, cols = len(matrix), len(matrix[0])
      queue = deque([(start[0], start[1], 0)])  # (row, col, distance)
      directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]  # Up, Down, Left, Right
      visited = set()
      visited.add((start[0], start[1]))
  
      while queue:
          r, c, dist = queue.popleft()
          
          if (r, c) == end:
              return dist
          
          for dr, dc in directions:
              nr, nc = r + dr, c + dc
              if 0 <= nr < rows and 0 <= nc < cols and (nr, nc) not in visited and matrix[nr][nc] == 0:
                  visited.add((nr, nc))
                  queue.append((nr, nc, dist + 1))
  
      return -1  # return -1 if there is no path