Feel free to checkout the latest version of the code or follow the progress on my GitHub page.
The basic game play part of the package consists of three main components:
Board: the game board object.
C4Bot: the player object.
main: The function used to play a game.
I will now describe each of these briefly.
The Board class
This is defined in board.py and acts to store the current game state as well as to encode the rules of a standard game of Connect Four. The game state consists of two main pieces of information: the current board layout stored as a 2-D numpy array of integers in the class attribute state, and an integer indicating which player is to move next called curr_player. In a standard C4 game, the board has 7 columns and 6 rows, so state is usually an array of shape (7, 6). But the dimensions of the board can be changed by changing the Board.NCOL and Board.NROW attributes.
The actual Connect Four game rules are also encoded within this class, and a variety of class methods are available for interacting with the board in legal ways. Get a list of legal moves (a move being the column number in which to drop a marker) using get_move_list(). Make a move and update the board state accordingly using make_move(). This function automatically checks for victory (or a draw) and returns an integer indicating the result of the move.
I've also included a function that converts any board configuration into a unique ID (stored as an integer or long). This ID is easier to e.g. store in a database than a Numpy array. I do this by treating each entry of the Connect Four board as a digit in a number that is represented in base 3 (since each entry of the state array contains one of three possible entries). The unique ID is just this number converted into base 10. You can see why this ID is stored as a long; the number can get as large as ~ 3**43-1 ~ 3e+20. To get the unique ID of the current board use get_board_id() and to convert from an ID to a board array use get_board_from_id(). Optionally a record of all moves can be stored as a list of these board IDs in state_record. This kind of functionality seems like it will be useful when playing around with ML algorithms.
The C4Bot class
The C4Bot class, defined in c4bot.py, is not actually intended to be used directly, but to be an abstract class that others inherit from. This class, and any of its children, have only two basic pieces of information: an attribute pnum which is an integer storing the player number, and a move method which describes how the class decides which move to make. move takes a Board instance as its only argument.
As of now, there are three subclasses of C4Bot that have been implemented. The Human class allows human players to play by requesting a move using standard input. Random is a computer player that selects from the available moves at random. BotA is a work in progress that chooses the move that has the highest probability of leading to a victory. The probability of each board configuration to lead to victory is what this bot needs to "learn." It remembers previous games that it plays by storing information about them into a database. It then recalls this information when deciding what moves to make. Therefore, this bot needs to be trained to some degree before it is any different from the random opponent. More on this later.
The main function
This function, defined in connectfour.py, simply provides a game loop that requests each of the specified players to make a move and updates the game board using the given move until victory or a draw has been reached. This function can be run from the command line or called from external scripts (e.g. if one wanted to write a script to have the computer play itself a number of times and record the results a la fight.py).
That's it for the basic description of the C4 game code. Next time I'll describe BotA in more detail and show some results from tests that I've run during and after its training.
No comments:
Post a Comment