123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- """This file contains a collection of player classes for comparison with your
- own agent and example heuristic functions.
- """
- from random import randint
- def null_score(game, player):
- """This heuristic presumes no knowledge for non-terminal states, and
- returns the same uninformative value for all other states.
- Parameters
- ----------
- game : `isolation.Board`
- An instance of `isolation.Board` encoding the current state of the
- game (e.g., player locations and blocked cells).
- player : hashable
- One of the objects registered by the game object as a valid player.
- (i.e., `player` should be either game.__player_1__ or
- game.__player_2__).
- Returns
- ----------
- float
- The heuristic value of the current game state.
- """
- if game.is_loser(player):
- return float("-inf")
- if game.is_winner(player):
- return float("inf")
- return 0.
- def open_move_score(game, player):
- """The basic evaluation function described in lecture that outputs a score
- equal to the number of moves open for your computer player on the board.
- Parameters
- ----------
- game : `isolation.Board`
- An instance of `isolation.Board` encoding the current state of the
- game (e.g., player locations and blocked cells).
- player : hashable
- One of the objects registered by the game object as a valid player.
- (i.e., `player` should be either game.__player_1__ or
- game.__player_2__).
- Returns
- ----------
- float
- The heuristic value of the current game state
- """
- if game.is_loser(player):
- return float("-inf")
- if game.is_winner(player):
- return float("inf")
- return float(len(game.get_legal_moves(player)))
- def improved_score(game, player):
- """The "Improved" evaluation function discussed in lecture that outputs a
- score equal to the difference in the number of moves available to the
- two players.
- Parameters
- ----------
- game : `isolation.Board`
- An instance of `isolation.Board` encoding the current state of the
- game (e.g., player locations and blocked cells).
- player : hashable
- One of the objects registered by the game object as a valid player.
- (i.e., `player` should be either game.__player_1__ or
- game.__player_2__).
- Returns
- ----------
- float
- The heuristic value of the current game state
- """
- if game.is_loser(player):
- return float("-inf")
- if game.is_winner(player):
- return float("inf")
- own_moves = len(game.get_legal_moves(player))
- opp_moves = len(game.get_legal_moves(game.get_opponent(player)))
- return float(own_moves - opp_moves)
- class RandomPlayer():
- """Player that chooses a move randomly."""
- def get_move(self, game, legal_moves, time_left):
- """Randomly select a move from the available legal moves.
- Parameters
- ----------
- game : `isolation.Board`
- An instance of `isolation.Board` encoding the current state of the
- game (e.g., player locations and blocked cells).
- legal_moves : list<(int, int)>
- A list containing legal moves. Moves are encoded as tuples of pairs
- of ints defining the next (row, col) for the agent to occupy.
- time_left : callable
- A function that returns the number of milliseconds left in the
- current turn. Returning with any less than 0 ms remaining forfeits
- the game.
- Returns
- ----------
- (int, int)
- A randomly selected legal move; may return (-1, -1) if there are
- no available legal moves.
- """
- if not legal_moves:
- return (-1, -1)
- return legal_moves[randint(0, len(legal_moves) - 1)]
- class GreedyPlayer():
- """Player that chooses next move to maximize heuristic score. This is
- equivalent to a minimax search agent with a search depth of one.
- """
- def __init__(self, score_fn=open_move_score):
- self.score = score_fn
- def get_move(self, game, legal_moves, time_left):
- """Select the move from the available legal moves with the highest
- heuristic score.
- Parameters
- ----------
- game : `isolation.Board`
- An instance of `isolation.Board` encoding the current state of the
- game (e.g., player locations and blocked cells).
- legal_moves : list<(int, int)>
- A list containing legal moves. Moves are encoded as tuples of pairs
- of ints defining the next (row, col) for the agent to occupy.
- time_left : callable
- A function that returns the number of milliseconds left in the
- current turn. Returning with any less than 0 ms remaining forfeits
- the game.
- Returns
- ----------
- (int, int)
- The move in the legal moves list with the highest heuristic score
- for the current game state; may return (-1, -1) if there are no
- legal moves.
- """
- if not legal_moves:
- return (-1, -1)
- _, move = max([(self.score(game.forecast_move(m), self), m) for m in legal_moves])
- return move
- class HumanPlayer():
- """Player that chooses a move according to user's input."""
- def get_move(self, game, legal_moves, time_left):
- """
- Select a move from the available legal moves based on user input at the
- terminal.
- **********************************************************************
- NOTE: If testing with this player, remember to disable move timeout in
- the call to `Board.play()`.
- **********************************************************************
- Parameters
- ----------
- game : `isolation.Board`
- An instance of `isolation.Board` encoding the current state of the
- game (e.g., player locations and blocked cells).
- legal_moves : list<(int, int)>
- A list containing legal moves. Moves are encoded as tuples of pairs
- of ints defining the next (row, col) for the agent to occupy.
- time_left : callable
- A function that returns the number of milliseconds left in the
- current turn. Returning with any less than 0 ms remaining forfeits
- the game.
- Returns
- ----------
- (int, int)
- The move in the legal moves list selected by the user through the
- terminal prompt; automatically return (-1, -1) if there are no
- legal moves
- """
- if not legal_moves:
- return (-1, -1)
- print(('\t'.join(['[%d] %s' % (i, str(move)) for i, move in enumerate(legal_moves)])))
- valid_choice = False
- while not valid_choice:
- try:
- index = int(input('Select move index:'))
- valid_choice = 0 <= index < len(legal_moves)
- if not valid_choice:
- print('Illegal move! Try again.')
- except ValueError:
- print('Invalid index! Try again.')
- return legal_moves[index]
- if __name__ == "__main__":
- from isolation import Board
- # create an isolation board (by default 7x7)
- player1 = RandomPlayer()
- player2 = GreedyPlayer()
- game = Board(player1, player2)
- # place player 1 on the board at row 2, column 3, then place player 2 on
- # the board at row 0, column 5; display the resulting board state. Note
- # that .apply_move() changes the calling object
- game.apply_move((2, 3))
- game.apply_move((0, 5))
- print(game.to_string())
- # players take turns moving on the board, so player1 should be next to move
- assert(player1 == game.active_player)
- # get a list of the legal moves available to the active player
- print(game.get_legal_moves())
- # get a successor of the current state by making a copy of the board and
- # applying a move. Notice that this does NOT change the calling object
- # (unlike .apply_move()).
- new_game = game.forecast_move((1, 1))
- assert(new_game.to_string() != game.to_string())
- print("\nOld state:\n{}".format(game.to_string()))
- print("\nNew state:\n{}".format(new_game.to_string()))
- # play the remainder of the game automatically -- outcome can be "illegal
- # move" or "timeout"; it should _always_ be "illegal move" in this example
- winner, history, outcome = game.play()
- print("\nWinner: {}\nOutcome: {}".format(winner, outcome))
- print(game.to_string())
- print("Move history:\n{!s}".format(history))
|