📜 ⬆️ ⬇️

Billiard bot: the history of creation

Hi, Habrahabr! This article is devoted to a detailed description of the process of creating a billiard bot, which, without human intervention, plays the game pool billiard and makes decisions, earning points. The article will be useful and interesting to people who are interested in the creation of bots and programming.



Foreword


We all have our favorite games and sports. It's great when the first coincides with the second. In addition to my hobbies for sports and sports projects, I also like some computer games. One of my favorite games, both live and virtual, is, of course, billiards. Billiards, pool, snooker ... whatever you like - I love them all! I share the opinion of many that, for example, snooker is “non-discrete” chess. It is not enough just to score a sequence of certain balls in the pocket, there is also an incredible strategic struggle. The fight for snookers, for positions ... and what a fantastic technique professional billiards players have - just keep quiet in a rag.

The advantages of this undoubtedly aristocratic game can be listed for a very long time. But let's get to the essence of the article. My favorite game of billiards for the past five years and to this day - this is “ Pool Billiard ” on Facebook. It is famously made not only aesthetically, but also technically. With the naked eye you can see a coolly written physics engine, thoughtful gameplay, client-server action validation, error handling, design, statistics system, shop, chat in the end. The game obviously did the pros, and she is in the tops. It is very nice to play ... and win!
')
I played it for a long time, until the thought came to my mind: “ Bah! Yes, it is ideal for creating a game bot under it! . It is pleasant to win, but to win with your robot, automatically - doubly! Winning paid players who have chosen a cue-ball navigation and twisting system, showing them fantastic shots in technique and beauty, leaving them with sagging jaws is triple pleasure! Plus an automatic set of experience points and coins: left the robot for the night, in the morning you are the best! In addition, even as a spectator, I adore to watch billiards for hours. In general, yes, I decided!

Creature


Before the start of creation, I, having at that time already quite a lot of experience playing Pool Billiard, carefully thought through everything with a pencil and a piece of paper in my hands. Of course, it is impossible to predict everything, but the “skeleton” was created. Bring the skeleton! To create a bot, I used C ++.

Writing and debugging the code in the optional mode in the evenings took me almost four months. Agree, it is difficult to debug something on a closed system, especially when you need to test some rare or exceptional case that happens in one of a hundred batches. I after all cannot frivolously place the balls and simulate this or that situation on the table.

How does the robot interact with the game?


I realized that the bot will interact with the browser through a complete imitation of a person: pattern recognition and imitation of human input: a mouse, a keyboard. Thank God, you do not need to enter a captcha before each blow :) So I did: I like systems for imitating the behavior of a person from whom browsers are so defenseless!

This means that you need to be able to find the region with the game on the screen, be able to interact with it, receive certain signals from the game and process them, and, most difficultly, be able to correctly strike. I made a list of necessary actions that a bot should be able to perform (for example, enter a certain game, send a certain message to chat, put a ball at a certain point, check the number of points, strike a certain force at a certain angle, break a pyramid and so on) and a list of certain signals that a bot should be able to recognize (for example, our turn began, the round ended abruptly, the enemy surrendered, there was little money, and so on). In total, there are about forty situations; some turned out to be asynchronous, some not. I programmed and, as far as possible, carefully tested each of them (about this separately), after which the building blocks of the bot were ready.

What is the general logic of the work?


I decided that the general logic of the work would, of course, be a state machine. First, the bot is calibrated for the game, then it calculates the amount of money available, then decides what bet to make. Next comes the gameplay itself, after which the bot again decides how best to enter the new game. The simpler the logic, the more reliable and predictable the system works. And it's easier to catch bugs.

What is the detailed logic of the work?


The detailed logic is harsh and bearded, it contains a whole bunch of branches and possible situations. It all starts with the fact that the game starts and the bot itself. The game (browser window with the start screen of the game) is on the screen. Its coordinates are recorded and this serves as a starting point for all subsequent mouse input actions and situation recognition.

Next, the bot determines the amount of my money in order to understand what bets can be made. After selecting the size of the bet, the bot enters the appropriate room and the game begins. It can end at any time, since already from this second the opponent can close the browser, and, after a certain timeout, our round is declared invalid. The opponent can also leave the round at any time: in this case, the victory will be awarded to me. Recognizing all of these situations begins right here.

