📜 ⬆️ ⬇️

Russian AI Cup: technical details

Hello!

This is the second time we have been (and have practically held) the Russian AI Cup Championship . This time the participants competed in creating artificial intelligence for a small squad of fighters. In fact, participants were offered a turn-based strategy game with formally defined rules and an API for managing the squad.

We are pleased that the competition has found its fans. They had the opportunity to familiarize themselves with the project and assess the amount of work outside, but much remained behind the scenes. Now we are talking about this part. After all, whatever one may say, the event was prepared by programmers for programmers.

The main technical part of the preparation and conduct of this competition was carried out by the team of the Center for Olympiad Programmers Training at Saratov State University, maybe familiar to some of you from other projects: Codeforces, ACM-ICPC quarterfinals in Saratov, ICPC-challenge at the ACM-ICPC 2013 final .
')
Iron
The system has two Linux servers and two small Windows computing clusters of 5 machines each.
One of the Linux servers hosts the project database (approximately 5GB currently). We use MySQL 5.6, the entire base in InnoDB. The second server is mainly needed for the web - there are a site, a forum and infrastructure applications on it. Participants have already noticed that Java is the native language for system developers, this is true, and for the web we use the Nginx / Tomcat-7 bundle. Both servers have an Intel® Xeon® E5-2620 processor and a rather modest 16GB of RAM.

Computers for testing work under Windows 7 and are located in Saratov State University. I managed to use the newly acquired i5-3470 with 32GB. At first, 5 computers were launched, and shortly before the start of Round 1, another 5 were added, which made it possible to reduce the testing interval of fights in the Sandbox from 1 hour to 30 minutes.

System components
The Russian AI Cup system consists of several components that provide the following functionality (only the most important):

● the participant has the opportunity to send the implementation of the game strategy,
● Participant or system creates a battle to be tested.
● the battle is tested, for which the processes of the participants and the game engine are started,
● The course of the battle can be viewed by the participant.

Here is a diagram of the entire system:



Participants' strategies are compiled into binaries (or not compiled, for example, as for Python), which, when launched, read descriptions of the tcp world and write the player's moves.

Briefly about the components:
● Database - stores the state of the system. Works on a dedicated database server.
● Contester (kontester) - takes the raw strategies and games from the base, gives tasks to the Invoker and updates the state of the strategy / game in the base after the answer. Run on web server.
● Invoker (invoker) - receives a task to compile, verify a strategy or test a game, process the task, return the answer to the contester. Inkers are running on a compute cluster. To simulate combat, the invoker launches the game server and game strategies.
● Game Server - is started by the invoker to simulate the battle. This application contains the logic of the game.
● Invoker's Cache - shared cache for invokers; it stores compiled binaries.
● Boombox - a repository for logs of games (the player shows the games by it) and tcpdump (you can play games with the help of a ripiter).
● Repeater is a simple utility that extorts the tcpdump of the desired game for the desired strategy and starts giving away its strategies under the guise of the state of the world. Tcpdump contains exactly everything that was sent to the strategy when testing during a battle simulation.

Now more about some of the components.

Contester is a special web application that performs all-all manipulations with games, attempts, ratings, stages of the competition and many others in the database, while the site is used mostly for displaying information (except for adding custom games and ). Kontester creates new games according to the plan, depending on the rules of a particular stage of the competition, and accumulates various tasks such as testing games, compiling and checking strategies, updating the rating. Rating kontester updates itself when it considers it necessary and for this there is an opportunity. Tasks for testing and compiling disassemble invoker.

Invoker-s are the main workers of AI Cup. As soon as they have a free minute, they turn to the contest with a request to issue them a task. For calls to Contester, the Apache XML-RPC protocol implementation is used, through which Google Protobuf objects are passed. Such an approach, on the one hand, allows replacing any component of the system with its implementation in another language, and, on the other, allows you to conveniently support different versions of objects (message in Protobuf terminology), add new fields and modify existing ones. As an example of such an object, a prototype of a compilation task can be given:

message CompileRequest { required string id = 1; required File file = 2; optional string description = 3; } 


