input: Write a function to find the shortest path between two points in a matrix. The function should return the length of the shortest path if a path exists, otherwise return -1. If the start or end point is out of the matrix boundaries, return -1.
  assert shortest_path([[2, 3, 5], [1, 7, 6], [3, 0, 9]], (0, 0), (2, 2))==5
  assert shortest_path([[1, 2], [3, 4]], (0, 0), (1, 1))==3
  assert shortest_path([[1, 2, 3], [4, 5, 6]], (0, 0), (2, 2))==-1
  assert shortest_path([], (0, 0), (0, 0))==-1
  assert shortest_path([[1]], (0, 0), (0, 0))==1
output: def shortest_path(matrix, start, end):
      if not matrix or start[0] < 0 or start[0] >= len(matrix) or start[1] < 0 or start[1] >= len(matrix[0]) or end[0] < 0 or end[0] >= len(matrix) or end[1] < 0 or end[1] >= len(matrix[0]):
          return -1
      
      from collections import deque
      rows, cols = len(matrix), len(matrix[0])
      directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
      queue = deque([(start[0], start[1], 0)])
      visited = set()
      visited.add(start)
      
      while queue:
          x, y, dist = queue.popleft()
          if (x, y) == end:
              return dist + 1
          for dx, dy in directions:
              nx, ny = x + dx, y + dy
              if 0 <= nx < rows and 0 <= ny < cols and (nx, ny) not in visited:
                  visited.add((nx, ny))
                  queue.append((nx, ny, dist + 1))
      
      return -1