Then the server randomly determines who will start the game: me or an opponent. The bot is waiting to start its turn. Only 20 seconds is given for the whole course. During this time, you need to have time to determine that the move is already mine, count the balls and glasses from the table, recognize them correctly, find the right strike and have time to carry it out.

The bot itself determines whether it will break the pyramid, and in this case, he has a couple of otpadnyh options in store. If you don’t need to break the pyramid, the bot recognizes the coordinates of the balls on the table, which balls it can score (colored or striped or any other than black or only black (judging by the situation in the game), the number of points and all the rest of the rest.) strikes.

The bot, besides the main activities and not to the detriment of the game, also likes to stumble with opponents. Usually, such a temporary window occurs immediately after the strike. This is where the bot writes some chat message to the opponent. After the strike, either the move goes to the opponent, or we continue to play, or we won, or we lost. The bot is waiting for a sign of one of these situations. In case of defeat or victory, the bot closes the current game window and the summary results window and goes back to recognizing the amount of money.

The state machine is generally about the same.



How is the game on screen?


I read the whole screen context in C ++. The game is on the screen is very simple. Since the design of the game is not "rubber" (it does not stretch), but fixed, all elements are always at the same distance from each other. So, it is necessary to find on the screen with the game a certain static element that never visually (graphically) changes, and calculate the coordinates of the beginning and end of the window relative to it. After making a couple of screenshots and processing everything in Photoshop, I did just that. I made a simple and reliable table recognition marker. I decided to abandon the idea of ​​recognizing the coordinates of the window before each stroke. It is stressful and takes away the precious moments of calculating the perfect blow. Therefore, the bot determines the position of the game only once - at launch. After the bot has found the game window, moving the browser window even one pixel is strictly forbidden: in the process of playing on the billiard table, an inaccuracy even in one pixel with long strokes accumulates a monstrously huge error. From here all beats will be wrong.

The game marker is the unchangeable part of the game window image:



How is the amount of money determined?


Here I was just lucky. I did not have to put a sniffer on the browser and listen to the game broadcast to determine the amount of money or recognize characters from the screen. Everything is prosaic: the fact is that in the game not everything is done on a flash. The element itself with the sum of my coins is a simple text field, easily selected by the mouse. I simply imitate the following: I bring the mouse to the beginning of the field, hold the paint button, move it to the right to the end of the field, release the paint button. As a result, the bot simply allocates a field with money. Then I copy it to the clipboard, delete special characters such as spaces, commas and periods ... and that's it! The amount of coins in my pocket.

Game coins are simply a highlighted field:



How is the room chosen for the game?


There are several rooms for the game, each of which contains a certain rate (admission fee). Two opponents enter the room, placing each, for example, 100 coins. The winner gets a win of 140 coins (not 200, as might be expected (this was done by game designers to constantly get a lot of money out of the game, and people had to use the store and buy more coins for real money and play, or wait until the daily wheel of fortune brings them coins for the game)). The loser leaves with nothing. The logic is simple.

In the cheap rooms there is always hanging around the rabble: novices, losers and so on. For the sake of fun, sometimes pros come in too. The probability of winning there is very high.

In the more expensive rooms, you can meet middle-level players, sometimes newbies go there by stupidity, sometimes superprises go down there (apparently, to tear someone to pieces). The probability of winning there is about 50%.

The elite hang out in expensive rooms: either superprofi, or payboards with a purchased navigation system, prompts, and so on. Most likely, there is a loss.

The bot has several modes of bet selection: forced modes (when the bot always puts the amount that I have given it) and auto mode. Auto mode is made in a very interesting way. I collected statistics of winnings by a bot in rooms of different rates and based on it I wrote a very interesting program. She only gives out a few numbers, but very important numbers. These are the so-called threshold amounts of coins. For example, if we have 300 coins, the bot has the right to play only in the first room, but after overcoming the threshold amount of 740 coins, the bot already has the right to play in the first and second rooms. Of course, the bot tends to play in the most expensive room.