Here, fields of the string type are analogs of string classes in various languages ​​and, in particular, of the java.lang.String class in Java. The file field is another Protobuf object and has the following structure:

 message File { required string name = 1; optional string type = 2; optional Blob content = 3; optional string uid = 4; } 


The file object is the base for other objects in our protocol and is also used in other requests, for example, in a game testing request. If the file is small (less than 32Kb), then its content is transferred directly to the content field, which has the following structure:

 message Blob { required bytes compressed_bytes = 1; required bytes original_bytes_sha256 = 2; } 


For large files, the uid is passed in - a unique identifier. Any file can be found by the uid in Invoker's Cache. If there is no file in the cache, the invoker requests the file from the contester and puts it in the cache. GridFS, which runs on top of MongoDB, was used as the cache engine.

After receiving the task, Invoker compiles the strategy, he also prepares the launch of the game, lays out the compiled strategies and the game simulator according to the catalogs, and then sets up and launches it. The inkers are on the cluster computers, one per machine. Depending on the settings, the invoker can perform tasks as multithreaded, as well as sequentially, in one stream.

The launch of game strategies is carried out in the sandbox, which is obtained by launching from under a user with limited rights, interception of some functions (approximately as written here ), by the security of the virtual machine (if the program is executed in vm, like Java or C #).

Game server - he is a game simulator, he is a game engine. Each participant can download the Local runner , which is a version of the Game server with limited functionality. The game server contains all the game logic and is responsible for simulating each specific battle, launching strategies specified by the programmer in a certain order and with specified connection descriptors (port of the local machine for connection and secret key for authorization of the strategy).

In fact, the Game server is the only component of the system that is tightly tied to a specific type of game. Compared to last year, only minor changes were made to all the others (meaning only those related to migration to the new game).

Strategies are also available to participants in the form of a CGDK (CodeGame DevKit) set for different languages. Immediately after launching, the strategy establishes connection with the server on the TCP port specified by it and begins to communicate. Communication consists of a series of question-answer series. The game server transmits the “cast” strategies of the game world, adapted for a specific player, as a question, the answer is the desire of the strategy to perform an action in this world.

After testing the game, its log and TCP dumps of the data sent by the Game server of each of the strategies are saved in the Boombox .

Boombox is a special binary data repository that works via http. Invoker and the game server write data to it, which the Boombox then sends to the participants directly to the browser or to the Repeater. Written using the asynchronous capabilities of the Servlet API 3. In the future, it can work in the mode when data is simultaneously written to it and the same data is read. This mode can be useful for the implementation of the possibility of viewing the battle in the process of testing it. Boombox is able to give data compressed by chunks to save traffic.

Website - project site. Written using the same technologies as Codeforces and some of our other projects. We used our own little Nocturne framework, the main utility of which here is that it can on the fly on F5 in the browser recompile and redevelop the web application, which makes development on statically-typed Java in speed similar to how you can write on dynamic languages. At the same time, all the charms of static typing remain, which we like very much. Similar functionality is positioned as a killer feature of the Play! Framework, but we use our own development.

Player - written in JavaScript, displays the progress of the game on the Canvas. When starting, it makes a request to the Boombox, gets a game log (as a set of lines, each in JSON) and draws what is happening. Last year there was support for rendering sprites both on Canvas and using DOM, but during the year the implementation of Canvas in browsers improved - the second option was no longer supported. By the way, the game log had to be compressed with tricks in the style of “not transmitting an object if it has not changed.” Iteration through such improvements has reduced the amount of traffic by about an order of magnitude.

Total
The developed system during the championship proved to be from the good side, everything worked clearly and quickly. This year, it was possible to manage to implement most of the “hoteles” on the part of the community, - this is how friends appeared, detailed reports on the reasons for the fall of strategies, and other chips.

A total of about 2 megabytes of code was written in Java only, which amounted to about 60 thousand lines or ~ 500 classes. The throughput of the testing system in the Final was about 43 fights per minute and rested solely on the work of the participants' strategies.

Judging by the feedback from participants, our forces were not wasted. We will read with interest your feedback on the championship.

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


All Articles