4

我正在实现游戏 Othello / Reversi 的 Python 版本。但是,我的算法在西南方向搜索时似乎遇到了问题。

这里有一些重要的函数可以帮助我理解我当前的代码是如何工作的:

def _new_game_board(self)->[[str]]:
    board = []
    for row in range(self.rows):
        board.append([])
        for col in range(self.columns):
            board[-1].append(0)
    return board
def _is_valid_position(self, turn:list)->bool:
        '''return true if the turn is a valid row and column'''
        row = int(turn[0]) - 1
        column = int(turn[1]) - 1
        if row >= 0:
            if row < self.rows:
                if column >= 0:
                    if column < self.columns:
                        return True
        else:
            return False


def _is_on_board(self, row:int, col:int)->bool:
    '''returns true is coordinate is on the board'''
    if row >=0:
        if row < self.rows:
            if col >=0:
                if col < self.columns:
                    return True




def _searchNorthEast(self)->None:
    '''Search the board NorthEast'''
    print("NorthEast")
    row = self.move_row
    column = self.move_column
    should_be_flipped = list()
    row += 1
    column -= 1
    if self._is_on_board(row, column):
         print("column searching NorthEast on board")
         if self.board[row][column] == self._opponent:
             should_be_flipped.append([row, column])
             while True:
                row += 1
                column -= 1
                if self._is_on_board(row, column):
                    if self.board[row][column] == self._opponent:
                        should_be_flipped.append([row, column])
                        continue
                    elif self.board[row][column] == self.turn:
                        self._to_be_flipped.extend(should_be_flipped)
                        break
                    else:
                        break
                else:
                    self._to_be_flipped.extend(should_be_flipped)
    else:
        pass

    def _searchSouthWest(self)->None:
    '''Search the board SouthWest'''
    print("in SouthWest")
    row = self.move_row
    column = self.move_column
    should_be_flipped = list()
    row -= 1
    column += 1
    if self._is_on_board(row, column):
         print("column searching SouthWest on board")
         if self.board[row][column] == self._opponent:
             should_be_flipped.append([row, column])
             while True:
                row -= 1
                column += 1
                if self._is_on_board(row, column):
                    if self.board[row][column] == self._opponent:
                        should_be_flipped.append([row, column])
                        continue
                    elif self.board[row][column] == self.turn:
                        self._to_be_flipped.extend(should_be_flipped)
                        break
                    else:
                        break
                else:
                    self._to_be_flipped.extend(should_be_flipped)
    else:
        pass

def _move_is_valid(self, turn:list)->bool:
    '''Verify move is valid'''
    self._to_be_flipped = list()
    self._opponent = self._get_opposite(self.turn)
    if self._is_valid_position(turn):
        self.move_row = int(turn[0]) - 1
        self.move_column = int(turn[1]) - 1
        self._searchRight()
        self._searchLeft()
        self._searchUp()
        self._searchDown()
        self._searchNorthWest()
        self._searchNorthEast
        self._searchSouthEast()
        self._searchSouthWest()
        if len(self._to_be_flipped) > 0:
            return True
    else:
         return False

现在假设当前的板如下所示:

. . . .
W W W .
. B B .
. B . .

Turn: B

并且玩家移动到第 1 行第 4 列,它说无效,因为它没有检测到要翻转的第 2 行第 3 列中的白色棋子。我所有的其他函数都以相同的方式编写。除了这种情况,我可以让它在其他所有方向上工作。

任何想法为什么它没有在这个对角线方向上检测到这块?

4

2 回答 2

1

不要重复自己。这些_search*方法非常多余,这使得很难看到

row -= 1
column += 1

是正确的。由于您只给出了两个方向(NE、SW)并且没有关于电路板方向的文档,我无法判断这些标志是否与电路板布局一致,甚至与它们自己一致。

这些_search*方法也太长了,应该分成多个功能,但这是次要的问题。

于 2015-05-27T17:05:35.383 回答
0

我同意 msw 关于不重复的内容。一旦你看到它,就很想继续做你能做的事情,但概括会为你省去调试的麻烦。

这是一些应该给出一般想法的伪代码。我可能无法处理您的代码,但希望这显示了如何减少重复代码。请注意,-1 是向上还是向下并不重要。棋盘类只是一个 2x2 数组(空方格/玩家 1 的棋子/玩家 2 的棋子),轮到它移动。

# x_delta and y_delta are -1/0/1 each based on which of the up to 8 adjacent squares you are checking. Player_num is the player number.
def search_valid(x_candidate, y_candidate, x_delta, y_delta, board, player_num):
    y_near = y_candidate + y_delta
    x_near = x_candidate + x_delta
    if x_near < 0 or x_near >= board_width:
        return False
    if y_near < 0 or y_near >= board_width:
        return False # let's make sure we don't go off the board and throw an exception
    if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == 0:
         return False #empty square
    if board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num:
         return False #same color piece
    return True #if you wanted to detect how many flips, you could use a while loop

现在一个简洁的函数可以循环这个 search_valid 来查看移动是否合法,例如

def check_valid_move(x_candidate, y_candidate, board, player_num):
    for dx in [-1, 0, 1]:
        for dy in [-1, 0, 1]:
            if not x and not y:
                continue # this is not a move. Maybe we don't strictly need this, since board.pieces[x_candidate+x_delta][y_candidate+y_delta] == player_num anyway, but it seems like good form.
            if search_valid(x_candidate, y_candidate, dx, dy, board, player_num):
                return True
    return False   

类似的功能实际上可以翻转所有相反的部分,但这有点棘手。您需要在 for 循环中使用 while 函数。但是您不必为每个方向重写代码。

于 2019-08-02T10:27:08.313 回答