So, the program is interesting in that it automatically selects these same threshold values ​​using a certain algorithm, which it itself goes further and uses to predict the risks of subsequent loss. It imitates millions of games and decisions about playing in one room or another (Monte-Carlo shelling) and gives the correct amount of coins. And, I noticed, the algorithm is convergent!

Directly the entrance to the room is carried out by clicking on a certain part of the screen, where the button for entering and implementing a certain rate is located.

After selecting the room click on the appropriate button:



How is the possibility of a move determined?


Here markers come to the rescue. The game screen is still as static as on the main one, and all the elements are always in the same places. This is a panacea. My opponent's avatar, as well as statistics, message box and other elements, are always on the left. My - on the right. I also created a simple and reliable marker for determining my turn. As soon as the bot reads it, it moves to the next phase.



How are the balls recognized?


Here is a whole epic in three acts. I will not describe all my two-month suffering on this issue, I will describe what is happening only briefly. From the image of the table, which was photographed at the time of recognition of the balls, the image of a clean table, carefully prepared by me in Photoshop, is subtracted. Next are the high-contrast zones on which are the spots of the balls. On certain specific light markers, taking into account the inadmissibility of overlap'a are the centers of the balls. Next, they are sorted by contrast of vividness to prevent debris from entering the screen (cue, writing on the table). After that, the position of the balls is determined by checking the shadow around them. Finally, received a list of the required number of centers of the balls in the image.

As soon as I did not try to look for balls in another way! And using the definition of shadows, and using the method of Kanni borders, and using ingenious classifiers: all these and many other methods were very ineffective and inaccurate compared to the method written by me personally. I even set Wolfram Mathematica on statistics, but it didn’t give me a very clear answer. Maybe bad set.

But it’s not enough to know the centers of the balls, we still have to determine where the strip is, where it is solid, where it is white (cue ball), and where it is black (eight) balls. There were no boundaries of boundless imagination, because it was necessary to solve a whole bunch of problems in a unified way. For example, the green ball merges very strongly with the cloth, and if the striped yellow ball stops so that its white pole is directed strictly into the chamber, it will be almost as white as the cue ball is. An entire billion surfaced subtleties, and I had to fight with all of them.

I went through a whole sea of ​​solutions, discarding them due to insufficient accuracy, and, finally, I myself wrote the most accurate of them. I got a decisive tree, in each node of which there is a samopisny classifier. For each found ball, I determine the color characteristics: the average {R, G, B}, the average {H, S, B}, the brightest and darkest color without taking into account the color spots. Then I definitely find the cue ball as the whitest ball. Next, I try to define the eight as the darkest ball. After all, you need to separate the color from the striped. But it was not easy to open the casket: I compiled three-dimensional sampling tables, photographed balls a thousand times in an attempt to train the network, but still I did not manage to build a hyperplane that uniquely separates clusters of solid and striped balls. Anyway, errors occur. For this case, I made a small correction-error-on-the-fly. About this - just below.

Here, different orthonormal turn bases sucked from a finger, clusters statistics with predefined balls colors and other mathematical basis went into play, but it was not that ... and it was not ... I went through a lot of options. In the end, we have a certain set of balls with their fairly accurate characteristics: there are always white and black balls, and sets of solid / striped ones. Believe me, not a small work has been done.

How is the possibility of breaking the pyramid?


Here I was relaxed: we create a simple classifier of the position of the pyramid (each ball is at the point of the pyramid) and if our turn and our turn is the first, then we break. But it was not there! Something did not work! It turns out that sly programmers added some noise to the initial positions of the balls in the pyramid. Clever! Otherwise, it would be possible to record the “perfect game” - an unmistakable series of blows leading to victory, and, constantly reproducing it, to win. But they provided such protection. Having slightly corrected the classifier, I achieved success in recognizing the moment of breaking the pyramid.

When it is necessary to break the pyramid, the bot chooses one of several tightly programmed into it luxurious options for breaking and implements it. Almost all of the above options make one or two balls immediately fly into the pockets. Well, or nakraynyak very scattered balls on the table, that my algorithm is only on hand.



