📜 ⬆️ ⬇️

Comparison of 2048 game strategies

2048 is a game that appeared in 2014 and quickly became a popular time killer. Simple rules of the game only push players to create clones, bots and winning strategies. Including on Habré. ( Clone , bot , strategy ) This article tells about a handy tool for evaluating game strategies and examples of how it works on several bots.


Screenshot game



The tool itself consists of three parts. The first is the C ++ engine. You can play with it manually in the console. It works according to the following algorithm:


  1. Selects two random cells on the playing field, places two for each of them and displays the coordinates of these cells.


  2. Until the player makes a dead-end move (the turn after which the playing field does not change) the engine performs a cycle:


    1. Read the player's move.
    2. Run this move on the playing field.
    3. Print the coordinate of the cell in which the new random value (two or four) and the value itself appeared.

  3. At the end of the game displays the number of moves, the score and the time of the game in milliseconds.

To simulate the playing field, the engine uses a class from board.hpp . Announcement of this class with comments.


template<int n> class A{ //    n private: int left_adder(int&, int); // 16      move int left_compressor(int&, int); //     namespace int left_move_row(int); //    4   int left_move(); //      , int right_adder(int&, int); //         int right_compressor(int&, int); // int right_move_row(int); // int right_move(); // int up_adder(int&, int); // int up_compressor(int&, int); // int up_move_column(int); // int up_move(); // int down_adder(int&, int); // int down_compressor(int&, int); // int down_move_column(int); // int down_move(); // std::pair<int,int> random(); //         2  4 void out() const; //    a.    move(0) unsigned score = 0; //  bool deadlock = false; //       static std::mt19937 rand; //    std::array<std::array<int,n>,n> a; //       public: A(); // std::vector<int> init(); //            std::vector<int> move(int); //   unsigned get_score() const; //   }; 

The second is a bot whose strategy needs to be evaluated. He reads what the engine displays (for synchronizing the game fields of the engine and the bot), and displays the move that the strategy under test considers best. Bot can be written in any language. The only restriction is that you cannot make a move in a dead end direction.


And the third part is a simple bash script that "connects" the first two components and displays the statistics in a readable form.


Bots examples


All 4 bots are written in python using the board module and differ only in the evaluation function. One argument is passed to the evaluation function - the current state of the playing field. To determine the available moves, the playing field has a deadlock method. The main function communicates with the engine.


1. Random selection


Bot makes a random available move. This bot is made only to compare its effectiveness with the effectiveness of other bots.


Medium Result: 1250


Source
 import random import board def f(a): l = [1, 2, 3, 4] ans = random.choice(l) while a.deadlock(ans) and l != []: ans = random.choice(l) del l[l.index(ans)] if l == [] and a.deadlock(ans): ans = 0 return ans board.main(f) 

2. Moving in a circle


With its first move, the bot makes a move up, and then selects the next move clockwise skipping dead ends.


Median result: 2900


Source
 import board def f(a): global h ans = h % 4 + 1 while a.deadlock(ans) and ans != h: ans = ans % 4 + 1 h = ans return h h = 0 board.main(f) 

3. Everything in one corner


The bot makes its first move up. After each move up, selects the move to the right, and after each move to the right, move up. If the selected move is a dead end, the bot repeats the previous move. If the previous move is a dead end, then the bot tries to move to the left and at the most, move down.


Medium Result: 3900


Source
 import board def f(a): global h if h == 1: l = [2, 1] else: l = [1, 2] l += [4, 3, 0] while a.deadlock(l[0]) and l[0] != 0: l = l[1:] h = l[0] return h h = 0 board.main(f) 

4. Maximum points


This bot checks the moves in all four directions and selects the one that brings the maximum points.


Median result: 4000


Source
 import board def f(a): max = 0 ans = 0 for i in range(1, 5): if not a.deadlock(i): b = a.copy() t = b.move(i) if (t >= max): ans = i max = t return ans board.main(f) 

Statistics


All bots were tested 1000 times under the same conditions.


Bot numberAverage StepsMin StepsMax. StepsAverage scoreMin scoreMax. scoreAverage timeMin timeMax. time
one13150266125924032169060242
22335764728852921129610852234
33119885939057401470015578363
four317708264027412132927761162692

All sources on github


')

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


All Articles