__       _          _                     _
 / _| __ _| |___  ___| |_ _ __ _   _  ___  (_) ___
| |_ / _` | / __|/ _ \ __| '__| | | |/ _ \ | |/ _ \
|  _| (_| | \__ \  __/ |_| |  | |_| |  __/_| | (_) |
|_|  \__,_|_|___/\___|\__|_|   \__,_|\___(_)_|\___/

== [Gemini capsule] * ============ [ 2014-04-05 ] ==
← Back

2048 game bot

Есть такая

игра 2048

, суть ее в том чтобы собрать квадрат 2048 из других меньших квадратов, складываются квадраты только с одинаковой цифрой 2+2, 4+4, 8+8 и т.д

Игра написана на Javascript и HTML, а это значит можно попробовать написать бота. Открыв инспектор я сразу посмотрел на структуру этих квадратов, все оказалось очень просто об этом ниже под катом.


8

как видно это это обычный div с классами tile-8 например означало что это “8”, чтобы распарсить все квадраты достаточно было сделать следующее:


var tiles = document.getElementsByClassName('tile');

После чего получив все элементы div с классом tile можно было легко с ними работать. Заморчиватся с умным алгоритмом нехотелось поэтому простой рандом из 4 типов ходов (влево, вверх, вправо, вниз) вполне подходил.

Чтобы реализовать эмуляцию нажатия кнопки в браузере нужно сделать следюющее


function keyDown(evt)

{

    var key;

    if(!evt)

    {

        evt = window.event;

        if(!evt.which)

        {

            key  =  evt.keyCode;

        }

    }

	else if(evt)

    {

        key = evt.which;

    }

}

function fireKey(el, key)

{

    if(document.createEventObject)

    {

        var eventObj = document.createEventObject();

        eventObj.keyCode = key;

        el.fireEvent("onkeydown", eventObj);

    }

	else if(document.createEvent)

    {

        var eventObj = document.createEvent("Events");

        eventObj.initEvent("keydown", true, true);

        eventObj.which = key;

        el.dispatchEvent(eventObj);

    }

}

fireKey(document.getElementByClassName('game-container')[0], 40);

Нужно создать обьект события нажатия кнопки, и присовать нужные свойства, в данном случае это keycode нужной кнопки.

В параметрах которые передаются в метод fireKey разберетесь сами.

Еще один момент, когда просиходит проигрышь, надо перезапускать игру, для этого надо отслеживать специальный div который становится видимым, и после этого надо нажимать кнопку New Game. Для этого надо просто отследить его свойство display.

На этом собствтенно все, в коде заложена возможность сделать бота более интелектуальным, можете попробовать сами.

Github:

https://github.com/noroot/2048-bot

Результат работы на видео:

Ну и для удобства код целиком здесь, чтобы его запустить надо скопировать, открыть игру и открыть консоль, и вставить туда этот код целиком, он сразу начнет работать.




/**

 * 2048 game bot

 * usage: startgame and paste code to browser development console

 */

function explode( delimiter, string ) {	// Split a string by string

	// 

	// +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)

	// +   improved by: kenneth

	// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)

	var emptyArray = { 0: '' };

	if ( arguments.length != 2

		|| typeof arguments[0] == 'undefined'

		|| typeof arguments[1] == 'undefined' )

	{

		return null;

	}

	if ( delimiter === ''

		|| delimiter === false

		|| delimiter === null )

	{

		return false;

	}

	if ( typeof delimiter == 'function'

		|| typeof delimiter == 'object'

		|| typeof string == 'function'

		|| typeof string == 'object' )

	{

		return emptyArray;

	}

	if ( delimiter === true ) {

		delimiter = '1';

	}

	return string.toString().split ( delimiter.toString() );

}

function keyDown(evt)

{

    var key;

    if(!evt)

    {

        evt = window.event;

        if(!evt.which)

        {

            key  =  evt.keyCode;

        }

    }

	else if(evt)

    {

        key = evt.which;

    }

}

function fireKey(el, key)

{

    if(document.createEventObject)

    {

        var eventObj = document.createEventObject();

        eventObj.keyCode = key;

        el.fireEvent("onkeydown", eventObj);

    }

	else if(document.createEvent)

    {

        var eventObj = document.createEvent("Events");

        eventObj.initEvent("keydown", true, true);

        eventObj.which = key;

        el.dispatchEvent(eventObj);

    }

}

function logscore()

{

	var tiles = [128, 256, 512, 1024, 2048];

	var arlen = tiles.length;

	for(var i = 0; i <= arlen;i++)

	{

		score = tiles[i];

		if (document.getElementsByClassName("tile-" + score).length != 0)

		{

			console.log("MAX SCORE=" + score);

		}

		else

		{

			console.log("FAIL");

		}

	}

}

// define key codes

var left = 37;

var up = 38;

var right = 39;

var down = 40;

var clicks = 0;

var tries = 0;

document.documentElement.focus();

document.onkeydown = keyDown;

//var fired = 0;

var matrix_object = [];

var matrix = [];

var selected_turn = 0;

var	prefered_turn = 0;

var gamebox = document.getElementsByClassName("game-container")[0];

function calculate_turn()

{

	var fired = 0;

	var arr = document.getElementsByClassName('tile');

	selected_turn = 0;

	prefered_turn = 0;

	var turns = [];

	matrix_object = [];

	// prepare object for more smart solving (not used in future)

	for(var i=0; i <= arr.length; i++)

	{

		var el = arr[i];

		if (el)

		{

			var t = explode("-", el.classList[1]);

			var tilescore = t[1];

			var t = explode("-", el.classList[2]);

			var tp = {'score': tilescore, 'x':t[2], 'y':t[3]};

			if (tp.x!=='undefined')

			{

				matrix_object.push(tp);

			}

		}

	}

	// TODO:

	// make clever work here

	// until clever work done just go random

	if (preferedturn == 0 || selectedturn == 0)

	{

		var keys = [up,right,down]; // tricky turns, without left turn in case of win

		var key = keys[Math.floor(Math.random() * keys.length)];

		selected_turn = key;

	}

	return selected_turn;

}

function make_turn()

{

	if (document.getElementsByClassName("game-over").length > 0)

	{

		console.clear();

		logscore();

		tries++;

		console.log("Restart (" + tries + ", "+clicks+")");

		clicks = 0;

		document.getElementsByClassName("restart-button")[0].click();

	}

	else if (document.getElementsByClassName("game-won").length > 0)

	{

		clearInterval(interval);

		console.log("win");

	}

	else

	{

		clicks++;

		var turn = calculate_turn();

		fireKey(gamebox, turn);

	}

}

var interval = setInterval(make_turn, 500);

console.log(matrix_object);

     ░▒▓▓▒░  FalseTrue - dmth's notes | Gemini Capsule [-]  ░▒▓▓▒░