How is the number of points on the table?


Near my avatars and opponent avatars there is a stack of hammered balls. It consists of a strip with balls scored into it, with a slightly smaller radius than on the table. However, how to be? It is not enough one recognition of balls on a table to understand, I play what series - striped or continuous. So, it is necessary to recognize not only the number of balls in the stacks, but also the balls themselves! Pffff ... the "table subtraction" algorithm is not suitable here, and the dimensions are not the same.
...
With an incredible effort of will, I forced myself to write another recognizer
...
and the second incredible effort is to combine both of these recognizers into one universal recognition function. In fact, I had to write everything from scratch. Here it is - the problem of insufficient planning. But now I indicate the region and size of the balls, and at the output I get the coordinates and characteristics of each ball! Victory of reason!

Having determined the number and type of balls scored by me and the opponent, the situation on the table becomes completely deterministic. Now the bot knows what and how it needs to score:



How is it determined which balls to hit?


A strictly deterministic algorithm is programmed here. If we break the pyramid at the beginning of the game, then we can hit any ball (we will not get into black anyway - it is hidden inside the pyramid). If the first move has already been made - we look at the number of balls scored. If not, you can beat anyone except black. If there is only an opponent - take the opposite type and beat. If I have (and not only me) - beat the same type. Finally, if I have scored all the balls of my series except black, score black. Everything! ;)



How are enemy fouls determined?


Sometimes the opponent mows. In this case, the rules of the game oblige me to a free kick: I have to put the cue ball myself at any point on the table and strike. So, there are two problems: the recognition of the opponent's foul and the correct setting of the ball under attack.

The first problem is solved relatively simply. In a separate thread, a certain tracker is trying to find such a situation: now the opponent’s turn and the “Fault!” Marker appeared on the table. In this case, he tells the mainstream that the next blow must be done with the production.

The second problem - the problem of staging - is solved a little more difficult. Although, I confess to you, my friends, here I fired. I'm not trying to put a cue ball along some line of scoring one of the balls in my series. Not. I'm just trying to put the ball universally - as close as possible to the center of the table, where there are no obstacles. First, I recognize the situation on the table, then I calculate the nearest unclosed point to the center of the table and put a ball there. As long as the production takes place, I will almost certainly calculate the perfect blow.



How is the angle and impact force calculated?


So, I had a task in a given time for a given configuration of balls on the table and a given rule of strikes to calculate all possible resultant hits and choose the best among them. Possible values ​​of the specified time: {20 seconds}. Possible configurations of balls: them? .. Possible rules of striking: {any except black, only solid, only striped, only black}.

Ball hammering

Before you get into the wilds of billiards, you must first understand the physics of what is happening. What you need to score a ball?



To do this, you must hold an imaginary segment from the center of the pocket to the center of the ball and slightly extend it further to the intersection with the border of the ball. The point of intersection is the point of impact. If you hit the ball on it, it will fly into the pocket.



In order for the cue ball to hit this point, it must be sent not at all to it, but to a point away from the point of impact on the cue ball radius further along the same imaginary line.



Well, then, I think you have already caught. In order for the cue-ball itself to fly to the right place, you must also build a line from the target point through the center of the cue ball and cross it with the far edge of the cue-ball circle.



So, from here comes the general rule: in order to send any ball to a given point A , you must connect point A and the center of this ball with an imaginary line and extend it to the intersection with the far border of the ball's circumference. This is where you need to hit the ball. I decided to make the strategy of the bot game the same as in humans: the bot chooses one ball to hit and scores it. Everything. The simpler the system, the more reliable and easier it is to debug it.

Luza

The pockets are different. And getting into them is subject to different laws. For example, in the corner pocket you can get in different ways:



But for each pocket I managed to find a universal point, the rolling of a ball to which from any place entails hitting the pocket:



I programmed the bot just to aim at these points. The only restriction that pockets of long sides impose on themselves: the flying of balls into them is possible only in a sash of 70 degrees. This is also embedded in the code.

Simulated space

