def _start_new_game() -> OthelloLogic.Game: """ Asks the user for a default or custom gameboard; if 'default' is chosen, options are an 8x8 board, most discs wins, black starts, and white is in the top-left corner of the starting layout; Else, prompts the user for custom options :return: Game object """ while True: boardtype = input('[Default] or [custom] board?: ').strip().lower() if boardtype == 'default': return OthelloLogic.Game() elif boardtype == 'custom': rows = int( _get_game_option_input( 'rows', ['4', '6', '8', '10', '12', '14', '16'])) cols = int( _get_game_option_input( 'cols', ['4', '6', '8', '10', '12', '14', '16'])) starting_player = _get_game_option_input('starting player', ['black', 'white']) corner_start_player = _get_game_option_input( 'corner color', ['black', 'white']) win_type = _get_game_option_input('win type', ['most', 'least']) return OthelloLogic.Game(rows, cols, win_type, starting_player, corner_start_player) else: print('Invalid input.')
def isGameEnd(board): """ゲームが終了したかどうか判定する Args: board ${1:arg1} Returns: bool $0 """ boardSize = len(board) currentPiece = len([cell for line in board for cell in line if cell != 0]) # 全てのマスが埋まった場合 if currentPiece == boardSize**2: return True # 最終手で最後の人マスを打てる場合 if currentPiece == (boardSize**2) - 1: if OthelloLogic.getMoves(board, 1, boardSize) != []: return False # 双方打つ手なし(互いにパス) nextBoard = deepcopy(board) if OthelloLogic.getMoves(nextBoard, 1, boardSize) == []: if OthelloLogic.getMoves(nextBoard, -1, boardSize) == []: return True return False
def before_complete(board, moves, turn, player, end_turn): tmp_board = copy.deepcopy(board) if len(moves) == 0: player *= -1 moves = Ol.getMoves(board, player, size=8) if len(moves) == 0: return None, weight_check(board) ans_move = moves[0] if turn == 60 or turn == end_turn: next_board = Ol.execute(tmp_board, ans_move, player, size=8) return ans_move, weight_check(next_board) ans_weight = -1000 sum_weight = 0 for move in moves: next_board = Ol.execute(tmp_board, move, player, size=8) next_moves = Ol.getMoves(next_board, player * -1, size=8) next_move, next_weight = before_complete(next_board, next_moves, turn + 1, player * -1, end_turn) if ans_weight < next_weight: ans_weight = next_weight ans_move = move sum_weight += next_weight ave_weight = float(sum_weight / len(moves)) if player == 1: return ans_move, ans_weight else: return ans_move, ave_weight
def complete(board, moves, turn, player): tmp_board = copy.deepcopy(board) if len(moves) == 0: player *= -1 moves = Ol.getMoves(board, player, 8) if len(moves) == 0: return None, win_rate(board) ans_move = moves[0] if turn == 60: next_board = Ol.execute(tmp_board, ans_move, player, 8) return ans_move, win_rate(next_board) w_rate = 0 l_rate = 1 sum_rate = 0 for move in moves: next_board = Ol.execute(tmp_board, move, player, 8) next_moves = Ol.getMoves(next_board, player * -1, 8) next_move, next_rate = complete(next_board, next_moves, turn + 1, player * -1) if w_rate < next_rate: w_rate = next_rate ans_move = move if l_rate > next_rate: l_rate = next_rate sum_rate += next_rate ave_rate = float(sum_rate / len(moves)) if player == 1: return ans_move, w_rate else: return None, ave_rate
def open_rate_exception(board, moves): message = "open_rate_exception: success!" danger = [ [1, 1], [1, 6], [6, 1], [6, 6] ] list_first = [ [0, 0], [7, 0], [7, 7], [0, 7] ] ans_move = moves[0] success_frag = 0 for move in moves: if move in danger: continue tmp_board = copy.deepcopy(board) next_board = Ol.execute(tmp_board, move, player=1, size=8) next_moves = Ol.getMoves(next_board, player=-1, size=8) for next_move in next_moves: if next_move in list_first: continue ans_move = move success_frag = 1 if success_frag == 0: message = "open_rate_exception: failure..." return ans_move, message
def getAction(board, moves): ans = moves[0] tmp = 0 for move in moves: next_board = ol.execute(board, move, 1, 8) next_moves = ol.getMoves(next_board, -1, 8) if tmp < len(next_moves): ans = move return ans
def getAction(board, moves): # オセロ番のサイズを変数に格納 board_size = len(board[0]) # オセロ盤の角の座標を配列に格納 squares = [ [0, board_size - 1], [board_size - 1, 0], [0, board_size - 1], [board_size - 1, board_size - 1], ] # もしも角がとれるなら角に手を打つ # for文で角の座標が引数moves内に存在するかどうかを調べる for s in squares: if s in moves: index = moves.index(s) return moves[index] # 相手の合法手の最小数を格納する変数(最小値なので初期値は適当に大きく) min_enemy_moves_length = 100 # 返す手のindex(配列の添字) index = 0 # for文で全ての手を打ってみる for m in moves: # 選択した手を打つ関数 # 関数:execute # 返り値:盤面の状況(ちょうどこのOthelloActionの引数であるboardと同じ感じ) # 引数:board:(盤面の状態),move:打つ手(moves配列の中身),player:打つプレイヤー(1だと自分,-1だと相手),size:オセロ盤のサイズ # 引数として渡すboardにはdeepcopy関数を使用してください!! # deepcopyをしないでboardを渡すとpythonの仕様でおかしなことになります(設計が悪かったですごめんなさい) # 詳しくはオブジェクトIDで調べてもらえば...! board_next = OthelloLogic.execute(copy.deepcopy(board), m, 1, board_size) # 自分の手を打った後の相手の合法手を取得する関数 # 関数:getMoves # 返り値:moves(選択したプレイヤーの合法手配列) # 引数:board(盤面の状態),player(どちらのプレイヤーの合法手を取得するか、1だと自分,-1だと相手,size:オセロ盤の大きさ) moves_next = OthelloLogic.getMoves(copy.deepcopy(board_next), -1, board_size) # 取得した相手の合法手の数が現在の最小値よりも低ければ最小値を更新 if min_enemy_moves_length > len(moves_next): min_enemy_moves_length = len(moves_next) # 返す手のindexを更新 index = moves.index(m) # 最小値の配列indexを返却して手を実行 return moves[index]
def complete(board, moves, turn, player): tmp_board = copy.deepcopy(board) if len(moves) == 0: player *= -1 moves = Ol.getMoves(board, player, 8) if len(moves) == 0: rate = win_rate(board) return None, rate, rate ans_move = moves[0] if turn == 60: next_board = Ol.execute(tmp_board, ans_move, player, 8) rate = win_rate(next_board) return ans_move, rate, rate w_rate = 0 l_rate = 1 sum_rate = 0 ave_move = moves[0] ave_rate_max = 0 for move in moves: # tmp_board = copy.deepcopy(board) # copy.deepcopyよりforで回した方が早い? for h in range(8): for w in range(8): tmp_board[h][w] = board[h][w] next_board = Ol.execute(tmp_board, move, player, 8) next_moves = Ol.getMoves(next_board, player * -1, 8) next_move, next_rate, next_ave_rate = complete(next_board, next_moves, turn + 1, player * -1) if w_rate < next_rate: w_rate = next_rate ans_move = move if l_rate > next_rate: l_rate = next_rate if ave_rate_max < next_ave_rate: ave_move = move ave_rate_max = next_ave_rate sum_rate += next_ave_rate ave_rate = float(sum_rate / len(moves)) if player == 1: if w_rate == 0: return ave_move, w_rate, ave_rate else: return ans_move, w_rate, ave_rate else: return None, l_rate, ave_rate
def evaluationFunc(board, target, size): nextBoard = OthelloLogic.execute(copy.deepcopy(board), target, 1, size) boardScore = 0 for i in range(8): for j in range(8): boardScore = boardScore + util.getDistance([4, 4], [i, j]) * board[i][j] return boardScore
def complete(board, moves, turn, player): tmp_board = copy.deepcopy(board) if len(moves) == 0: player *= -1 moves = Ol.getMoves(board, player, 8) if len(moves) == 0: rate = win_rate(board) return None, rate ans_move = moves[0] if turn == 60: next_board = Ol.execute(tmp_board, ans_move, player, 8) rate = win_rate(next_board) return ans_move, rate w_rate = 0 l_rate = 1 for move in moves: # tmp_board = copy.deepcopy(board) # copy.deepcopyよりforで回した方が早い? for h in range(8): for w in range(8): tmp_board[h][w] = board[h][w] next_board = Ol.execute(tmp_board, move, player, 8) next_moves = Ol.getMoves(next_board, player * -1, 8) next_move, next_rate = complete(next_board, next_moves, turn + 1, player * -1) # 2021/01/09追加 if player == 1 and next_rate == 1: return move, next_rate elif player == -1 and next_rate == 0: return None, next_rate if w_rate < next_rate: w_rate = next_rate ans_move = move if l_rate > next_rate: l_rate = next_rate if player == 1: return ans_move, w_rate else: return None, l_rate
def evalutionTree(board, player, boardSize, currentDepth=1): moves = OthelloLogic.getMoves(board, player, boardSize) # パスの時 if moves == []: return evalutionTree(deepcopy(board), player * -1, boardSize) scores = [] for move in moves: nextBoard = deepcopy(board) OthelloLogic.execute(nextBoard, move, player, boardSize) if util.isGameEnd(nextBoard): currentPlayer = 1 if currentDepth % 2 == 1 else -1 scores.append( util.getBoardScore(deepcopy(nextBoard), currentPlayer)) else: scores.append( evalutionTree(nextBoard, player * -1, boardSize, currentDepth + 1)) return min(scores)
def open_rate(board, moves): danger = [[1, 0], [1, 1], [0, 1], [6, 0], [7, 1], [6, 1], [7, 6], [6, 6], [6, 7], [1, 7], [0, 6], [1, 6]] list_first = [[0, 0], [7, 0], [7, 7], [0, 7]] del_ls = [] for i in range(4): if board[list_first[i][0]][list_first[i][1]] == 1: del_ls.append(i) for i in del_ls: for j in range(i * 3, (i * 3) + 3): list_first.append(danger[j]) del_ls.sort(reverse=True) for i in del_ls: del danger[(i * 3):((i * 3) + 3)] vectors = [[-1, -1], [0, -1], [1, -1], [-1, 0], [1, 0], [-1, 1], [0, 1], [1, 1]] ans_move = moves[0] ans_rate = 100 for move in moves: if move in danger: continue elif move in list_first: return move, "great!" rate = 0 zero_board = [[0 for _ in range(8)] for _ in range(8)] tmp_board = copy.deepcopy(board) next_board = Ol.execute(tmp_board, move, player=1, size=8) for h in range(8): for w in range(8): if board[h][w] == -1 and next_board[h][w] == 1: for vec in vectors: moved_index = [int(h + vec[0]), int(w + vec[1])] if 0 <= moved_index[0] <= 7 and 0 <= moved_index[ 1] <= 7: zero_board[moved_index[0]][moved_index[1]] = 1 for h in range(8): for w in range(8): if board[h][w] == 0 and zero_board[h][w] == 1: rate += 1 if rate < ans_rate: ans_rate = rate ans_move = move if ans_rate == 100: return open_rate_exception(board, moves) else: return ans_move, ans_rate
def _read_information(self): '''reads in the information to create the gamestate from the information module''' self._info = Information() self._info.start() self._rows = self._info.rows self._columns = self._info.columns self._starting_color = self._info.starting_color self._seed_color = self._info.seed_color self._win_type = self._info.win_type self.gamestate = OthelloLogic.Gameboard(self._rows, self._columns, self._starting_color, self._seed_color, self._win_type)
def lern(board, moves): """ Args: board arg1 Returns: """ boardSize = len(board) minScore = boardSize**2 minScoreMove = moves[0] # 最終手の場合探索を行わない if util.getOnBoardPieces(board) == (boardSize**2) - 1: moves = OthelloLogic.getMoves(board, 1, boardSize) return moves[0] # 自分がパスで相手は打てる時 if len(moves) == 1: return moves[0] if len(moves) == 0: if util.isGameEnd(deepcopy(board)): return moves[0] params = [] for move in moves: params.append((deepcopy(board), move, boardSize)) results = [] with ProcessPoolExecutor() as executor: results = list(executor.map(evalFunc, params)) # min for i in range(len(results)): if results[i] <= minScore: minScore = results[i] minScoreMove = moves[i] pprint(results) pprint(moves) return minScoreMove
def ab(board, moves, lim, a, b, side): # print(moves) if lim == 0: return calc_eval_score(board) """ if len(moves) == 0: pass eval = -ab(board) """ for move in moves: # print(move) nb = get_next_board(board, move, -side) enemy_hand = ol.getMoves(nb, -SIDE, SIZE) eval = -ab(board, enemy_hand, lim - 1, -b, -a, -side) a = max(a, eval) if a >= b: return a return a
import OthelloAction import OthelloLogic #sizeを変更することでテストプレイする盤面の大きさを変更できます。 #size = 4 #size = 6 size = 8 board = [[0 for i in range(size)] for j in range(size)] board[int(size/2)-1][int(size/2)-1] = 1; board[int(size/2)][int(size/2)-1]=-1; board[int(size/2)-1][int(size/2)]=-1; board[int(size/2)][int(size/2)]=1; player = -1 moves = OthelloLogic.getMoves(board,player,size) while(True): if(player == -1): action = OthelloAction.getAction(OthelloLogic.getReverseboard(board),moves) else: action = OthelloAction.getAction(board,moves) if(not (action in moves)): print(board) print('合法手ではない手が打たれました' + action) exit() board = OthelloLogic.execute(board,action,player,size) OthelloLogic.printBoard(board) print('現在の合法手一覧') print(moves) moves = OthelloLogic.getMoves(board,player*-1,size) if(len(moves) == 0):
print('エラーが発生しました。') exit() data = r.json() roomid = data['id'] player = data['player'] board = [] payload = {} if (player == 1): payload = {'player': player} r = requests.post(base_url + "wait_for_player/" + roomid, data=payload, headers=headers) data = r.json() OthelloLogic.printBoard(json.loads(data['board'])) board = json.loads(data['board']) moves = json.loads(data['moves']) else: OthelloLogic.printBoard(json.loads(data['board'])) rev_board = json.loads(data['board']) board = json.loads(data['board']) for x in range(len(rev_board)): for y in range(len(rev_board)): board[x][y] = rev_board[x][y] * -1 moves = json.loads(data['moves']) action = json.dumps(OthelloAction.getAction(board, moves)) payload = {'action': action, 'player': player} while (True):
def evalFunc(params): (board, move, boardSize) = params OthelloLogic.execute(board, move, 1, boardSize) return evalutionTree(board, -1, boardSize)
def middle_check(board, moves): left_ls = [ [0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], ] right_ls = [ [7, 0], [7, 1], [7, 2], [7, 3], [7, 4], [7, 5], [7, 6], [7, 7], ] up_ls = [ [0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0], [6, 0], [7, 0], ] down_ls = [ [0, 7], [1, 7], [2, 7], [3, 7], [4, 7], [5, 7], [6, 7], [7, 7], ] ls_manager = [up_ls, down_ls, left_ls, right_ls] danger = [ [1, 0], [1, 1], [0, 1], [6, 0], [7, 1], [6, 1], [7, 6], [6, 6], [6, 7], [1, 7], [0, 6], [1, 6] ] list_first = [ [0, 0], [7, 0], [7, 7], [0, 7] ] del_ls = [] for i in range(4): if board[list_first[i][0]][list_first[i][1]] == 1: del_ls.append(i) for i in del_ls: for j in range(i * 3, (i * 3) + 3): list_first.append(danger[j]) del_ls.sort(reverse=True) for i in del_ls: del danger[(i * 3):((i * 3) + 3)] for move in moves: if move in danger: continue elif move in list_first: return move, "middle_check!" for ls in ls_manager: if move in ls: tmp_board = copy.deepcopy(board) before_execute = for_middle_check(board, ls) next_board = Ol.execute(tmp_board, move, player=1, size=8) after_execute = for_middle_check(next_board, ls) next_moves = Ol.getMoves(next_board, player=-1, size=8) if before_execute + 1 < after_execute: frag = 0 for next_move in next_moves: if next_move in ls: frag = 1 if frag == 1: continue else: return move, "middle_check!" elif before_execute + 1 == after_execute: enemy_stone = 0 for i in ls: if board[i[1]][i[0]] == -1: enemy_stone += 1 if enemy_stone == 0: return move, "middle_check!" return open_rate(board, moves)