Esempio n. 1
0
def findSpotToExpand(node, valid_moves):
    """
    Finds a new child(a new gamestate associated with a move) for the current node. 
    Alternatively, if all children are already given, calculate the children for the best child.
    """
    # print("Find spot to expand: ", node, " valid moves: ", valid_moves)
    # If node is terminal(game finished), return current node
    if node.isTerminal():
        # print("Node terminal in findspottoexpand: ", node)
        return node

    if not node.isFullyExpanded():
        # Create a new child node with a random valid move and add it to the current node's children
        new_gamestate = copy.deepcopy(node.game)
        new_gamestate_move = random.choice(node.valid_moves)

        valid, win, ngs = gomoku.move(new_gamestate, new_gamestate_move)
        if type(ngs) != gomoku.GameState and type(ngs) != tuple:
            print(type(ngs))
            print("Error in findspottoexpand!")
            return node
        newChild = Node(node, ngs, new_gamestate_move)
        node.children.append(newChild)

        # Return the new child
        # print("Returning newchild: ", newChild)
        return newChild

    # print("FSTE > Node is fully expanded. Finding best child and calling that")
    # If the node is already expanded, find the best child of this node and expand that one
    newNode = node.findBestChild()
    # print("FSTE > Best child: ", newNode)
    return findSpotToExpand(newNode, gomoku.valid_moves(
        newNode.game))  # Find a new one with the list of valid moves
Esempio n. 2
0
    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
Esempio n. 3
0
 def move(self, state: GameState, last_move: Move, max_time_to_move: int = 1000) -> Move:
     """This is the most important method: the agent will get:
     1) the current state of the game
     2) the last move by the opponent
     3) the available moves you can play (this is a special service we provide ;-) )
     4) the maximum time until the agent is required to make a move in milliseconds [diverging from this will lead to disqualification].
     """
     moves = gomoku.valid_moves(state)
     return random.choice(moves)
Esempio n. 4
0
    def move(self, state, last_move, max_time_to_move=1000):
        """This is the most important method: the agent will get:
        1) the current state of the state
        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(state)
        time_deadline = time.time() + (
            max_time_to_move * 1 / 1000
        )  # Deadline is 99% of the time to move in ms in ns. Can be optimized

        board = state[0]
        ply = state[1]

        # If only 1 move is possible, do that move
        if (len(valid_moves) == 1):
            return valid_moves[0]

        currentGame = copy.deepcopy(state)  # Current game board
        rootNode = Node(None, currentGame,
                        last_move)  # Current Rootnode(active gamestate)
        cRound = 0
        while (time.time() < time_deadline):
            ## Calculate new move
            newLeaf = findSpotToExpand(rootNode, valid_moves)
            # print("FindSpotToExpand Done: ", newLeaf)
            ## Play until game ends for that move
            gameresult = rollout(newLeaf)

            ## Calculate score for that move
            backupValue(gameresult, newLeaf)

        # If the best child is invalid for some reason, just use a random valid move
        # With the new code it should always be valid, but just in case
        bestChild = rootNode.findBestChild()
        if not bestChild.last_move in valid_moves:
            print("Chosen best child move is invalid")
            return valid_moves[0]

        self.play += 2
        return bestChild.last_move
Esempio n. 5
0
 def getValidMoves(self):
     """
     Returns the current valid moves for the game statea
     """
     self.valid_moves = gomoku.valid_moves(self.game)
     return self.valid_moves
Esempio n. 6
0
 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.starting_state(
                 bsize_=self.bsize)  # initialise the game
             previous_move = ()
             over = False
             currentRound = 1
             while not over:
                 print("Current Round: ", currentRound)
                 if game[1] % 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, previous_move, max_time_to_move=maxtime_per_move)
                 stop_time = time.time_ns()
                 currentRound += 1
                 # print(str((stop_time-start_time)/1000000)+"/"+str(maxtime_per_move*(1+tolerance)))
                 ok, win, game = gomoku.move(
                     game, move
                 )  # perform the move, and obtain whether the move was valid (ok) and whether the move results in a win
                 previous_move = move
                 # Uncomment the follwing two lines if you want to watch the games unfold slowly:
                 # time.sleep(1)
                 # gomoku.pretty_board(game[0])
                 # print("\n")
                 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.pretty_board(game[0])
                     print("trying to play: (" + str(move[0]) + "," +
                           str(move[1]) + ")")
                     if game[1] % 2 == 1:
                         print("as black")
                     else:
                         print("as white")
                 if win:
                     over = True
                     self.results[pid][pid_other] += 1
                 elif len(gomoku.valid_moves(game)) == 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