I decided to give up bounce. No, no, do not be scared, not in the sense, of course;) To build such a simulated space in order to forget about bounce. They are in the game and remain, but they will not be in space. I worked on the solution of this problem only in the evening. I realized that the collision of a ball of radius R with a board with a thickness of 0 is the same as a collision of a material point of radius 0 with a board with a thickness of R :



So, it is possible to significantly simplify the calculation of physics: in terms of trajectories we will work not with balls, but with material points. Next: according to the laws of the genre, the angle of the ball on board is equal to the angle of reflection. As in the case of light rays and a mirror surface. You ask: where is it? I will answer. The collision of a material point with a board (ricochet about the side) is the same as the continuation of the movement of a material point through the side into space mirrored from this side. That is, if the ball could “see” forward in the direction of its movement, and the sides were mirrors, then it would have been this:



In such a "mirror-sided" space, I no longer need to think about rebounding. They flow by themselves. Plus, we connect the rule of motion of the material point, and it turns out generally luxurious.

In the simulated space, all the blows are straight lines, there is no rebound. But on the table they are already there.



Maximum impact force and the cue ball path

Great, a lot of work has been done! But there is still an extremely important question that we have not touched at all: what is the maximum way the cue ball can go? What is the energy in it? I do not want every time to lupas balls with full force; this will put the cue ball at risk of accidentally slipping into the pocket. I want to very accurately and accurately calculate the impact force.To do this, I need to know at what delay of the cue from the cue ball in pixels there is a minimum impact and how long it is, and at which delay of the cue from the cue ball in pixels the maximum impact occurs and how long it is. I also need to know what energy is taken from the ball when it hits the board. Now it remains to find out all this. With minimal strokes, everything is prosaic: it is measured at any time. With the maximum much, much more difficult. There is not enough table diagonal even for a medium strike, so I obviously cannot measure the length of his path.

I thought of expanding it into two cases: horizontal and vertical. Then, after making the corresponding measurements and equating the equations together, I would get the full length of the maximum trajectory of the ball and the quenching coefficient of energy on the side. So I did.I waited for the moments when the opponent got a foul in order to put the cue ball neatly to the edges of the sides, so that the horizontal and vertical movement of the cue ball did not interfere. And twice hit with all the power: once horizontally, the other - vertically. He took off the indicators: with a vertical blow, the cue-ball bounced off the long sides 8 times and, having reached the rest of the energy, some other way, stopped. With a horizontal blow, the number of rebounds was 5 with a tail. Hence, knowing the size of the table, it is easy to get the equations, numerically deciding which we will get and the full length of the maximum path, and the quenching coefficient.

Let x be the maximum length of the ball's rolling path without hitting the sides in pixels, and p <1 is the coefficient of energy loss when hitting the side at a right angle. Known width w and height h of the table in pixels. Consider the horizontal case:


Equate the last equation to zero. Similarly, we obtain the equation for the vertical case. Solving this non-linear system of two equations with two unknowns numerically, I obtained the desired x and p.

Chain rules

Of course, the depth of the blow can be any, if only there is enough energy. But because of the accumulation of errors, I decided to stop at number 4, that is, the maximum number of objects involved (including pockets) is 4. My cue ball can hit ball A , which hits ball B , which falls into a pocket. And that (!) Accuracy is lost so much that I introduced a number of restrictions on such attacks. They should be without ricochets on the sides, the distances between the balls and the pocket should be approximately equal and the angles of attack are close to elastic blows. But such a fantasy I still do not shine:



Rollback cue ball

All sufferings and calculations will be in vain if, even after an enchantingly masterpiece stroke, our cue ball rolls back and falls into the pocket. Even through the rebound. Therefore, I immediately throw out from the consideration such strikes, after which the bot can shine a failure. To calculate the cue rollback, the force and directions of the rollback after hitting the target ball are calculated. I thought everything would be simple: we calculate the remainder of the energy after an elastic / inelastic impact, at what distance and in which direction the cue ball rolls back, the direction - using the cosine of the relative angle of attack, and see if the trajectory passes through pockets. But no, the pitfall was waiting for me and here. After conducting a series of tests, I noticed that the actual rollback is significantly different from the simulated one.

