Coder Social home page Coder Social logo

ethos2048-sui-game-bot's Introduction

Ethos2048-Sui-Game-Bot

hi im not a robot.

2048 oyunu olan her platformda çalışır ethos, singularity vs../ siteye sağ tıklayıp incele tuşuna basın ya da direk f12 basıp o ekrana erişin / açılan sayfada üstte Console yazan yere tıklayın ve alttaki kodu yapıştırın.

(function () {
    // Bot flags.
    var EVALUATE_ONLY = false;
    var AUTO_RETRY = false;

    // Search constants.
    var SEARCH_DEPTH = 4;
    var SEARCH_TIME = 50;
    var RETRY_TIME = 1000;
    var ACCEPT_DEFEAT_VALUE = -999999;

    // Evaluation constants.
    var NUM_EMPTY_WEIGHT = 5;
    var ADJ_DIFF_WEIGHT = -0.5;
    var INSULATION_WEIGHT = -2;
    var POSITION_WEIGHT = 0.04;
    var POSITION_VALUE = [
         0,  0,  0, 10,
         0,  0,  0, 15,
         0,  0, -5, 20,
        10, 15, 20, 50
    ];
    var LOG2 = {};
    for (var i = 0 ; i < 20; i++) {
        LOG2[1 << i] = i;
    }

    // Game constants.
    var GRID_SIZE = 4;
    var PROB_2 = 0.9;

    // Move constants. 
    // drow: delta along row axis
    // dcol: delta along column axis
    // dir: iteration direction for correct merging
    // keyCode: key code to send
    // key: key name to send
    var MOVE_UP = {
        drow: -1,
        dcol: 0,
        dir: 0,
        keyCode: 38,
        key: 'Up'
    };
    var MOVE_DOWN = {
        drow: 1,
        dcol: 0,
        dir: 1,
        keyCode: 40,
        key: 'Down'
    };
    var MOVE_LEFT = {
        drow: 0,
        dcol: -1,
        dir: 0,
        keyCode: 37,
        key: 'Left'
    };
    var MOVE_RIGHT = {
        drow: 0,
        dcol: 1,
        dir: 1,
        keyCode: 39,
        key: 'Right'
    };

    // If EVALUATE_ONLY flag is not set, play the game. If the flag is set (for
    // development purposes), just print detailed evaluation output.
    if (EVALUATE_ONLY) {
        var grid = getGrid();
        print(grid);
        evaluate(grid, true);
    }
    else {
        setInterval(nextMove, SEARCH_TIME);
    }

    // Press continue to keep playing if we win the game.
    setInterval(function() {
        if (gameWon()) {
            keepPlaying();
        }
    }, RETRY_TIME);

    // If AUTO_RETRY flag is set, print statistics and automatically retry after
    // losses.
    if (AUTO_RETRY) {
        var games = 0;
        var bestScore = 0;
        var averageScore = 0;
        var bestLargestTile = 0;
        var averageLargestTile = 0;

        setInterval(function() {
            if (gameLost()) {
                var score = getScore();
                bestScore = Math.max(bestScore, score);

                var grid = getGrid();
                var largestTile = 0;
                for (var i = 0; i < grid.length; i++) {
                    largestTile = Math.max(largestTile, grid[i]);
                }
                bestLargestTile = Math.max(bestLargestTile, largestTile);

                averageScore = (averageScore * games + score) / (games + 1);
                averageLargestTile = (averageLargestTile * games + largestTile) / (games + 1);
                games++;

                console.log('Game                   ' + games + '\n' +
                            'Score                  ' + score + '\n' +
                            'Largest tile           ' + largestTile + '\n' +
                            'Average score          ' + Math.round(averageScore) + '\n' +
                            'Average largest tile   ' + Math.round(averageLargestTile) + '\n' +
                            'Best score             ' + bestScore + '\n' +
                            'Best largest tile      ' + bestLargestTile + '\n' +
                            '\n');

                search.table = {};

                if (AUTO_RETRY)
                    tryAgain();
            }
        }, RETRY_TIME);
    }

    /**
     * Chooses and the next move and plays it.
     */
    function nextMove() {
        var grid = getGrid();
        var move = search(grid, SEARCH_DEPTH, Number.NEGATIVE_INFINITY, true);
        pressKey(move);
    }

    /**
     * Searches for the best move with depth-first search.
     * @param grid: flat array representation of game grid.
     * @param depth: search tree depth, where leaves are at depth 0.
     * @param alpha: lower bound on search value.
     * @param root: whether to treat the node as the root node.
     * @return best move at root nodes, value of best move at other nodes.
     */
    function search(grid, depth, alpha, root) {
        if (depth <= 0) {
            return evaluate(grid);
        }

        if (!search.table) {
            search.table = {};
        }

        // Look up game grid in the transposition table. 
        var key = getGridKey(grid);
        var entry = search.table[key];
        if (entry && entry.depth >= depth && (!entry.isBound || entry.value <= alpha)) {
            return root ? entry.move : entry.value;
        }

        // If there was a transposition entry and its value couldn't be used,
        // at least move its best move to the front of the current move list. 
        var moves = [ MOVE_RIGHT, MOVE_DOWN, MOVE_LEFT, MOVE_UP ];
        if (entry) {
            var index = moves.indexOf(entry.move);
            var temp = moves[index];
            moves[index] = moves[0];
            moves[0] = temp;
        }

        var bestMove = undefined;
        var alphaImproved = false;

        for (var i = 0; i < moves.length; i++) {
            var copyGrid = copy(grid);
            var move = moves[i];

            if (make(copyGrid, move)) {
                bestMove = bestMove || move;
                var value = Number.POSITIVE_INFINITY;

                // Try to put a 2 in each free square. Don't bother with 4s because
                // it doesn't seem to make any significant difference. Iterate from
                // the bottom right because that's the corner favoured; try to get
                // a minimum value early to exit early from the loop.
                for (var j = copyGrid.length - 1; j >= 0 && value > alpha; j--) {
                    if (!copyGrid[j]) {
                        copyGrid[j] = 2;
                        value = Math.min(value, search(copyGrid, depth - 1, alpha));
                        copyGrid[j] = 0;
                    }
                }

                if (value > alpha) {
                    alpha = value;
                    bestMove = move;
                    alphaImproved = true;
                }
            }
        }

        if (!bestMove) {
            return root ? MOVE_LEFT : ACCEPT_DEFEAT_VALUE + evaluate(grid);
        }

        // Store search results in the transposition table.
        search.table[key] = {
            depth: depth,
            value: alpha,
            move: bestMove,
            isBound: !alphaImproved
        };

        return root ? bestMove : alpha;
    }

    /**
     * Evaluates the given grid state.
     * @param grid: flat array representation of game grid.
     * @param logging: whether to log evaluation computation.
     * @return estimated value of grid state.
     */
    function evaluate(grid, logging) {
        var value = 0;

        var positionValue = 0;
        var adjDiffValue = 0;
        var insulationValue = 0;
        var numEmpty = 0;

        for (var r = 0; r < GRID_SIZE; r++) {
            for (var c = 0; c < GRID_SIZE; c++) {
                var tile = get(grid, r, c);
                if (!tile) {
                    numEmpty++;
                    continue;
                }
                positionValue += tile * POSITION_VALUE[r * GRID_SIZE + c];

                // Perform pairwise comparisons.
                if (c < GRID_SIZE - 1) {
                    var adjTile = get(grid, r, c + 1);
                    if (adjTile) {
                        adjDiffValue += levelDifference(tile, adjTile) * Math.log(tile + adjTile);

                        // Perform triplet comparisons.
                        if (c < GRID_SIZE - 2) {
                            var thirdTile = get(grid, r, c + 2);
                            if (thirdTile && levelDifference(tile, thirdTile) <= 1.1) {
                                var smallerTile = Math.min(tile, thirdTile);
                                insulationValue += levelDifference(smallerTile, adjTile) * Math.log(smallerTile);
                            }
                        }
                    }
                }

                // Perform pairwise comparisons.
                if (r < GRID_SIZE - 1) {
                    adjTile = get(grid, r + 1, c);
                    if (adjTile) {
                        adjDiffValue += levelDifference(tile, adjTile) * Math.log(tile + adjTile);

                        // Perform triplet comparisons.
                        if (c < GRID_SIZE - 2) {
                            var thirdTile = get(grid, r + 2, c);
                            if (thirdTile && levelDifference(tile, thirdTile) <= 1.1) {
                                var smallerTile = Math.min(tile, thirdTile);
                                insulationValue += levelDifference(smallerTile, adjTile) * Math.log(smallerTile);
                            }
                        }
                    }
                }
            }
        }

        // Equation for log-like curve that starts at 0, ramps up quickly up
        // to 10 at numEmpty = 5, and levels off nearly completed after that.
        var numEmptyValue = 11.12249 + (0.05735587 - 11.12249) / (1 + Math.pow((numEmpty / 2.480941), 2.717769));

        value += POSITION_WEIGHT * positionValue;
        value += NUM_EMPTY_WEIGHT * numEmptyValue;
        value += ADJ_DIFF_WEIGHT * adjDiffValue;
        value += INSULATION_WEIGHT * insulationValue;

        if (logging) {
            console.log('EVALUATION     ' + value + '\n' +
                        '  position     ' + (POSITION_WEIGHT * positionValue) + '\n' +
                        '  numEmpty     ' + (NUM_EMPTY_WEIGHT * numEmptyValue) + '\n' +
                        '  adjDiff      ' + (ADJ_DIFF_WEIGHT * adjDiffValue) + '\n' +
                        '  insulation   ' + (INSULATION_WEIGHT * insulationValue) + '\n'
            );
        }

        return value;
    }

    /**
     * Computes the stack level difference between two tiles.
     * @param tile1: first tile value.
     * @param tile2: second tile value.
     * @return stack level difference between two given tiles.
     */
    function levelDifference(tile1, tile2) {
        return tile1 > tile2 ? LOG2[tile1] - LOG2[tile2] : LOG2[tile2] - LOG2[tile1];
    }

    /**
     * Returns the tile value in the grid for a given position.
     * @param grid: flat array representation of game grid.
     * @param row: position row.
     * @param col: position column.
     * @return tile value in the grid for given position.
     */
    function get(grid, row, col) {
        return grid[row * GRID_SIZE + col];
    }

    /**
     * Sets the tile value in the grid for a given position.
     * @param grid: flat array representation of game grid.
     * @param row: position row.
     * @param col: position column.
     * @param tile: new tile value to assign.
     */
    function set(grid, row, col, tile) {
        grid[row * GRID_SIZE + col] = tile;
    }

    /**
     * Prints the given grid to the console.
     * @param grid: flat array representation of game grid.
     */
    function print(grid) {
        function pad(str, len) {
            len -= str.length;
            while (len-- > 0)
                str = ' ' + str;
            return str;
        }

        var result = '';
        for (var r = 0; r < GRID_SIZE; r++) {
            for (var c = 0; c < GRID_SIZE; c++) {
                var tile = get(grid, r, c);
                result += tile ? pad(tile + '', 5) : '    .';
            }
            result += '\n';
        }
        console.log(result);
    }

    /**
     * Copies the given grid.
     * @param grid: flat array representation of game grid.
     * @return copy of given grid.
     */
    function copy(grid) {
        return grid.slice();
    }

    /**
     * Determines whether the given location is within grid bounds.
     * @param row: position row.
     * @param col: position column.
     * @return whether the given location is within grid bounds.
     */
    function inBounds(row, col) {
        return 0 <= row && row < GRID_SIZE && 0 <= col && col < GRID_SIZE;
    }

    /**
     * Makes the given move on the grid without inserting new tile.
     * @param grid: flat array representation of game grid.
     * @param move: object containing move vectors.
     * @return whether the move was made successfully.
     */
    function make(grid, move) {
        var start = move.dir * (GRID_SIZE - 1);
        var end = (1 - move.dir) * (GRID_SIZE + 1) - 1;
        var inc = 1 - 2 * move.dir;

        var anyMoved = false;

        for (var r = start; r != end; r += inc) {
            for (var c = start; c != end; c += inc) {
                if (get(grid, r, c)) {
                    var newr = r + move.drow;
                    var newc = c + move.dcol;
                    var oldr = r;
                    var oldc = c;

                    while (inBounds(newr, newc)) {
                        var target = get(grid, newr, newc);
                        var tile = get(grid, oldr, oldc);
                        if (!target) {
                            set(grid, newr, newc, tile);
                            set(grid, oldr, oldc, 0);
                            anyMoved = true;
                        }
                        else if (target === tile) {
                            // negative to prevent additional merging
                            set(grid, newr, newc, -2 * tile);
                            set(grid, oldr, oldc, 0);
                            anyMoved = true;
                            break;
                        }
                        oldr = newr;
                        oldc = newc;
                        newr += move.drow;
                        newc += move.dcol;
                    }
                }
            }
        }

        if (!anyMoved) {
            return false;
        }

        var numEmpty = 0;
        for (var i = 0; i < grid.length; i++) {
            if (grid[i] < 0) {
                grid[i] *= -1;
            }
            else if (!grid[i]) {
                numEmpty++;
            }
        }

        if (numEmpty === 0) {
            throw 'No empty squares after making move.';
        }

        return true;
    }

    /**
     * Computes hash key for the given game grid.
     * @param grid: flat array representation of game grid.
     * @return hash key for the given game grid.
     */
    function getGridKey(grid) {
        if (!getGridKey.table1) {
            getGridKey.table1 = {};
            getGridKey.table2 = {};

            for (var i = 0; i < grid.length; i++) {
                for (var t = 2; t <= 8192; t *= 2) {
                    var key = t * grid.length + i;
                    getGridKey.table1[key] = Math.round(0xffffffff * Math.random());
                    getGridKey.table2[key] = Math.round(0xffffffff * Math.random());
                }
            }
        }

        var value1 = 0;
        var value2 = 0;
        for (var i = 0; i < grid.length; i++) {
            var tile = grid[i];
            if (tile) {
                var key = tile * grid.length + i;
                value1 ^= getGridKey.table1[key];
                value2 ^= getGridKey.table2[key];
            }
        }

        return value1 + '' + value2;
    }

    /**
     * Constructs current game grid from DOM.
     * @return flat array representation of game grid.
     */
    function getGrid() {
        var tileContainer = document.getElementsByClassName('tile-container')[0];
        var tileList = [];

        for (var i = 0 ; i < tileContainer.children.length; i++) {
            var tile = tileContainer.children[i];
            var tileInner = tile.children[0];
            var value = parseInt(tileInner.innerHTML);

            var className = tile.className;
            var positionPrefix = 'tile-position-';
            var positionIndex = className.indexOf(positionPrefix) + positionPrefix.length;
            var positionStr = className.substring(positionIndex, positionIndex + 3);
            var row = parseInt(positionStr[2]) - 1;
            var col = parseInt(positionStr[0]) - 1;

            tileList.push({
                value: value,
                row: row,
                col: col
            });
        }

        var grid = new Array(GRID_SIZE * GRID_SIZE);
        for (var i = 0; i < grid.length; i++) {
            grid[i] = 0;
        }
        for (var i = 0; i < tileList.length; i++) {
            var tile = tileList[i];
            set(grid, tile.row, tile.col, tile.value);
        }

        return grid;
    }

    /**
     * Emulates a keypress for a given move.
     * @param move: object containing key information.
     */
    function pressKey(move) {
        var event = new Event('keydown', {
            bubbles: true,
            cancelable: true
        });
        event.altKey = false;
        event.char = '';
        event.charCode = 0;
        event.ctrlKey = false;
        event.defaultPrevented = false;
        event.eventPhase = 3;
        event.isTrusted = true;
        event.key = move.key;
        event.keyCode = move.keyCode;
        event.locale = 'en-CA';
        event.location = 0;
        event.metaKey = false;
        event.repeat = false;
        event.shiftKey = false;
        event.which = move.keyCode;

        document.body.dispatchEvent(event);
    }

    /**
     * Determines whether the current game has been lost from the DOM.
     * @return whether current game has concluded.
     */
    function gameLost() {
        var gameMessage = document.getElementsByClassName('game-message')[0];
        return gameMessage.className.indexOf('game-over') >= 0;
    }

    /**
     * Determines whether the current game has been won from the DOM.
     * @return whether current game has concluded.
     */
    function gameWon() {
        var gameMessage = document.getElementsByClassName('game-message')[0];
        return gameMessage.className.indexOf('game-won') >= 0;
    }

    /**
     * Starts a new game when the current game has concluded.
     */
    function tryAgain() {
        var retryButton = document.getElementsByClassName('retry-button')[0];
        retryButton.click();
    }

    /**
     * Continues the game when the current game has been won.
     */
    function keepPlaying() {
        var keepPlayingButton = document.getElementsByClassName('keep-playing-button')[0];
        keepPlayingButton.click();
    }

    /**
     * Gets the current score from the DOM.
     * @return current score of game.
     */
    function getScore() {
        var scoreContainer = document.getElementsByClassName('score-container')[0];
        return parseInt(scoreContainer.innerHTML);
    }

    /**
     * Gets the best score from the DOM.
     * @return best score in all games.
     */
    function getBestScore() {
        var bestContainer = document.getElementsByClassName('best-container')[0];
        return parseInt(bestContainer.innerHTML);
    }
})();

ethos2048-sui-game-bot's People

Contributors

enzifiri avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.