def is_valid_move(self, pos): land_posx, land_posy = util.sgf_to_pos(pos) board_copy = copy.deepcopy(self.board) # 最先判断落子位置是不是空点,如果是不是空点,那么一定是不可以下的。 if self.board[land_posx][land_posy] != EMPTY_STONE: return False # 判断它的周围是不是有空点,如果有空点,那么一定是可以下的。 for i in range(4): if 0 <= land_posx + dx[i] < 19 and 0 <= land_posy + dy[i] < 19: if self.board[land_posx + dx[i]][land_posy + dy[i]] == EMPTY_STONE: return True # 判断吃子的话,先算一下zobrist哈希 num_pos = util.pos_to_num((land_posx, land_posy)) hash = self.zob_history[-1] if self._current_player() == SIDE_BLACK: c_zb_state = zb.STATE_BLACK o_zb_state = zb.STATE_WHITE current_stone = BLACK_STONE opposite_stone = WHITE_STONE else: c_zb_state = zb.STATE_WHITE o_zb_state = zb.STATE_BLACK current_stone = WHITE_STONE opposite_stone = BLACK_STONE # 判断是否吃子了,如果吃子了,那么应该是可以下的,但是要判断打劫,用zb哈希 has_eat = False for key, value in self.group[self._opposite_player()].items(): if value.count_liberty() == 1: if value.has_liberty(util.pos_to_num((land_posx, land_posy))): has_eat = True for s in self.group[self._opposite_player()][key].stone: px, py = util.num_to_pos(s) board_copy[px][py] = EMPTY_STONE # 取消对方子的状态 hash = zb.get_new_hash(hash, self.zob_arr, o_zb_state, s) # 赋予空点的状态 hash = zb.get_new_hash(hash, self.zob_arr, zb.STATE_EMPTY, s) board_copy[land_posx][land_posy] = current_stone hash = zb.get_new_hash(hash, self.zob_arr, zb.STATE_EMPTY, num_pos) hash = zb.get_new_hash(hash, self.zob_arr, c_zb_state, num_pos) if has_eat and len(self.zob_history) > 2: if self.zob_history[-2] == hash: # print 'ko rule!' return False if has_eat: return True # 如果没有吃子,那么可能就是往对方里面填子,那么用dfs遍历一下,看看这个棋串周围是否有空点 # pos_x, pos_y是坐标! self.found = False self._dfs(board_copy, land_posx, land_posy, current_stone) if self.found is False: self.found = False return False return True
def place_stone(self, pos): land_posx, land_posy = util.sgf_to_pos(pos) num = util.pos_to_num((land_posx, land_posy)) self.place_stone_num(num) """ current_player = self._current_player() opposite_player = self._opposite_player() num_pos = util.pos_to_num((land_posx, land_posy)) current_stone, opposite_stone = None, None # 如果是停一手,则做如下操作 if land_posx < 0: self.history[current_player].append('tt') self.zob_history.append(self.zob_history[-1]) self.round += 1 return # 先判断是否合法 if self.is_valid_move(pos) is False: # print 'Invalid!' return # 如果合法,则做这些操作: """ """ 1. 减去对方棋串的气 2. 将新的子加入本方的棋串中 2.1 遍历本方所有棋串的气,如果有重合,记录备用 2.2 将这些有重合的都加入这个新的棋串中去 2.3 删除那些重合加入的棋串 2.4 重新计算新串的气 3. 对对面所有没气了的棋串:如果对面没有没气了的棋串,并且本方的气是0,说明自尽,那么对本方这块棋的周围, 3.1 对于每个没气了的棋串的每个子,看上下左右(注意边界) 3.2 上下左右如果有本方的棋子,那么加入一个列表备用 3.3 删除这个棋串 4. 重新生成棋盘 5. 记录的这些黑子,判断属于哪些棋块,对这些棋块重新算气 """ """