Both the navigation system of the game (yellow) and common sense with calculations show that the cue ball will roll back along the green line. However, after hitting, he rolls on red:



Here it is a zapad. It turns out that the game also takes into account the torsion inertia of the ball and its direction. It took almost four evenings to write and test the nonlinear function of calculating the rollback trajectory. Such trifles enrage, but in the end it turns out that these are not trivialities at all. I managed to determine a less precise function only through trial and error. But I did it! Now I can safely throw punches that lead the cue ball through pockets as a result of a rollback.

Best hit search function

As a result of analyzing the configuration of the table, I received a collection of a large number of possible strokes. But how to choose the best one? It is necessary to turn on the brains and evaluate each parameter of impact. Logically, what would we like? It would be desirable to minimize the number of ricochets of the path from the cue ball to the target ball: each ricochet introduces a small but inaccuracy. The distance from the cue ball to the target ball should be as small as possible, but not quite small, in order to be able to qualitatively aim. Oddly enough, these are two different conditions. Think about it.Further. The distance from the target ball to the pocket to which it should fall should be as small as possible. Of course.And this path should contain a minimum of bounce, preferably - zero. The blow is desirable medium strength, not too strong (errors of torsion and the physical engine of the game) and not too weak (errors of my bot). The cue ball against the target ball should be as “straight” and elastic as possible: tangents are evil! From here automatically follows the minimum length of the rollback. Additional conditions (not so important, but still significant) flowed out of my long diving and analysis of underwater stones: it is necessary that the target ball fly into corner pockets at an angle as close as possible to 45 degrees, and into pockets of long sides at an angle no more than 35 degrees. There are some additional conditions, but keep silence about them.









But in essence, all these things are far from perfectly comparable to each other, and among themselves. For example, if the angle of attack (impact elasticity) is somehow comparable to another angle of attack (say, 0 degrees is better than 50), then such a characteristic as the impact force ...? For different lengths of trajectories, different forces are needed, because there is different distance and cutting. If we translate the force of impact into some relative indicator, then what to do with cutting? After all, for different blows she is her own! And how to compare incomparable categories, such as, for example, the number of ricochets (a number from 0 to, say, 10) and the angle of the ball into the pocket of the long side? What is more important?

… . . , 0 1, 0 — , 1 — . ; , ( ) [0, 1]. . . , 0 10, 1 2 . 8 — , . [0, 10] [0, 1] . «» , , , . , 77 .

— . — . . ? , . — . . , . , . ;)



, ! , , . «» 0 1 (). — : .


Over the months of testing, I found an interesting bug. Whether because of inaccuracies of the engine, or because of some of my shoals, the impact balls standing near the side do not always lend themselves to the general laws of striking. A must. This is what happens: in a situation where I ideally direct the impact ball, standing near the long side, into the pocket, instead of flying strictly parallel to the board and falling into the pocket, for some reason, it hits the side and bounces, flying in the wrong direction . It feels like I'm undercutting. I introduced a special corrective function to bring the cutting to the ideal. It is again taken from the ceiling and is pure fit. But it works.



Adaptive search in 20 seconds

We have only 20 seconds for everything about everything, and the bot may not have time to find the impact. Therefore, with a high priority stream, I am looking for so-called emergency strikes. These are blows that are aimed not at hitting the ball, but at least touching their ball. If, within 15 seconds of the search, the bot did not find a single strike for clogging, he immediately implements an emergency strike at the touch to avoid a foul. And I made the search for impact myself adaptive. First, the table itself is taken as the modeled (that same mirror) space as it is. If no impact was found, then the simulated space increases three times horizontally and vertically: a vertical reflection along with balls and pockets is “attached” to the table on the left and right, and the horizontal reflection is on the top and bottom.If the blow is not found here, then another completion of the simulated space occurs. And so on until either 15 seconds have passed, or the number of “blocks” of the table does not exceed the maximum allowable number of bounce messages; further ride at the ball simply does not have enough energy.

You need to score a green ball:



Aiming and hitting

