class Solution:
  def minimumSeconds(self, land: list[list[str]]) -> int:
    self.DIRS = ((0, 1), (1, 0), (0, -1), (-1, 0))
    m = len(land)
    n = len(land[0])
    floodDist = self._getFloodDist(land)
    startPos = self._getStartPos(land, 'S')
    q = collections.deque([startPos])
    seen = {startPos}
    step = 1
    while q:
      for _ in range(len(q)):
        i, j = q.popleft()
        for dx, dy in self.DIRS:
          x = i + dx
          y = j + dy
          if x < 0 or x == m or y < 0 or y == n:
            continue
          if land[x][y] == 'D':
            return step
          if floodDist[x][y] <= step or land[x][y] == 'X' or (x, y) in seen:
            continue
          q.append((x, y))
          seen.add((x, y))
      step += 1
    return -1
  def _getFloodDist(self, land: list[list[str]]) -> list[list[int]]:
    m = len(land)
    n = len(land[0])
    dist = [[math.inf] * n for _ in range(m)]
    q = collections.deque()
    seen = set()
    for i, row in enumerate(land):
      for j, cell in enumerate(row):
        if cell == '*':
          q.append((i, j))
          seen.add((i, j))
    d = 0
    while q:
      for _ in range(len(q)):
        i, j = q.popleft()
        dist[i][j] = d
        for dx, dy in self.DIRS:
          x = i + dx
          y = j + dy
          if x < 0 or x == m or y < 0 or y == n:
            continue
          if land[x][y] in 'XD' or (x, y) in seen:
            continue
          q.append((x, y))
          seen.add((x, y))
      d += 1
    return dist
  def _getStartPos(self, land: list[list[str]], c: str) -> tuple[int, int]:
    for i, row in enumerate(land):
      for j, cell in enumerate(row):
        if cell == c:
          return i, j