def move(self, board, last_move, max_time_to_move=1000): """This is the most important method: the agent will get: 1) the current state of the board 2) the last move by the opponent 3) the available moves you can play (this is a special service we provide ;-) ) 4) the maximimum time until the agent is required to make a move in milliseconds [diverging from this will lead to disqualification]. """ valid_moves = gomoku.valid_moves(board) time_deadline = time.time() + ( max_time_to_move * 0.90 / 1000 ) # Deadline is 99% of the time to move in ms in ns. Can be optimized # If only 1 move is possible, do that move if (len(valid_moves) == 1): return valid_moves[0] currentGame = gomoku.gomoku_game(19, copy.deepcopy(board), self.play) # Current game board rootNode = Node(None, currentGame, last_move) # Current Rootnode(active gamestate) while (time.time() < time_deadline): ## Calculate new move newLeaf = findSpotToExpand(rootNode) ## Play until game ends for that move gameresult = rollout(newLeaf) ## Calculate score for that move backupValue(gameresult, newLeaf) # Find best child #-- Met de code hieronder zou die als die een fout maakt, alsnog een slimme keuze moeten maken. Dit was tijdelijke code, maar maakt hem ook dommer? # bestChild = None # while len(rootNode.children) != 0: # bestChild = rootNode.findBestChild() # if not bestChild.last_move in valid_moves: # rootNode.children.remove(bestChild) # print("Current best child move is invalid") # else: # break # if not bestChild.last_move in valid_moves: # print("Chosen best child move is invalid") # return valid_moves[0] # If the best child is invalid for some reason, just use a random valid move bestChild = rootNode.findBestChild() if not bestChild.last_move in valid_moves: print("Chosen best child move is invalid") return valid_moves[0] print("Supplied Valid Moves: {}".format(len(valid_moves))) print("Simulated Valid Moves: {}".format(len( currentGame.valid_moves()))) gomoku.prettyboard(currentGame.board) self.play += 2 return bestChild.last_move
def new_game(self, black_): self.black = black_ if black_: self.ply = 1 else: self.ply = 2 if self.n_root is None: self.game = gomoku.gomoku_game(ply_=self.ply) # Create a new game
def rollout(self, nLeaf): me = True game = gomoku.gomoku_game(19, nLeaf.board) lastMove = copy.deepcopy(nLeaf.last_move) validMoves = copy.deepcopy(nLeaf.valid_moves) while (lastMove is None or (not game.check_win(lastMove))) and validMoves: move = random.choice(validMoves) game.move(move) validMoves.remove(move) me = not me lastMove = move if not validMoves: return 0.5 return me
def move(self, board, last_move, valid_moves, max_time_to_move=1000): """This is the most important method: the agent will get: 1) the current state of the board 2) the last move by the opponent 3) the available moves you can play (this is a special service we provide ;-) ) 4) the maximimum time until the agent is required to make a move in milliseconds [diverging from this will lead to disqualification]. """ t = time.time() # print("Move > Start") if (len(valid_moves) == 1): return valid_moves[0] aGame = gomoku.gomoku_game(19, board, self.ply) root = TreeNode(aGame, None, last_move) # print("Move > Loop") while time.time() < t + (max_time_to_move * 0.99 / 1000): # print(" Loop > Expand ") leaf = findSpotToExpand(root) # print(" Loop > Rollout ") val = rollout(leaf) # print(" Loop > Backup ") backupValue(leaf, val) bestChild = root.bestChild() self.ply += 2 if not bestChild.move in valid_moves: # print("Move > move is invalid, finding new one") bestChildren = root.bestChildren() if (len(bestChildren) <= 1): if bestChildren[0] not in valid_moves: raise IOError i = 0 while bestChild.move not in valid_moves: # print("Move > move {} is invalid".format(i)) # print("{}/{}".format(len(bestChildren), i)) bestChild = bestChildren[i] i += 1 if (len(bestChildren) <= i): # print("Move > No valid moves in best children!!!") raise InterruptedError if bestChild.move in valid_moves: root.gamestate.move(bestChild.move) # print("Move > Done") return bestChild.move else: # print("INVAL MOVE!") raise InterruptedError
def findSpotToExpand(self, nRoot): game = gomoku.gomoku_game(19, nRoot.board) if not nRoot.valid_moves and not nRoot.children: return nRoot if nRoot.valid_moves: move = nRoot.valid_moves[0] game.move(move) nRoot.valid_moves.remove(move) color = not nRoot.color nChild = Node(game.current_board(), nRoot.valid_moves, color, move, nRoot) nRoot.children.append(nChild) return nChild nChild = nRoot.children[0] for child in nRoot.children: if child.UCT() > nChild.UCT(): nChild = child return self.findSpotToExpand(nChild)
def findSpotToExpand(self, node): # if node is terminal(game finished). if len(node.valid_moves) == 0: return node # a node is not fully expanded if there are more valid_moves than children. if len(node.children) < len(node.valid_moves): newBoard = gomoku.gomoku_game(19, node.board) # create a new board newMove = node.valid_moves[len(node.children)] # get the next move newNode = Node(newBoard, node.valid_moves, newMove) # create new node to expand newNode.parent = node node.children.append(newNode) # add node to node's children return newNode # if all possible children have been added to a node (all valid moves have been visited), # we need to select one of the children of the node with the highest uct value. if len(node.children) >= len(node.valid_moves): bestChild = self.bestChild(node) # get the best child return self.findSpotToExpand(bestChild) # expand on the best child
def rollout(self, leafnode): if leafnode is not None: # print("rolling out: ") # lm = leafnode.last_move simgame = gomoku.gomoku_game(19, leafnode.board) while leafnode.valid_moves: candidate = random.choice(leafnode.valid_moves) lm = candidate # print(candidate) simgame.move(candidate) leafnode.valid_moves.remove(candidate) if simgame.check_win(lm): return 1.0 if len(simgame.valid_moves()) == 0: # print("DRAW") return 0.5 else: return 0 return 0 else: print("LEAFNOTE IS NONE ??????????????????/")
def findSpotToExpand(self, nRoot): # print("explaning", nRoot) # if this node is terminal, end # print("findspot") if len(nRoot.valid_moves) == 0: return nRoot # # if there are nodes to make if len(nRoot.children) < len(nRoot.valid_moves): game = gomoku.gomoku_game(19, nRoot.board) move = nRoot.valid_moves[len(nRoot.children)] game.move(move) NewNode = Node(nRoot.board, move, nRoot.valid_moves, nRoot.color) NewNode.parent = nRoot nRoot.children.append(NewNode) return NewNode if len(nRoot.children) >= len(nRoot.valid_moves): # print(id(nRoot)) # print(nRoot.children[1].valid_moves) bestc = nRoot.best_child(nRoot) # print("CALLING with", len(nRoot.children)) # print("VMS", len(nRoot.valid_moves)) return self.findSpotToExpand(bestc)
def rollout(self, node): if node is not None: # checks if the node is not empty game = gomoku.gomoku_game( 19, node.board) # create a game with the nodes board while node.valid_moves: # loop as long as there are still valid moves randomMove = random.choice( node.valid_moves ) # get a random move out of the possible valid moves print(node.valid_moves) game.move(randomMove) # do the random move node.valid_moves.remove( randomMove) # remove the random move we just did if game.check_win( randomMove ): # check if we have won with the random move return 1.0 # return 1 if we win if len(game.valid_moves() ) == 0: # check if there are still valid moves return 0.5 # nobody wins it is a draw else: # if there are still valid moves but we did not win return 0 # return 0 if we lose return 0 else: print("------fault")
def play_competition(self, maxtime_per_move=1000, tolerance=0.05): """This method runs the actual competition between the registered players. Each player plays each other player twice: once with black and once with white.""" self.results = [] mtime = maxtime_per_move * ( 1.0 + tolerance) * 1000000 #operational maxtime in nanoseconds for i in range(len(self.players)): self.results.append( [0.0] * len(self.players)) #set the results matrix to all zeroes for i in range(len(self.players)): for j in range(len(self.players)): if (i == j): continue #players do not play themselves self.players[i].new_game(True) #player i is black self.players[j].new_game(False) # player j is white game = gomoku.gomoku_game( bsize_=self.bsize) #initialise the game over = False while not over: if game.ply % 2 == 1: #black to move current_player = self.players[i] pid = i pid_other = j else: #white to move current_player = self.players[j] pid = j pid_other = i start_time = time.time_ns() move = current_player.move( game.current_board(), game.previous_move, game.valid_moves(), max_time_to_move=maxtime_per_move) stop_time = time.time_ns() #print(str((stop_time-start_time)/1000000)+"/"+str(maxtime_per_move*(1+tolerance))) ok, win = game.move( move ) #perform the move, and obtain whether the move was valid (ok) and whether the move results in a win if (stop_time - start_time) > mtime: #player who made the illegal move should be disqualified. This needs to be done manually. print( "disqualified for exceeding maximum time per move: player " + str(pid)) if not ok: #player who made the illegal move should be disqualified. This needs to be done manually. print("disqualified for illegal move: player " + str(pid)) print("on board: ") gomoku.prettyboard(game.current_board()) print("trying to play: (" + str(move[0]) + "," + str(move[1]) + ")") if game.ply % 2 == 1: print("as black") else: print("as white") if win: over = True self.results[pid][pid_other] += 1 elif len(game.valid_moves()) == 0: #if there are no more valid moves, the board is full and it's a draw over = True self.results[pid][pid_other] += 0.5 self.results[pid_other][pid] += 0.5
over = True self.results[pid][pid_other] += 1 elif len(game.valid_moves()) == 0: #if there are no more valid moves, the board is full and it's a draw over = True self.results[pid][pid_other] += 0.5 self.results[pid_other][pid] += 0.5 def print_scores(self): """This method prints the results of the competition to sysout""" i = 0 for line in self.results: for res in line: print(str(res), end=" ") print("[" + self.players[i].id() + ", " + str(sum(line)) + "]") i += 1 ##Now follows the main script for running the competition # At present the competition consists of just three random dummy players playing each other # When the students submit a player file, they should be entered one by one. game = gomoku.gomoku_game() player = random_player.random_dummy_player() player2 = random_player.random_dummy_player() player3 = random_player.random_dummy_player() comp = competition() comp.register_player(player) comp.register_player(player2) comp.register_player(player3) comp.play_competition() comp.print_scores()