It would seem that he achieved everything: there is an aiming point, and the force of the blow. It remains only to implement it. But even here I came across difficulties, or, more precisely, either the inaccuracy of programming, or the hidden protection from the fellow programmers of the game Pool Billiard. But first things first.Between the sighting point and the cue ball is the angle of impact. Suppose it is 27 degrees:



The bot must find such a pixel on the table, so that by placing the mouse there, the line of impact was exactly 27 degrees. Since the pixels are discrete, not continuous, then in a special search area, a search is made for the pixel that best suits this angle.



Well, it would seem, that's all! Put the mouse in the desired pixel, do a delay for a specified number of pixels to the cue ball and release. But no. ! !? , - , ! 4 , . . , : () . . , , 4 1 . - ; , .


Yes, the recognition of the balls I have is not perfect. Sometimes a bot mistakenly classifies a striped ball as solid, and vice versa. The easiest way to correct this situation is when the incorrectly recognized ball is on the table. The hardest thing is when there are balls in the stack.
Suppose the bot has incorrectly recognized the ball on the table. For definiteness, let the bot think that the ball is striped, when in fact it is solid. Bot clogs striped. By chance, this particular ball was chosen to be hit. What happens next? If the bot strikes not with his own ball, he will receive a Fault and a pass. And this is not good. I did this: if at the moment of aiming at the ball (if there are no ricochets) in the game interface, a green arrow lights up near the ball, then you can beat.



If it is red, the bot immediately reclassifies it into the opposite type (now it is solid for the bot), discards all the blows found on it and takes the next best blow, which does not concern this particular ball. The bot is trying to hit another ball. If he is also incorrectly classified - history repeats itself. And so on, until the bot either fails to time out, or ...
... logic is more cunning. After all, this situation is also possible: the beginning of the party; bot scored the first and only ball. In fact, it is solid, while the bot thinks it is clogged striped. This is the second situation described in the beginning of the section.

What will happen next? The bot will be absolutely sure that he needs to score striped ones, when in reality they are solid. The bot will aim at the first striped ball - the red arrow, the second striped ball - again the red arrow, the third - the same. In fact, this process will not last until the timeout. I programmed this way: if more than half of the balls on the table give a red arrow, then the type of the ball in the stack of balls that are scored is simply recognized incorrectly. Then the bot immediately reclassifies the type of balls being hammered from the wrong striped ones to the correct solid ones and is already looking for strikes on the solid ones, withdrawing itself from a steep dive. And this is all - if there is time.

How is the chat?


In war, any means are good. And, therefore, it is possible and necessary to look for such means. For example, the means of influence on the enemy. The game essentially completely closes the opponents from each other. They interact only through the gaming table. Game table and ... chat! Yes, the game has a chat. And this is the maximum available channel of verbal communication. And, therefore, the impact. What can be done through chat with the enemy? Calling him to surrender, of course, will not work, but you can cool his attention and even nerves! Ay yes method!

I decided not to bother with the connectivity of the broadcast text. After all, chat is a secondary task. Let it be just some kind of short message.

On a separate occasion, I programmed several greeting options. They are spoken by the bot at the beginning of the game to a) attract the opponent to the chat function and b) immediately tune him to what I will talk to him. And good humor compels to answer, I tell you. To answer means to connect to the brain an additional function that distracts from the game of talk and reaction to messages. I note that the overwhelming majority of players respond with a greeting. Fine! Let them think that a person is playing with them (they can't even come to mind, that there could be a robot)!

Well, then - sausage shop! Here come into the course and jokes, pribibirovki, and subring, and teasers, and incoherent nonsense, and demotivating phrases ... Of the ten people about two seriously communicate with the bot. Many respond obscene. Raging. Bot forces them. It's great!

Well, the chat functionality itself is implemented after the bot hits and waits for the physics to trigger; great place to "talk". I simply place the selected phrase on the clipboard and, through the on-screen baloon, send a message to my opponent. The tricks here are zero.

That's all


On this my long and painstaking work on the bot has been completed. It remains only to enjoy the fruits of labor.

Some video


I place for you a presentation video of a very old version of the bot:



And the video of the new version of many hours of play in automatic mode:



Thanks for attention!

Source: https://habr.com/ru/post/251101/


All Articles