code: def potential_swaps(self):
          
          a = self._array
          rows, cols = a.shape
          for this_position, tile in self.positions_with_tile():
              #produce horizontal swap for this position
              r, c = this_position
              if c < cols - 1:
                  other_position = (r, c + 1)
                  if self._swap_optimizer_allows(this_position, other_position):
                      yield (this_position, other_position)
              #produce vertical swap for this position. not DRY but maybe ok
              if r < rows - 1:
                  other_position = (r + 1, c)
                  if self._swap_optimizer_allows(this_position, other_position):
                      yield (this_position, other_position)
docs: Generate a sequence of at least all valid swaps for this board.
  
          The built-in optimizer filters out many meaningless swaps, but not all.