自动进行Coin Craze游戏

in STEEM CN/中文yesterday

每周Succinct都会发$10 credit用于游戏,而其中最快消费掉这些credit的方式是用于Coin Craze的游戏

这游戏每局1分钟,得分的方式是选择靠近的数字加起来等于10。得分超过60就会获得最高的6个星星(消费$0.6),也就是玩个16分钟就可以消费完$10 credit

这里分享一下这个游戏的自动脚本

// Script to automate Coin Craze game
// To use: Copy and paste into browser console at https://testnet.succinct.xyz/coin

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

async function solveCoinCraze() {
    // Function to simulate mouse events
    function simulateMouseEvent(element, x, y, type) {
        const rect = element.getBoundingClientRect();
        const event = new MouseEvent(type, {
            bubbles: true,
            cancelable: true,
            view: window,
            clientX: rect.left + x,
            clientY: rect.top + y,
            screenX: rect.left + x,
            screenY: rect.top + y,
            buttons: type === 'mouseup' ? 0 : 1,
            button: 0,
            relatedTarget: null,
        });
        element.dispatchEvent(event);
    }

    // Function to get coin value
    function getCoinValue(coin) {
        return parseInt(coin.textContent);
    }

    // Function to check if coins are in a straight line
    function areInStraightLine(coins, indices) {
        if (indices.length < 2) return true;
        
        const rects = indices.map(i => coins[i].getBoundingClientRect());
        const centers = rects.map(rect => ({
            x: rect.left + rect.width/2,
            y: rect.top + rect.height/2
        }));

        // Check if all coins are horizontally aligned (same y)
        const isHorizontal = centers.every(c => Math.abs(c.y - centers[0].y) < 15);
        if (isHorizontal) {
            // Sort by x coordinate
            const sortedIndices = [...indices].sort((a, b) => {
                const rectA = coins[a].getBoundingClientRect();
                const rectB = coins[b].getBoundingClientRect();
                return (rectA.left + rectA.width/2) - (rectB.left + rectB.width/2);
            });
            
            // Check if coins are consecutive
            for (let i = 1; i < sortedIndices.length; i++) {
                const rect1 = coins[sortedIndices[i-1]].getBoundingClientRect();
                const rect2 = coins[sortedIndices[i]].getBoundingClientRect();
                const distance = (rect2.left + rect2.width/2) - (rect1.left + rect1.width/2);
                if (distance > rect1.width * 2) return false;
            }
            return true;
        }

        // Check if all coins are vertically aligned (same x)
        const isVertical = centers.every(c => Math.abs(c.x - centers[0].x) < 15);
        if (isVertical) {
            // Sort by y coordinate
            const sortedIndices = [...indices].sort((a, b) => {
                const rectA = coins[a].getBoundingClientRect();
                const rectB = coins[b].getBoundingClientRect();
                return (rectA.top + rectA.height/2) - (rectB.top + rectB.height/2);
            });
            
            // Check if coins are consecutive
            for (let i = 1; i < sortedIndices.length; i++) {
                const rect1 = coins[sortedIndices[i-1]].getBoundingClientRect();
                const rect2 = coins[sortedIndices[i]].getBoundingClientRect();
                const distance = (rect2.top + rect2.height/2) - (rect1.top + rect1.height/2);
                if (distance > rect1.height * 2) return false;
            }
            return true;
        }

        return false;
    }

    // Function to find sequence of adjacent coins that sum to 10
    function findCoinCombination(coins) {
        const startTime = Date.now();
        
        // Try all possible combinations
        for (let i = 0; i < coins.length; i++) {
            const value1 = getCoinValue(coins[i]);
            if (value1 > 10) continue;

            // Get nearby coins for efficiency
            const rect1 = coins[i].getBoundingClientRect();
            const nearby = [];
            for (let j = 0; j < coins.length; j++) {
                if (i === j) continue;
                const rect2 = coins[j].getBoundingClientRect();
                const dx = (rect2.left + rect2.width/2) - (rect1.left + rect1.width/2);
                const dy = (rect2.top + rect2.height/2) - (rect1.top + rect1.height/2);
                const distance = Math.sqrt(dx * dx + dy * dy);
                if (distance < rect1.width * 2.5) {
                    nearby.push(j);
                }
            }

            // Try two-coin combinations with nearby coins
            for (const j of nearby) {
                const value2 = getCoinValue(coins[j]);
                const sequence = [i, j];
                
                if (value1 + value2 === 10 && areInStraightLine(coins, sequence)) {
                    return sequence;
                }

                // Try three-coin combinations with another nearby coin
                if (value1 + value2 < 10) {
                    for (const k of nearby) {
                        if (k === i || k === j) continue;
                        const value3 = getCoinValue(coins[k]);
                        
                        if (value1 + value2 + value3 === 10) {
                            const sequence3 = [i, j, k];
                            if (areInStraightLine(coins, sequence3)) {
                                return sequence3;
                            }
                        }
                    }
                }
            }

            // Check if we're taking too long
            if (Date.now() - startTime > 50) {
                return null;
            }
        }
        
        return null;
    }

    // Function to handle game over sequence
    async function handleGameOver() {
        // Check for "Game Over!" text
        const gameOverText = document.evaluate(
            '/html/body/div[1]/main/div[1]/div/div/div[2]/div/div/div[2]/div/div/h2',
            document,
            null,
            XPathResult.FIRST_ORDERED_NODE_TYPE,
            null
        ).singleNodeValue;

        if (gameOverText && gameOverText.textContent.includes('Game Over!')) {
            console.log('Game Over detected, handling end sequence...');
            
            // Click "Confirm Score"
            const confirmScoreBtn = document.evaluate(
                '/html/body/div[1]/main/div[1]/div/div/div[2]/div/div/div[2]/div/div/div[2]/button[1]',
                document,
                null,
                XPathResult.FIRST_ORDERED_NODE_TYPE,
                null
            ).singleNodeValue;
            
            if (confirmScoreBtn) {
                confirmScoreBtn.click();
                await sleep(1000); // Wait for confirmation dialog
                
                // Click "Confirm"
                const confirmBtn = document.evaluate(
                    '/html/body/div[1]/main/div[1]/div/div/div[2]/div/div/div[3]/div/div/button[2]',
                    document,
                    null,
                    XPathResult.FIRST_ORDERED_NODE_TYPE,
                    null
                ).singleNodeValue;
                
                if (confirmBtn) {
                    confirmBtn.click();
                    await sleep(1000); // Wait for play again button
                    
                    // Click "Play Again!"
                    const playAgainBtn = document.evaluate(
                        '/html/body/div[1]/main/div[1]/div/div/div[2]/div/div/div[2]/div/div/div[2]/button[1]',
                        document,
                        null,
                        XPathResult.FIRST_ORDERED_NODE_TYPE,
                        null
                    ).singleNodeValue;
                    
                    if (playAgainBtn) {
                        playAgainBtn.click();
                        await sleep(1000); // Wait for new game to start
                        return true;
                    }
                }
            }
        }
        return false;
    }

    while (true) {
        try {
            // Check for game over first
            if (await handleGameOver()) {
                console.log('Starting new game...');
                continue;
            }

            // Get all coins using the specific selector
            const gameBoard = document.querySelector('body > div.fixed.inset-0.flex.flex-col.overflow-hidden.bg-cover.bg-center > main');
            if (!gameBoard) {
                await sleep(100);
                continue;
            }

            // Try different selectors for the coin container
            let container = gameBoard.querySelector('.game-board');
            if (!container) {
                container = gameBoard.querySelector('[class*="aspect-square"]');
            }
            if (!container) {
                container = gameBoard.querySelector('div[class*="relative"] > div > div');
            }
            
            if (!container) {
                await sleep(100);
                continue;
            }
            
            // Get all button elements within the container
            const coins = Array.from(container.querySelectorAll('button'));
            if (coins.length === 0) {
                await sleep(100);
                continue;
            }

            // Remove pointer-events-none class from parent elements
            let parent = container;
            while (parent) {
                if (parent.classList && parent.classList.contains('pointer-events-none')) {
                    parent.classList.remove('pointer-events-none');
                }
                parent = parent.parentElement;
            }

            // Find combination that sums to 10
            const combination = findCoinCombination(coins);
            if (!combination) {
                await sleep(100);
                continue;
            }

            // Log the selected coins and their sum
            const values = combination.map(i => getCoinValue(coins[i]));
            const sum = values.reduce((a, b) => a + b, 0);
            console.log(`Selected ${values.length} coins:`, values.join(' + '), '=', sum);

            // Select the coins
            const firstCoin = coins[combination[0]];
            simulateMouseEvent(firstCoin, 20, 20, 'mousedown');
            
            // Only move to the last coin directly
            const lastCoin = coins[combination[combination.length - 1]];
            simulateMouseEvent(lastCoin, 20, 20, 'mousemove');
            simulateMouseEvent(lastCoin, 20, 20, 'mouseup');

            // Give the game a short break
            await sleep(100);
        } catch (error) {
            console.error('Error:', error);
            await sleep(100);
        }
        // Add a small break between iterations to prevent freezing
        await new Promise(resolve => setTimeout(resolve, 0));
    }
}

// Start the solver
solveCoinCraze();

这脚本并不是完美,只能查看4个位置之内的数字之和,但是已经足够获得60积分

image.png

Sort:  
 yesterday 

感谢村长分享,还没来得及搞这个JS脚本