How I created the online game “backgammon” (part five). Server

Hi all!

In the previous parts of my story I told how I came up with the idea to implement a simple, at first glance, game of “long backgammon”, then I described the server architecture, the “authorization” and “game” modules, and this time I want to talk about the players controlled by the program, such players are also called bots. Most games implement the mechanics of bots in one way or another, since bots can be considered any opponents or characters in the game, if they are not controlled by a person.

In games with large budgets, bots can be controlled by artificial intelligence, which is used to make all the bots' actions look as natural as possible and their diversity creates the feeling of playing with a real person. The implementation of such a system requires a lot of time resources, and also requires studying a number of issues related to connecting artificial intelligence to managing this process.

After reading a few articles on the topic and spending some time thinking, I realized that a real AI would be overkill in my case and made a short list of desirable bot capabilities to break down the problem:

  • emulate the actions of a real player

  • change the level of analysis of the current game situation

  • adjust the depth of prediction of actions in the game

  • dynamically select a game strategy

By the way, for those of you who want to get more information on this topic, I recommend starting with the article, which is a translation into Russian of good material, presented in an accessible form and covering a large number of issues related to the implementation of AI in games.

The specifics of the game I developed allow me to implement all the above-mentioned features in a fairly compact form. To analyze the current state of the game, I only need to know the location of the chips on the board and the values ​​of the dice. In long backgammon, players move chips around the board counterclockwise in an effort to bring all the chips to the last quarter of the board, called the home, creating all sorts of obstacles for the opponent along the way. The game has a number of rules that, for example, prohibit a player from placing six of his chips in a row, blocking the opponent's chips from moving around the board. But this rule only applies if none of the opponent's chips are in his home.

By the time I started developing the bot, all the rules of the game had already been implemented in the corresponding class, which has a public method that allows you to restore the state of the game and a method that gives all available moves of the chips for the current player, taking into account the dice that have fallen. To implement the bot, I chose a functional approach, since the process is quite simple and linear. As a result, the bot has only one public function, which receives the state of the game as a parameter, which contains the location of the chips on the board and the values ​​of the dice that have fallen. The color that the current player plays is determined by the first move in the game, and therefore it is always possible to find out which chips are the chips of the current player.

In order to avoid creating different calculation options depending on which side of the board the bot is playing on, I implemented a method that allows you to “flip” the board if necessary and invert the color of the chips, so the bot always thinks that it is playing white and starts from the upper right part of the board, in the picture above this is “Devel's start”.

After restoring the game state and, if necessary, rotating the board and inverting the color of the chips, the method for obtaining a list of all available moves using the dice that have fallen is called. After that, each possible step is simulated by repeating the call to the method for obtaining a list of available moves and the process is repeated. Thus, as a result of these actions, I get all possible options for moves in all combinations. Then this list, together with the current state of the board, is passed to a function that returns the “best” combination of moves, which are the result of the bot's “intellectual work”.

The function that determines the best combination reproduces each move variant on the transmitted board state and evaluates the new state on a number of parameters, giving a different number of points to the given combination depending on the situation on the board as a result of the moves. Here is a list of evaluations that I use in this function:

  • Basic evaluation of the position after the move. Allows you to understand how much all the chips are moving towards their home as a result of this move. The rating is calculated incrementally depending on the distance to the starting position. This evaluation pushes the bot to move the chips towards its home.

  • Bonus for removing a chip from the starting position. This allows the bot to remember to bring chips into the game in a timely manner.

  • Bonus for creating an obstacle in the opponent's path. The score increases depending on the number of consecutive chips placed. This allows the bot to effectively create obstacles and protect its positions.

  • An additional bonus for blocking inside the opponent's starting area. This assessment already influences rather the tactics, which consists of blocking the opponent's moves to move the pieces from the starting position, which ultimately allows to increase the chances of winning.

  • An additional bonus for moving chips to the home after all chips have left the starting area. Affects the change in game tactics in the second half of the game.

  • Penalty for moving chips inside the house. Appeared after the bot's passion for making the house “beautiful” was noticed. Instead of effectively removing chips from the game and winning as quickly as possible, it sought to put chips in a blocking state, although in this situation it no longer matters. This is solved by implementing an additional condition in the blocking bonus, but I decided that the bot's life should not only have bonuses, so I left it as is.

All bonuses and penalties have their own numerical ratings, which are a separate type of entertainment to set up. As a result of the calculations, the sum of the ratings becomes the rating of the combination of moves that was processed. After evaluating all combinations, the function returns one combination that has the highest rating.

Of course, this mechanic sometimes provokes the bot to illogical steps, but, in the end, who among us does not make mistakes. This implementation allows you to create a certain resistance from the bot for the player, but it is far from the limit. I considered that this is quite enough to create an atmosphere of a duel and postponed further improvements until the next version of the game.

As I already told in the previous article, after creating and launching the game, depending on whose turn is the current one, the system either waits for a move from the player, or in the case of the “Game with AI” mode, passes the move to the bot. It is at this moment that the current state of the game is passed to the function described above, and as a result, a move is made by the bot, information about which is transmitted to the game channel.

After this mechanic was implemented, I really wanted to watch a bot play with a bot, as a result of which the active game viewing mode appeared. It allows you to connect to the game channel and receive all the messages that players receive. On the client side, when messages are received, the game state is restored and a new move is played, which allows you to watch the game of both people and bots, because in the system, a bot (AI) is the same player as everyone else, except that it can play an unlimited number of games at the same time.

In conclusion, I would like to tell you about one idea that has been bothering me for a long time. While creating the bot, I thought that it would be interesting for me to try to compete in the topic of creating bots for playing backgammon. It is possible to create a mechanism for the safe use of third-party bot logic on the server and launch games using it so that within the framework of one game it would be possible to use different logic for each player. It is clear that in backgammon, sometimes the dice decide the outcome of the game, but how the strategy is built and what steps are taken play a significant role in achieving victory. I see this as an opportunity to pass a link to a serverless function to the parameters of a new game Cloudflare Workers, AWS Lambda, DigitalOcean Functions or any other placement option, where in essence the function will process a POST request containing the state of the board and a list of combinations of possible moves.

The request body in JSON format might look like this:

{
  "board": {
    "white": [[0, 13], [1, 1], [4, 1]], 
    "black": [[0, 13], [2, 1], [5, 1]]
  },
  "steps": [
    [
      [0, 3], [3, 7]
    ],
    [
      [1, 4], [4, 8]
    ],
    [
      [4, 7], [7, 11]
    ]
  ]
}

In response, the function must return the index of the combination from the “steps” array, and this movement will be counted as a move.

The simplest implementation of such a function on the Cloudflare platform might look like this:

export default {
	async fetch(request) {
		if (request.method !== 'POST') {
			return new Response('Bad Request', { status: 400 });
		}

		try {
			const data = await request.json();
			const index = Math.floor(Math.random() * data.steps.length);
			return new Response(JSON.stringify({ index }), {
				headers: {
					'content-type': 'application/json;charset=utf-8'
				}
			});
		} catch (err) {
			return new Response('Bad Request', { status: 400 });
		}
	}
};

If anyone is interested in discussing this topic, let me know in the comments or write to me in telegram.

In the last poll, a third of voters showed interest in voice chat, so in the next part I will talk about it, and then move on to a description of the client application.

P.S. You can play my backgammon at website or in telegram.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *