def is_valid_move_numpos(self, pos): land_posx, land_posy = util.num_to_pos(pos) board_copy = copy.deepcopy(self.board) # 最先判断落子位置是不是空点,如果是不是空点,那么一定是不可以下的。 if self.board[land_posx][land_posy] != EMPTY_STONE: return 0 # 判断它的周围是不是有空点,如果有空点,那么一定是可以下的。 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 1 # 判断吃子的话,先算一下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 -1 if has_eat: return 1 # 如果没有吃子,那么可能就是往对方里面填子,那么用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 0 return 1
def recount_liberty(self, side, go_board): assert isinstance(go_board, np.ndarray) for s in self.stone: posx, posy = util.num_to_pos(s) for i in range(4): if 0 <= posx + dx[i] < 19 and 0 <= posy + dy[i] < 19: if go_board[posx + dx[i]][posy + dy[i]] == EMPTY_STONE: self.add_liberty(util.pos_to_num((posx + dx[i], posy + dy[i])))
def judge_ladder(self, key): self_copy = copy.deepcopy(self) pos = -1 opp = set() for st in self_copy.group[self_copy._current_player()][key].stone: posx, posy = util.num_to_pos(st) pos = st for i in range(4): if 0 <= posx + dx[i] < 19 and 0 <= posy + dy[i] < 19: if self_copy.board[posx + dx[i]][posy + dy[i]] == self_copy._opposite_stone(): opp.add(util.pos_to_num((posx + dx[i], posy + dy[i]))) """ for st in opp: for key, value in self_copy.group[self_copy._opposite_player()].items(): if value.has_stone(st): self_copy.ladder_string.append(key) break """ self_copy.ladder_string = list(opp) return self_copy._judge_ladder(pos)
def gtp_io(): global board PASS_FLAG = 0 known_commands = [ 'boardsize', 'clear_board', 'komi', 'play', 'genmove', 'quit', 'name', 'version', 'known_command', 'list_commands', 'protocal_version' ] while True: try: line = raw_input().strip() except EOFError: break if line == '': continue command = [s.lower() for s in line.split()] if re.match('\d+', command[0]): cmdid = command[0] command = command[1:] else: cmdid = '' ret = '' if command[0] == 'boardsize': debug_print( "Warning: Trying to set incompatible boardsize %s (!= %d)" % (command[1], 19)) ret = None elif command[0] == 'clear_board': board = board.Go() elif command[0] == 'komi': pass elif command[0] == 'play': if command[2].upper() == 'PASS': go.place_stone_num(-1) PASS_FLAG = 1 if command[1].upper() == 'B': # and board.current_player == BLACK: # print command[2] go.place_stone_num(util.gtppos_to_num(command[2].upper())) elif command[1].upper( ) == 'W': # and board.current_player == WHITE: # print command[2] go.place_stone_num(util.gtppos_to_num(command[2].upper())) elif command[0] == 'genmove': move = -1 if PASS_FLAG == 1: PASS_FLAG = 0 move = -1 ret = 'pass' else: move = make_prediction() if move is None: ret = 'pass' if move == -1: ret = 'resign' else: ret = util.pos_to_gtppos(util.num_to_pos(move)) go.place_stone_num(move) elif command[0] == 'name': ret = 'PikachuP, 2018' elif command[0] == 'version': ret = '0.2' elif command[0] == 'list_commands': ret = '\n'.join(known_commands) elif command[0] == 'protocol_version': ret = '2' elif command[0] == 'quit': print '=%s \n\n' % (cmdid, ), exit(0) else: debug_print("Unknown Command! ") ret = None if ret is not None: print '=%s %s\n\n' % (cmdid, ret), else: print '?%s ???\n\n' % (cmdid, ), sys.stdout.flush()
def make_prediction(): global go, first_run, first_run_2 """ 第一步: 先对盘面生成特征:这是一个16通道的特征。 使用策略网络(也可能是RL网络) """ feature = go.generate() """ 用iter喂数据给神经网络 """ iter = mx.io.NDArrayIter(data=feature) """ 如果是第一次运行,则绑定模型,并设置参数 """ if first_run: module.bind(data_shapes=iter.provide_data) module.set_params(arg_params, aux_params) first_run = False """ t0 = time.clock() for i in range(320): feature = go.generate() iter = mx.io.NDArrayIter(data=feature) pred = module.predict(iter).asnumpy() pred = feature[0][2].reshape(1, 361) * pred out = np.argsort(-pred) go.place_stone_num(out[0][0]) go_plot.go_plot(go.board) print time.clock() - t0 exit(0) """ """ module.predict(iter) 进行预测,结果在pred中。他是一个(1, 361)的numpy数组 """ pred = module.predict(iter).asnumpy() """ 由于有禁入点的缘故,用feature[0][2]点乘pred。feature[0][2]就是可入点的盘面特征 """ pred = feature[0][2].reshape(1, 361) * pred """ 先取反 然后从小到大排 60 40 20... -60 -40 -20 这样的话就是概率从小到大的顺序。 """ out = np.argsort(-pred) """ X_prior -> X 的平均回报 """ if config.enable_ucb is False: return out[0][0] X_prior = [] """ T_prior -> 已经探索的次数 基于策略网络,假设一定的先验知识 total是访问的总次数 """ T_prior = [config.pre_place_num] * config.search_position_num total = config.pre_place_num * config.search_position_num """ 循环做5次,具体看config.search_position_num的配置 """ for i in range(config.search_position_num): # 打印策略网络的落子概率 debug_print( util.pos_to_gtppos(util.num_to_pos(out[0][i])) + '\t%.2f%%' % (pred[0][out[0][i]] * 100)) # 复制一份 gocopy = copy.deepcopy(go) # 用复制的一份盘面模拟走子! gocopy.place_stone_num(out[0][i]) # 生成模拟走子后的盘面 next_state = gocopy.generate() # 使用价值网络预测胜率 iter_ = mx.io.NDArrayIter(data=next_state) if first_run_2: v_module.bind(data_shapes=iter_.provide_data) v_module.set_params(v_arg_params, v_aux_params) first_run_2 = False # 结果返回到result中 result = v_module.predict(iter_).asnumpy()[0][0] """ 将 策略网络 与 价值网络 相结合! 先验X_prior是 result -> -1 要输 +1 要赢 盘面判断的是对面的 所以 (result + 1) / 2 -> 0->对面要输 1->对面要赢 反过来: 我要赢 我要输 1 - (result + 1) / 2 0 我输了 1 我赢了 """ X_prior.append(config.value_weight * (1 - ((result + 1) / 2)) + POLICY_WEIGHT * pred[0][out[0][i]]) """ 判断本方是哪一方,然后输出对手的获胜概率 """ if gocopy.current_player() == 0: side = 'BLACK: ' else: side = 'WHITE: ' debug_print(side + '%.2f%%' % ((result + 1) / 0.02)) for i in range(config.search_position_num): """ 先输出探索他的 X拔 """ debug_print(util.pos_to_gtppos(util.num_to_pos(out[0][i]))) debug_print("-> {:.2f}%".format(X_prior[i] * 100)) # 计个时 t = time.time() # stat_black, stat_white = 0, 0 # 判断现在是哪一方走棋,然后设置target值。 """ target值用来判断谁输谁赢 """ if go.current_player() == 0: target = 1 _side = 'BLACK' else: target = 0 _side = 'WHITE' """ TO: 要探索多少轮。 这个值会逐渐递增 如果有更好的策略,在这里改进 PikachuP """ TO = ROLLOUTS end_search_value = TO / 2 + config.pre_place_num for i in range(TO): # 选择一个位置: ucb_max = -1000 ucb_id = 0 """ 选择最值得探索的位置 """ for j in range(config.search_position_num): ucb = X_prior[j] + UCB_C * math.sqrt(math.log(total) / T_prior[j]) if ucb > ucb_max: ucb_max = ucb ucb_id = j """ 在最值得探索的位置!位置模拟落子! """ go_copy = copy.deepcopy(go) # pre_black, pre_white = go_copy.evaluate_2() go_copy.place_stone_num(out[0][ucb_id]) """ 用蒙特卡洛模拟模拟走子 返回的是一个模拟走子的胜负结果,0表示白胜利,1表示黑胜利 """ res = monte_carlo_simulate(go_copy) prompt = "" """ 这里的代码算的是chens形势判断领先多少 被我废弃了 if _black - _white > pre_black - pre_white > 0 and target == 1:# 本方黑,黑胜利 X_prior[ucb_id] = (X_prior[ucb_id] * T_prior[ucb_id] + 1) / (T_prior[ucb_id] + 1) T_prior[ucb_id] += 1 prompt = "Win" if T_prior[ucb_id] > TO / 2: total += 1 break elif _white - _black > pre_white - pre_white and target == 0: # 本方白,白胜利 X_prior[ucb_id] = (X_prior[ucb_id] * T_prior[ucb_id] + 1) / (T_prior[ucb_id] + 1) T_prior[ucb_id] += 1 prompt = "Win" if T_prior[ucb_id] > TO / 2: total += 1 break else: X_prior[ucb_id] = (X_prior[ucb_id] * T_prior[ucb_id]) / (T_prior[ucb_id] + 1) T_prior[ucb_id] += 1 prompt = "Loss" if T_prior[ucb_id] > TO / 2: total += 1 break total += 1 """ if res == 1 and target == 1: # 本方黑,黑胜利 # 获胜概率增加了! X_prior[ucb_id] = (X_prior[ucb_id] * T_prior[ucb_id] + 1) / (T_prior[ucb_id] + 1) # 被访问次数增加了! T_prior[ucb_id] += 1 # 提示获胜 prompt = "Win" # 提早结束,提高效率 # 原因:访问节点次数超过二分之一,不可能再有节点比这个更优了 if T_prior[ucb_id] > end_search_value: total += 1 break elif res == 0 and target == 0: # 本方白,白胜利 X_prior[ucb_id] = (X_prior[ucb_id] * T_prior[ucb_id] + 1) / (T_prior[ucb_id] + 1) T_prior[ucb_id] += 1 prompt = "Win" if T_prior[ucb_id] > end_search_value: total += 1 break else: X_prior[ucb_id] = (X_prior[ucb_id] * T_prior[ucb_id]) / (T_prior[ucb_id] + 1) T_prior[ucb_id] += 1 prompt = "Loss" if T_prior[ucb_id] > end_search_value: total += 1 break total += 1 # 提示一下而已 debug_print("Playout\t" + str(i) + '\t' + util.pos_to_gtppos(util.num_to_pos(out[0][ucb_id])) + "\t" + prompt) """ max_index 它是我要采取的策略! """ max_index = T_prior.index(max(T_prior)) debug_print(_side + ":{:.2f}%".format(X_prior[max_index] * 100)) # UCB完毕,打印一下节点的访问次数 for i in range(config.search_position_num): debug_print("visited: " + util.pos_to_gtppos(util.num_to_pos(out[0][i])) + ":" + str(T_prior[i])) # 再打印一下耗时 debug_print("Time:" + str(time.time() - t)) # debug_print(str(out)) # print pred # print feature[0][2].reshape(1, 361) # return pred.argmax() """ 如果最优秀的评估值小于一个阈值,那么认输 """ if X_prior[max_index] < 0.12: return -1 """ overall_score_max = - 999999 overall_score_index = -1 for i in range(4): overall_score = X_prior[i] * 0.4 + pred[0][out[0][i]] * 0.6 if overall_score > overall_score_max: overall_score_max = overall_score overall_score_index = i """ return out[0][max_index]
def place_stone_num(self, pos): land_posx, land_posy = util.num_to_pos(pos) 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 # 如果是停一手,则做如下操作 """ mistake !!!! 停一手忘记更新棋盘了! """ if land_posx < 0: self.history[current_player].append(pos) self.zob_history.append(self.zob_history[-1]) """ 2019年1月7日01:54:54修补该bug """ """ if current_player == SIDE_BLACK: current_stone = BLACK_STONE opposite_stone = WHITE_STONE else: current_stone = WHITE_STONE opposite_stone = BLACK_STONE """ self.round += 1 return # 先判断是否合法 if self.is_valid_move(util.pos_to_sgf((land_posx, land_posy))) is False: # print 'Invalid!' return False # 如果合法,则做这些操作: """ 1. 减去对方棋串的气 2. 将新的子加入本方的棋串中 2.1 遍历本方所有棋串的气,如果有重合,记录备用 2.2 将这些有重合的都加入这个新的棋串中去 2.3 删除那些重合加入的棋串 2.4 重新计算新串的气 3. 对对面所有没气了的棋串:如果对面没有没气了的棋串,并且本方的气是0,说明自尽,那么对本方这块棋的周围, 3.1 对于每个没气了的棋串的每个子,看上下左右(注意边界) 3.2 上下左右如果有本方的棋子,那么加入一个列表备用 3.3 删除这个棋串 4. 重新生成棋盘 5. 记录的这些黑子,判断属于哪些棋块,对这些棋块重新算气 """ # 合法了的话,棋盘更新 if current_player == SIDE_BLACK: self.board[land_posx][land_posy] = BLACK_STONE current_stone = BLACK_STONE opposite_stone = WHITE_STONE else: self.board[land_posx][land_posy] = WHITE_STONE current_stone = WHITE_STONE opposite_stone = BLACK_STONE # 1. 减去对方棋串的气,并用dead列表记录哪些死透了的棋子 dead = [] for key, value in self.group[opposite_player].items(): assert isinstance(value, Group) value.remove_liberty(num_pos) if value.count_liberty() == 0: dead.append(key) # 遍历本方所有棋串的气,如果有重合,记录备用在merge里面 merge = [] for key, value in self.group[current_player].items(): assert isinstance(value, Group) if value.has_liberty(num_pos): merge.append(key) # 2.2 新建一个棋串,将这些有重合的都加入这个新的棋串中去 self.group[current_player][self.round] = Group(self.round) self.group[current_player][self.round].add_stone(num_pos) # 2.3 删除那些重合加入的棋串 for ids in merge: self.group[current_player][self.round].merge_stone(self.group[current_player][ids]) self.group[current_player].pop(ids) # 2.4 重新计算新串的气(有一个不必要的参数side) self.group[current_player][self.round].recount_liberty(current_player, self.board) # 3 对面所有没气了的棋串,在dead里面,删掉这些子,但是记录一下他们 record_dead_stone = set() for d in dead: for st in self.group[opposite_player][d].stone: record_dead_stone.add(st) posx, posy = util.num_to_pos(st) # 在这里清除了对方的死子 self.board[posx][posy] = EMPTY_STONE # 由于记录了死子的位置,所以看一下它的上下左右,有没有本方的子 # 有的话,记录本方这些子的棋串号 recount_liberty_group = set() for dead_pos in record_dead_stone: posx, posy = util.num_to_pos(dead_pos) for i in range(4): if 0 <= posx + dx[i] < 19 and 0 <= posy + dy[i] < 19: if self.board[posx + dx[i]][posy + dy[i]] == current_stone: for key, value in self.group[current_player].items(): if value.has_stone(util.pos_to_num((posx + dx[i], posy + dy[i]))): recount_liberty_group.add(key) # 删掉这些棋串 for del_ids in dead: self.group[opposite_player].pop(del_ids) # 对需要重新算气的本方棋串重新算气 for rec in recount_liberty_group: self.group[current_player][rec].recount_liberty(current_player, self.board) if current_player == SIDE_BLACK: c_zb_state = zb.STATE_BLACK o_zb_state = zb.STATE_WHITE else: c_zb_state = zb.STATE_WHITE o_zb_state = zb.STATE_BLACK hash = self.zob_history[-1] # 取消本方落子的那个空点 hash = zb.get_new_hash(hash, self.zob_arr, zb.STATE_EMPTY, util.pos_to_num((land_posx, land_posy))) # 本方落子在那个空点 hash = zb.get_new_hash(hash, self.zob_arr, c_zb_state, util.pos_to_num((land_posx, land_posy))) for ds in record_dead_stone: hash = zb.get_new_hash(hash, self.zob_arr, o_zb_state, ds) hash = zb.get_new_hash(hash, self.zob_arr, zb.STATE_EMPTY, ds) self.zob_history.append(hash) self.history[current_player].append(pos) # self.print_board() self.round += 1 return True
def generate_fast(self): features = np.zeros((1, 8, 19, 19), dtype=np.int8) current_stone = self._current_stone() opposite_stone = self._opposite_stone() """本方棋子的位置,和对方棋子的位置2/16 """ features[0][0] = (self.board == current_stone) + 0 features[0][1] = (self.board == opposite_stone) + 0 """5个气位的特征,外加两个征子的特征 7,8,9,10,11,12,13/16 """ for key, value in self.group[self._current_player()].items(): if value.count_liberty() == 1: for st in value.stone: x, y = util.num_to_pos(st) features[0][2][x][y] = 1 elif value.count_liberty() == 2: for st in value.stone: x, y = util.num_to_pos(st) features[0][3][x][y] = 1 elif value.count_liberty() == 3: for st in value.stone: x, y = util.num_to_pos(st) features[0][4][x][y] = 1 elif value.count_liberty() == 4: for st in value.stone: x, y = util.num_to_pos(st) features[0][5][x][y] = 1 elif value.count_liberty() >= 5: for st in value.stone: x, y = util.num_to_pos(st) features[0][6][x][y] = 1 for key, value in self.group[self._opposite_player()].items(): if value.count_liberty() == 1: for st in value.stone: x, y = util.num_to_pos(st) features[0][2][x][y] = 1 elif value.count_liberty() == 2: for st in value.stone: x, y = util.num_to_pos(st) features[0][3][x][y] = 1 elif value.count_liberty() == 3: for st in value.stone: x, y = util.num_to_pos(st) features[0][4][x][y] = 1 elif value.count_liberty() == 4: for st in value.stone: x, y = util.num_to_pos(st) features[0][5][x][y] = 1 elif value.count_liberty() >= 5: for st in value.stone: x, y = util.num_to_pos(st) features[0][6][x][y] = 1 if len(self.history[self._opposite_player()]) > 0 and self.history[self._opposite_player()][-1] >= 0: x, y = util.num_to_pos(self.history[self._opposite_player()][-1]) features[0][7][x][y] = 1 return features
def generate(self): features = np.zeros((1, 16, 19, 19), dtype=np.int8) current_stone = self._current_stone() opposite_stone = self._opposite_stone() """本方棋子的位置,和对方棋子的位置2/16 """ features[0][0] = (self.board == current_stone) + 0 features[0][1] = (self.board == opposite_stone) + 0 for i in range(361): px, py = util.num_to_pos(i) if self.is_valid_move_numpos(i) == 1: """空点的位置3/16 """ features[0][2][px][py] = 1 elif self.is_valid_move_numpos(i) == -1: """如果是打劫,那么+打劫位置4/16 """ features[0][12][px][py] = 1 eye = self.is_eye(i) if eye == 2: """对于本方来说,极有可能成为眼位的空点5/16 """ features[0][10][px][py] = 1 elif eye == 3: """已经是眼位的点6/16 """ features[0][11][px][py] = 1 """5个气位的特征,外加两个征子的特征 7,8,9,10,11,12,13/16 """ for key, value in self.group[self._current_player()].items(): if value.count_liberty() == 1: """1气要做征子判断!对于本方的1气棋子来说, 先自己走,然后让对方走 """ for st in value.stone: x, y = util.num_to_pos(st) if self.judge_ladder(key) == 1: features[0][13][x][y] = 1 features[0][3][x][y] = 1 elif value.count_liberty() == 2: for st in value.stone: x, y = util.num_to_pos(st) features[0][4][x][y] = 1 elif value.count_liberty() == 3: for st in value.stone: x, y = util.num_to_pos(st) features[0][5][x][y] = 1 elif value.count_liberty() == 4: for st in value.stone: x, y = util.num_to_pos(st) features[0][6][x][y] = 1 elif value.count_liberty() >= 5: for st in value.stone: x, y = util.num_to_pos(st) features[0][7][x][y] = 1 for key, value in self.group[self._opposite_player()].items(): if value.count_liberty() == 1: """对方的1气也做征子判断,但是本方先让一手,然后看征子情况 """ for st in value.stone: x, y = util.num_to_pos(st) if self.judge_ladder_oppo(key) == 1: features[0][14][x][y] = 1 features[0][3][x][y] = 1 elif value.count_liberty() == 2: for st in value.stone: x, y = util.num_to_pos(st) features[0][4][x][y] = 1 elif value.count_liberty() == 3: for st in value.stone: x, y = util.num_to_pos(st) features[0][5][x][y] = 1 elif value.count_liberty() == 4: for st in value.stone: x, y = util.num_to_pos(st) features[0][6][x][y] = 1 elif value.count_liberty() >= 5: for st in value.stone: x, y = util.num_to_pos(st) features[0][7][x][y] = 1 if len(self.history[self._opposite_player()]) > 0 and self.history[self._opposite_player()][-1] >= 0: x, y = util.num_to_pos(self.history[self._opposite_player()][-1]) features[0][9][x][y] = 1 features[0][8][x][y] = 1 if len(self.history[self._opposite_player()]) > 1 and self.history[self._opposite_player()][-2] >= 0: x, y = util.num_to_pos(self.history[self._opposite_player()][-2]) features[0][8][x][y] = 1 if len(self.history[self._current_player()]) > 0 and self.history[self._current_player()][-1] >= 0: x, y = util.num_to_pos(self.history[self._current_player()][-1]) features[0][8][x][y] = 1 if self._current_player() == SIDE_BLACK: features[0][15] = np.ones((19, 19), dtype=np.int8) return features
def is_eye(self, pos): current_stone = self._current_stone() opp_stone = self._opposite_stone() # 先判断旁边的四个角 pos_x, pos_y = util.num_to_pos(pos) if self.board[pos_x][pos_y] != EMPTY_STONE: return EYE_NOT if pos == 0 and self.board[0][1] == self.board[1][0] == self.board[1][1] == current_stone: return EYE_MUST if pos == 18 and self.board[0][17] == self.board[1][17] == self.board[1][18] == current_stone: return EYE_MUST if pos == 342 and self.board[17][0] == self.board[17][1] == self.board[18][1] == current_stone: return EYE_MUST if pos == 360 and self.board[18][17] == self.board[17][17] == self.board[17][18] == current_stone: return EYE_MUST if pos_x == 0 and 0 < pos_y < 18: cnt = 0 if self.board[pos_x][pos_y - 1] == current_stone: cnt += 1 elif self.board[pos_x][pos_y - 1] == opp_stone: cnt -= 1 if self.board[pos_x][pos_y + 1] == current_stone: cnt += 1 elif self.board[pos_x][pos_y + 1] == opp_stone: cnt -= 1 if self.board[pos_x + 1][pos_y - 1] == current_stone: cnt += 1 elif self.board[pos_x + 1][pos_y - 1] == opp_stone: cnt -= 1 if self.board[pos_x + 1][pos_y] == current_stone: cnt += 1 elif self.board[pos_x + 1][pos_y] == opp_stone: cnt -= 1 if self.board[pos_x + 1][pos_y + 1] == current_stone: cnt += 1 elif self.board[pos_x + 1][pos_y + 1] == opp_stone: cnt -= 1 if cnt == 5: return EYE_MUST if cnt == 4: return EYE_HIGH_PRO """ if pos_x == 18 and 0 < pos_y < 18: if self.board[pos_x][pos_y - 1] == self.board[pos_x][pos_y + 1] == self.board[pos_x - 1][pos_y - 1] \ == self.board[pos_x - 1][pos_y] == self.board[pos_x - 1][pos_y + 1] == current_stone: return EYE_MUST """ if pos_x == 18 and 0 < pos_y < 18: cnt = 0 if self.board[pos_x][pos_y - 1] == current_stone: cnt += 1 elif self.board[pos_x][pos_y - 1] == opp_stone: cnt -= 1 if self.board[pos_x][pos_y + 1] == current_stone: cnt += 1 elif self.board[pos_x][pos_y + 1] == opp_stone: cnt -= 1 if self.board[pos_x - 1][pos_y - 1] == current_stone: cnt += 1 elif self.board[pos_x - 1][pos_y - 1] == opp_stone: cnt -= 1 if self.board[pos_x - 1][pos_y] == current_stone: cnt += 1 elif self.board[pos_x - 1][pos_y] == opp_stone: cnt -= 1 if self.board[pos_x - 1][pos_y + 1] == current_stone: cnt += 1 elif self.board[pos_x - 1][pos_y + 1] == opp_stone: cnt -= 1 if cnt == 5: return EYE_MUST if cnt == 4: return EYE_HIGH_PRO """ if pos_y == 0 and 0 < pos_x < 18: if self.board[pos_x - 1][pos_y] == self.board[pos_x + 1][pos_y] == self.board[pos_x - 1][pos_y + 1] \ == self.board[pos_x][pos_y + 1] == self.board[pos_x + 1][pos_y + 1] == current_stone: return EYE_MUST """ if pos_y == 0 and 0 < pos_x < 18: cnt = 0 if self.board[pos_x - 1][pos_y] == current_stone: cnt += 1 elif self.board[pos_x - 1][pos_y] == opp_stone: cnt -= 1 if self.board[pos_x + 1][pos_y] == current_stone: cnt += 1 elif self.board[pos_x + 1][pos_y] == opp_stone: cnt -= 1 if self.board[pos_x - 1][pos_y + 1] == current_stone: cnt += 1 elif self.board[pos_x - 1][pos_y + 1] == opp_stone: cnt -= 1 if self.board[pos_x][pos_y + 1] == current_stone: cnt += 1 elif self.board[pos_x][pos_y + 1] == opp_stone: cnt -= 1 if self.board[pos_x + 1][pos_y + 1] == current_stone: cnt += 1 elif self.board[pos_x + 1][pos_y + 1] == opp_stone: cnt -= 1 if cnt == 5: return EYE_MUST if cnt == 4: return EYE_HIGH_PRO if pos_y == 18 and 0 < pos_x < 18: cnt = 0 if self.board[pos_x - 1][pos_y] == current_stone: cnt += 1 elif self.board[pos_x - 1][pos_y] == opp_stone: cnt -= 1 if self.board[pos_x + 1][pos_y] == current_stone: cnt += 1 elif self.board[pos_x + 1][pos_y] == opp_stone: cnt -= 1 if self.board[pos_x - 1][pos_y - 1] == current_stone: cnt += 1 elif self.board[pos_x - 1][pos_y - 1] == opp_stone: cnt -= 1 if self.board[pos_x][pos_y - 1] == current_stone: cnt += 1 elif self.board[pos_x][pos_y - 1] == opp_stone: cnt -= 1 if self.board[pos_x + 1][pos_y - 1] == current_stone: cnt += 1 elif self.board[pos_x + 1][pos_y - 1] == opp_stone: cnt -= 1 if cnt == 5: return EYE_MUST if cnt == 4: return EYE_HIGH_PRO if 0 < pos_x < 18 and 0 < pos_y < 18: cnt_beside = 0 cnt_not_beside = 0 score = 0.0 for i in range(4): if self.board[pos_x + dx[i]][pos_y + dy[i]] == current_stone: cnt_beside += 1 score += 2.5 elif self.board[pos_x + dx[i]][pos_y + dy[i]] == opp_stone: score -= 4 for i in range(4): if self.board[pos_x + kdx[i]][pos_y + kdy[i]] == current_stone: cnt_not_beside += 1 score += 1 elif self.board[pos_x + kdx[i]][pos_y + kdy[i]] == opp_stone: score -= 2 if cnt_beside == 4 and cnt_not_beside >= 3: return EYE_MUST if score > 8: return EYE_HIGH_PRO return EYE_NOT