This blogpost was moved here from https://creatingboardgames.wordpress.com/2021/12/18/a-framework-for-having-bots-playing-your-board-game/.
You might have seen a blogpost or two of mine, where I talk about using a computer to simulate a board game in order to get a data for a lot of games. Thanks to some feedback from Facebook, the code I wrote for my own game project is now turning into a framework that could be used by other board game developers who are interested in coding.
The ideas are these:
Use Google spreadsheet to describe volumes of input data: cards, player stats, properties on the board, and the like. The framework gives you nice functions to get the data into formats that could be used in the simulation (such as buildObjectArrayFromRows(‘sheet1’, ‘A1:D201’)).
The high-order simulation stuff is managed by the framework, and the code specific for your game is kept in a module. On a very high level, the framework does this to simulate a game:
- Find which module to use.
- Call buildInitialData() in the module. This function does two things. The first is populating the global variable with static stuff that are needed in the game simulations. This could be information about the board, setting up default values for how do use dice, or other things that do not change within or between games. The second thing is to build the initialGameState, which could be setting up decks, describing initial data for players (called agents in the framework) and the like. Both these tasks will most likely read a lot of data from the spreadsheet.
- The framework then prepares for the first game iteration, by copying the initial game state and processing it – data about agents, cards/decks and tracks/spaces are fed into pre-made classes that simplifies a lot of work later on. The framework also sets up some variables used to keep track of things – both within a game iteration (such as the number of rounds) and between rounds (such as data that should be used for statistics).
- The framework allows the module to do any extra processing before the first iteration starts, by calling preIteration(gameState) in the module. Examples of where this is useful is to remove three cards from the deck in No Thanks!, or drawing cards and placing initial disease cubes in Pandemic.
- Then the game iteration starts. The framework calls gameOver(gameState) in the module, to check if the game is still on. If we’re still game, the framework ticks up one round and calls playRound(gameState) in the module. This is where the magic happens – agents do stuff in ways described by the game rules and implemented by the coding game designer. In games where players take turns, the code will most likely be broken down into turns inside the round, but I’ve left that for developers to implement. In any case, there are a lot of tools provided by the framework that speeds up the programming. For example:
- The Agent class has room for swappable strategies, provided by the module. By calling agent.consultStrategy(‘considerReroll’, gameState), for example, the agent’s strategy is looked up, any method with name considerReroll is called with the game state (and agent) as argument, and its result is returned. Apply to whatever strategy functions you need to write.
- The Agent class also has methods for recording when stats are changed, so you can pick up how many times hit points have been lost, or how often the player’s money increased.
- The Deck and Card classes provide methods for shuffling decks, drawing/discaring/returning cards, placing cards in a display, and more. One particularly useful aspect is the resolver property that can be set on cards. If present, card.resolve(arguments) can be called to take care of cards when handling needs special-case code.
- The DiceRoll class provides some neat shortcuts, also for customized dice.
- The Track class can be used for moving pawns on tracks, or emulating simple game boards. The pawns can be player pawns or general pawns keeping track of global game elements. Apart from moving pawns and getting information about which space each pawn is on, there are also options for the same type of resolvers as the cards have. If spaces need special code, it can be handled by setting a resolver.
All of this is in place right now, but I want to write an example or two and also create a few videos showing how the framework can be used before releasing version 1.0 beta. Anyone’s interested can go over to GitHub and check out the project page: https://github.com/Itangalo/Board-game-scripting-tools
A few additional thoughts:
- I think that the first example I provide in the framework will be No Thanks, and I’m looking for a second example. This should ideally be a simple worker placement game, to show how cards can be used to emulate worker placement. If you have any suggestion for a suitable game, please let me know.
- I’m looking for a good name for the framework/toolbox. Have any idea?