自动进行Coin Craze游戏
每周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积分
感谢村长分享,还没来得及搞这个JS脚本