FoolGo Documentation

repository·master·Indexed 18 days ago

https://github.com/chncwang/foolgo

FoolGo is a Go AI implementation based on Monte Carlo Tree Search (MCTS) and the UCT algorithm, currently targeting 9x9 boards. It features a high-performance FullBoard class for managing game state, including Zobrist hashes and Ko restrictions, and provides an extensible OOP framework with Player and Game interfaces. The library includes implementations for RandomPlayer and UCTPlayer, as well as an Engine class for managing deep learning lifecycles, model parameter initialization, and training loops.

Tokens
5.1K
Snippets
24
Records
26
Agent score
63%

What's inside FoolGo

  1. Core classes and interfaces in FoolGo

    master

    FoolGo is designed with an Object-Oriented Programming (OOP) approach, making it extensible. The following core components define the game logic and player behavior:

    • FullBoard: The game board class. It provides efficient methods like PlayMove to update the game state.
    • Player: An interface for move selection. You can implement this interface to create different types of players. Key implementations include:
      • RandomPlayer: Returns a random legal position for the next move.
      • UCTPlayer: Uses the UCT (Upper Confidence Bound applied to Trees) algorithm to determine the next move.
    • Game: An interface that manages two Player objects. An example implementation is MonteCarloGame, which can be initialized with two RandomPlayer objects.
  2. Build FoolGo using CMake

    master

    To build FoolGo, you must have the boost library installed on your system. Use the following commands to create a build directory, configure the project with CMake, and compile it using make.

    mkdir build && cd build
    cmake ..
    make
  3. Manage game state with FullBoard

    master

    The FullBoard<BOARD_LEN> class is the primary interface for managing a Go game state efficiently. It tracks board positions, piece chains, eye states, and Ko indices. It is designed for high-performance updates using PlayMove and Pass methods, which automatically update internal structures like Zobrist hashes and playable move bitsets.

    // Example initialization and move execution
    // Note: BOARD_LEN is a template parameter (e.g., 19 for 19x19)
    foolgo::FullBoard<19> board;
    board.Init();
    
    // Play a move for Black at a specific index
    board.PlayMove(foolgo::Move(foolgo::BLACK_FORCE, some_position_index));
    
    // Or use the helper Play function
    foolgo::Play(&board, some_position_index);
  4. Implement a custom game by subclassing Game

    master

    The foolgo::Game<BOARD_LEN> class is a template base class used to manage the lifecycle of a Go game. To create a specific game implementation, you must subclass Game and provide an implementation for the Play method (which is called by the internal Run loop).

    Key Lifecycle Methods

    • Play(&full_board_, next_index): This is the core method you must implement. It defines how a move at next_index is applied to the FullBoard.
    • BeforePlay(PositionIndex index): A virtual hook called immediately before a move is played. Use this for custom logic or logging.
    • ShouldLog(): A virtual method that returns a boolean. If true, the game state will be printed to std::cout during the Run() loop.

    Constructor Parameters

    When initializing your subclass, the base constructor requires:

    • full_board: An initial FullBoard<BOARD_LEN> state.
    • black_player: A pointer to a Player<BOARD_LEN> instance for the black stones.
    • white_player: A pointer to a Player<BOARD_LEN> instance for the white stones.
    • only_log_board: A boolean (default true) determining if the board output is restricted to board-only logging.
  5. Initialize a custom game with FreshGame::BuildFreshGame

    master

    Use BuildFreshGame to create a game session with specific, pre-instantiated Player objects for Black and White.

    Parameters:

    • black_player (Player<BOARD_LEN>*): Pointer to the player object for the Black side.
    • white_player (Player<BOARD_LEN>*): Pointer to the player object for the White side.
    // Example: Using custom player instances
    // (Assuming black_p and white_p are valid Player pointers)
    auto game = foolgo::FreshGame<19>::BuildFreshGame(black_p, white_p);
  6. Execute a game loop with Run()

    master

    The Run() method starts the automated game loop. It continues executing as long as full_board_.IsEnd() returns false.

    In each iteration, the loop:

    1. Determines the NextForce (whose turn it is).
    2. Retrieves the corresponding Player.
    3. Requests the next move via current_player->NextMove(full_board_).
    4. If the move is POSITION_INDEX_END, it marks the board as ended.
    5. Otherwise, it calls BeforePlay() and then calls the virtual Play() method to update the board state.
    6. Logs the board to std::cout if ShouldLog() is enabled.
    // Example of starting a game loop
    MyCustomGame<19> game(initial_board, black_ptr, white_ptr);
    game.Run();
  7. Create an SgfGame instance using BuildSgfGame

    master

    To load or play a game from SGF (Smart Game Format) data, use the static factory method BuildSgfGame. This method initializes two SgfPlayer instances (one for black and one for white) and sets up the game board. You can optionally provide a pointer to a std::vector<Sample<BOARD_LEN>> to collect board states during play.

    Note: SgfGame is a template class and requires a BOARD_LEN parameter.

    // Example usage of BuildSgfGame
    // Assuming BOARD_LEN is defined (e.g., 19)
    std::vector<foolgo::Sample<19>> samples;
    foolgo::GameInfo info = /* ... initialize game info ... */;
    
    auto game = foolgo::SgfGame<19>::BuildSgfGame(info, &samples);
  8. Use the Board class to manage game state

    master

    The Board<BOARD_LEN> class is a template used to manage the state of a game board of a specific size. It stores PointState values for each position on the board. You can initialize the board, copy its state, and query or modify individual points using either a PositionIndex or a Position object.

    Key methods:

    • Init(): Resets all points on the board to EMPTY_POINT.
    • Copy(const Board<BOARD_LEN> &b): Performs a shallow copy of the board state from another board instance.
    • GetPoint(PositionIndex index) or GetPoint(const Position &pos): Retrieves the PointState at a specific location.
    • SetPoint(PositionIndex index, PointState point) or SetPoint(const Position &pos, PointState point): Updates the state of a specific location.
    // Example usage of the Board class
    // Assuming BOARD_LEN and PointState are defined in the project
    
    // Create a board of a specific size
    Board<19> board;
    
    // Initialize the board to an empty state
    board.Init();
    
    // Set a point using a Position object
    board.SetPoint(Position(5, 5), SOME_POINT_STATE);
    
    // Get a point using a PositionIndex
    PointState state = board.GetPoint(123);
  9. Initialize a Human vs Human game with FreshGame::BuildHumanVsHumanGame

    master

    Use BuildHumanVsHumanGame to create a game session where two humans play against each other using manual input.

    Parameters:

    • only_log_board (bool): If true, the game focuses on logging the board state. Defaults to true.
    // Example: Two humans playing on a 19x19 board
    auto game = foolgo::FreshGame<19>::BuildHumanVsHumanGame(true);
  10. Split SGF files into string segments using SGFParser

    master

    The SGFParser class includes methods to segment the contents of an SGF file into a vector of strings, which can be useful for manual processing or custom parsing logic:

    • chop_from_file(const std::string &fname, size_t index): Extracts a single segment starting from a specific index in the file.
    • chop_all(const std::string &fname, size_t stopat = SIZE_MAX): Splits the entire file into segments, stopping if the stopat index is reached.
    • chop_stream(std::istream& ins, size_t stopat = SIZE_MAX): Performs the same splitting logic but operates on an input stream instead of a filename.
    #include "src/util/SGFParser.h"
    #include <fstream>
    
    // Example: Splitting a file into all its segments
    std::vector<std::string> segments = foolgo::SGFParser::chop_all("game.sgf");
    
    // Example: Splitting from an input stream
    std::ifstream file("game.sgf");
    std::vector<std::string> stream_segments = foolgo::SGFParser::chop_stream(file);
  11. Use the Engine class for deep learning training

    master

    The Engine class is the primary interface for managing the deep learning lifecycle in FoolGo. It handles model parameter initialization, graph construction, and the training loop.

    To use the Engine:

    1. Initialize: Instantiate the Engine with a HyperParams object and call Init(). This sets up the model parameters, exports them to a model updater, and initializes a set of GraphBuilder instances based on the specified batch size.
    2. Train: Call Train() by passing a vector of Sample<19> objects. The method performs a forward pass through the builders, computes the loss using softMaxLoss, and executes a backward pass to update the model. It returns the computed cost (as dtype).
    // Assuming HyperParams and Sample are defined elsewhere
    foolgo::HyperParams params;
    // ... configure params ...
    
    foolgo::Engine engine(params);
    engine.Init();
    
    std::vector<foolgo::Sample<19>> training_samples;
    // ... populate samples ...
    
    dtype loss = engine.Train(training_samples);