Use this to learn the idea, then write your own version.
1class Solution:2 def minPushBox(self, grid: list[list[str]]) -> int:3 DIRS = ((0, 1), (1, 0), (0, -1), (-1, 0))4 m = len(grid)5 n = len(grid[0])6 7 for i in range(m):8 for j in range(n):9 if grid[i][j] == 'B':10 box = (i, j)11 elif grid[i][j] == 'S':12 player = (i, j)13 elif grid[i][j] == 'T':14 target = (i, j)15 16 def isInvalid(playerX: int, playerY: int) -> bool:17 return (playerX < 0 or playerX == m or playerY < 0 or playerY == n or18 grid[playerX][playerY] == '#')19 20 def canGoTo(21 playerX: int,22 playerY: int,23 fromX: int,24 fromY: int,25 boxX: int,26 boxY: int27 ) -> bool:28 """Returns True if (playerX, playerY) can go to (fromX, fromY)."""29 q = collections.deque([(playerX, playerY)])30 seen = {(playerX, playerY)}31 32 while q:33 i, j = q.popleft()34 if i == fromX and j == fromY:35 return True36 for dx, dy in DIRS:37 x = i + dx38 y = j + dy39 if isInvalid(x, y):40 continue41 if (x, y) in seen:42 continue43 if x == boxX and y == boxY:44 continue45 q.append((x, y))46 seen.add((x, y))47 48 return False49 50 51 q = collections.deque([(box[0], box[1], player[0], player[1])])52 seen = {(box[0], box[1], player[0], player[1])}53 54 step = 055 while q:56 for _ in range(len(q)):57 boxX, boxY, playerX, playerY = q.popleft()58 if boxX == target[0] and boxY == target[1]:59 return step60 for k, (dx, dy) in enumerate(DIRS):61 nextBoxX = boxX + dx62 nextBoxY = boxY + dy63 if isInvalid(nextBoxX, nextBoxY):64 continue65 if (nextBoxX, nextBoxY, boxX, boxY) in seen:66 continue67 fromX = boxX + DIRS[(k + 2) % 4][0]68 fromY = boxY + DIRS[(k + 2) % 4][1]69 if isInvalid(fromX, fromY):70 continue71 if canGoTo(playerX, playerY, fromX, fromY, boxX, boxY):72 q.append((nextBoxX, nextBoxY, boxX, boxY))73 seen.add((nextBoxX, nextBoxY, boxX, boxY))74 step += 175 76 return -177