diff --git a/src/bot/handlers/messageCreate.js b/src/bot/handlers/messageCreate.js index c0af9b0..8777673 100644 --- a/src/bot/handlers/messageCreate.js +++ b/src/bot/handlers/messageCreate.js @@ -16,7 +16,7 @@ import { calculateMaxPrice } from '../../utils/index.js'; import { channelPointsHandler, slowmodesHandler, randomSkinPrice, initTodaysSOTD } from '../../game/points.js'; -import { requestTimestamps, activeSlowmodes, activePolls, skins } from '../../game/state.js'; +import {requestTimestamps, activeSlowmodes, activePolls, skins, activeSolitaireGames} from '../../game/state.js'; import { flopoDB, getUser, @@ -27,6 +27,7 @@ import { getAllSkins, hardUpdateSkin } from '../../database/index.js'; import {client} from "../client.js"; +import {autoSolveMoves} from "../../game/solitaire.js"; // Constants for the AI rate limiter const MAX_REQUESTS_PER_INTERVAL = parseInt(process.env.MAX_REQUESTS || "5"); @@ -280,5 +281,9 @@ async function handleAdminCommands(message) { }) console.log('Reworked', dbSkins.length, 'skins.'); break; + case `${prefix}:solve-solitaire`: + autoSolveMoves( + { "tableauPiles": [ [ { "suit": "d", "rank": "K", "faceUp": true }, { "suit": "s", "rank": "Q", "faceUp": true }, { "suit": "d", "rank": "J", "faceUp": true }, { "suit": "c", "rank": "T", "faceUp": true }, { "suit": "h", "rank": "9", "faceUp": true }, { "suit": "c", "rank": "8", "faceUp": true }, { "suit": "h", "rank": "7", "faceUp": true }, { "suit": "c", "rank": "6", "faceUp": true }, { "suit": "h", "rank": "5", "faceUp": true } ], [ { "suit": "h", "rank": "K", "faceUp": true }, { "suit": "c", "rank": "Q", "faceUp": true }, { "suit": "h", "rank": "J", "faceUp": true }, { "suit": "s", "rank": "T", "faceUp": true }, { "suit": "d", "rank": "9", "faceUp": true } ], [ { "suit": "s", "rank": "K", "faceUp": true }, { "suit": "d", "rank": "Q", "faceUp": true }, { "suit": "c", "rank": "J", "faceUp": true }, { "suit": "h", "rank": "T", "faceUp": true }, { "suit": "c", "rank": "9", "faceUp": true }, { "suit": "h", "rank": "8", "faceUp": true } ], [], [], [ { "suit": "c", "rank": "K", "faceUp": true }, { "suit": "h", "rank": "Q", "faceUp": true }, { "suit": "s", "rank": "J", "faceUp": true }, { "suit": "d", "rank": "T", "faceUp": true }, { "suit": "s", "rank": "9", "faceUp": true }, { "suit": "d", "rank": "8", "faceUp": true }, { "suit": "c", "rank": "7", "faceUp": true }, { "suit": "h", "rank": "6", "faceUp": true }, { "suit": "c", "rank": "5", "faceUp": true }, { "suit": "h", "rank": "4", "faceUp": true } ], [ { "suit": "h", "rank": "3", "faceUp": true } ] ], "foundationPiles": [ [ { "suit": "c", "rank": "A", "faceUp": true }, { "suit": "c", "rank": "2", "faceUp": true }, { "suit": "c", "rank": "3", "faceUp": true }, { "suit": "c", "rank": "4", "faceUp": true } ], [ { "suit": "h", "rank": "A", "faceUp": true }, { "suit": "h", "rank": "2", "faceUp": true } ], [ { "suit": "s", "rank": "A", "faceUp": true }, { "suit": "s", "rank": "2", "faceUp": true }, { "suit": "s", "rank": "3", "faceUp": true }, { "suit": "s", "rank": "4", "faceUp": true }, { "suit": "s", "rank": "5", "faceUp": true }, { "suit": "s", "rank": "6", "faceUp": true }, { "suit": "s", "rank": "7", "faceUp": true }, { "suit": "s", "rank": "8", "faceUp": true } ], [ { "suit": "d", "rank": "A", "faceUp": true }, { "suit": "d", "rank": "2", "faceUp": true }, { "suit": "d", "rank": "3", "faceUp": true }, { "suit": "d", "rank": "4", "faceUp": true }, { "suit": "d", "rank": "5", "faceUp": true }, { "suit": "d", "rank": "6", "faceUp": true }, { "suit": "d", "rank": "7", "faceUp": true } ] ], "stockPile": [], "wastePile": [], "seed": "mgqnxweyjp8fggj6ol9", "isSOTD": false, "score": 205, "moves": 90, "hist": [ { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 3, "sourceCardIndex": 3, "destPileType": "tableauPiles", "destPileIndex": 4, "cardsMoved": [ { "suit": "c", "rank": "9", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 6, "sourceCardIndex": 6, "destPileType": "foundationPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "c", "rank": "A", "faceUp": true } ], "cardWasFlipped": true, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 5, "sourceCardIndex": 5, "destPileType": "tableauPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "c", "rank": "5", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 5, "sourceCardIndex": 4, "destPileType": "tableauPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "h", "rank": "4", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 6, "sourceCardIndex": 5, "destPileType": "tableauPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "h", "rank": "9", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 6, "sourceCardIndex": 4, "destPileType": "foundationPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "h", "rank": "A", "faceUp": true } ], "cardWasFlipped": true, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 6, "sourceCardIndex": 3, "destPileType": "tableauPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "d", "rank": "8", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 6, "sourceCardIndex": 2, "destPileType": "tableauPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "c", "rank": "8", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "draw", "card": { "suit": "h", "rank": "2", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 0, "destPileType": "foundationPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "h", "rank": "2", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "h", "rank": "Q", "faceUp": true } }, { "move": "draw", "card": { "suit": "h", "rank": "5", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 1, "destPileType": "tableauPiles", "destPileIndex": 3, "cardsMoved": [ { "suit": "h", "rank": "5", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "d", "rank": "K", "faceUp": true } }, { "move": "draw", "card": { "suit": "c", "rank": "J", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 2, "destPileType": "tableauPiles", "destPileIndex": 6, "cardsMoved": [ { "suit": "c", "rank": "J", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 4, "sourceCardIndex": 4, "destPileType": "tableauPiles", "destPileIndex": 6, "cardsMoved": [ { "suit": "h", "rank": "T", "faceUp": true }, { "suit": "c", "rank": "9", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "draw", "card": { "suit": "d", "rank": "4", "faceUp": true } }, { "move": "draw", "card": { "suit": "h", "rank": "K", "faceUp": true } }, { "move": "draw", "card": { "suit": "s", "rank": "3", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 4, "destPileType": "tableauPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "s", "rank": "3", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "c", "rank": "K", "faceUp": true } }, { "move": "draw", "card": { "suit": "h", "rank": "7", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 5, "destPileType": "tableauPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "h", "rank": "7", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 3, "sourceCardIndex": 2, "destPileType": "tableauPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "c", "rank": "6", "faceUp": true }, { "suit": "h", "rank": "5", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "draw", "card": { "suit": "h", "rank": "8", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 5, "destPileType": "tableauPiles", "destPileIndex": 6, "cardsMoved": [ { "suit": "h", "rank": "8", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "c", "rank": "Q", "faceUp": true } }, { "move": "draw", "card": { "suit": "s", "rank": "A", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 6, "destPileType": "foundationPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "s", "rank": "A", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "d", "rank": "J", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 6, "destPileType": "tableauPiles", "destPileIndex": 5, "cardsMoved": [ { "suit": "d", "rank": "J", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 0, "sourceCardIndex": 0, "destPileType": "tableauPiles", "destPileIndex": 5, "cardsMoved": [ { "suit": "c", "rank": "T", "faceUp": true }, { "suit": "h", "rank": "9", "faceUp": true }, { "suit": "c", "rank": "8", "faceUp": true }, { "suit": "h", "rank": "7", "faceUp": true }, { "suit": "c", "rank": "6", "faceUp": true }, { "suit": "h", "rank": "5", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "c", "rank": "4", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 6, "destPileType": "tableauPiles", "destPileIndex": 5, "cardsMoved": [ { "suit": "c", "rank": "4", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "s", "rank": "5", "faceUp": true } }, { "move": "draw", "card": { "suit": "h", "rank": "J", "faceUp": true } }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 4, "sourceCardIndex": 3, "destPileType": "tableauPiles", "destPileIndex": 5, "cardsMoved": [ { "suit": "d", "rank": "3", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "draw", "card": { "suit": "c", "rank": "2", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 8, "destPileType": "foundationPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "c", "rank": "2", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "c", "rank": "7", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 8, "destPileType": "tableauPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "c", "rank": "7", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 1, "sourceCardIndex": 1, "destPileType": "tableauPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "h", "rank": "6", "faceUp": true }, { "suit": "c", "rank": "5", "faceUp": true }, { "suit": "h", "rank": "4", "faceUp": true }, { "suit": "s", "rank": "3", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "draw", "card": { "suit": "d", "rank": "5", "faceUp": true } }, { "move": "draw", "card": { "suit": "d", "rank": "A", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 9, "destPileType": "foundationPiles", "destPileIndex": 3, "cardsMoved": [ { "suit": "d", "rank": "A", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "c", "rank": "3", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 9, "destPileType": "foundationPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "c", "rank": "3", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "d", "rank": "7", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 9, "destPileType": "tableauPiles", "destPileIndex": 3, "cardsMoved": [ { "suit": "d", "rank": "7", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "d", "rank": "6", "faceUp": true } }, { "move": "draw-reset" }, { "move": "draw", "card": { "suit": "h", "rank": "Q", "faceUp": true } }, { "move": "draw", "card": { "suit": "d", "rank": "K", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 1, "destPileType": "tableauPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "d", "rank": "K", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 5, "sourceCardIndex": 3, "destPileType": "tableauPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "s", "rank": "Q", "faceUp": true }, { "suit": "d", "rank": "J", "faceUp": true }, { "suit": "c", "rank": "T", "faceUp": true }, { "suit": "h", "rank": "9", "faceUp": true }, { "suit": "c", "rank": "8", "faceUp": true }, { "suit": "h", "rank": "7", "faceUp": true }, { "suit": "c", "rank": "6", "faceUp": true }, { "suit": "h", "rank": "5", "faceUp": true }, { "suit": "c", "rank": "4", "faceUp": true }, { "suit": "d", "rank": "3", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 5, "sourceCardIndex": 2, "destPileType": "foundationPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "s", "rank": "2", "faceUp": true } ], "cardWasFlipped": true, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 2, "sourceCardIndex": 8, "destPileType": "foundationPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "s", "rank": "3", "faceUp": true } ], "cardWasFlipped": true, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 1, "sourceCardIndex": 0, "destPileType": "foundationPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "s", "rank": "4", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 5, "sourceCardIndex": 1, "destPileType": "foundationPiles", "destPileIndex": 3, "cardsMoved": [ { "suit": "d", "rank": "2", "faceUp": true } ], "cardWasFlipped": true, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 0, "sourceCardIndex": 10, "destPileType": "foundationPiles", "destPileIndex": 3, "cardsMoved": [ { "suit": "d", "rank": "3", "faceUp": true } ], "cardWasFlipped": true, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 0, "sourceCardIndex": 9, "destPileType": "foundationPiles", "destPileIndex": 0, "cardsMoved": [ { "suit": "c", "rank": "4", "faceUp": true } ], "cardWasFlipped": true, "points": 11 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 5, "sourceCardIndex": 0, "destPileType": "tableauPiles", "destPileIndex": 6, "cardsMoved": [ { "suit": "s", "rank": "7", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "d", "rank": "4", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 1, "destPileType": "foundationPiles", "destPileIndex": 3, "cardsMoved": [ { "suit": "d", "rank": "4", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "h", "rank": "K", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 1, "destPileType": "tableauPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "h", "rank": "K", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "c", "rank": "K", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 1, "destPileType": "tableauPiles", "destPileIndex": 5, "cardsMoved": [ { "suit": "c", "rank": "K", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 0, "destPileType": "tableauPiles", "destPileIndex": 5, "cardsMoved": [ { "suit": "h", "rank": "Q", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 4, "sourceCardIndex": 2, "destPileType": "tableauPiles", "destPileIndex": 5, "cardsMoved": [ { "suit": "s", "rank": "J", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "draw", "card": { "suit": "c", "rank": "Q", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 0, "destPileType": "tableauPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "c", "rank": "Q", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "draw", "card": { "suit": "s", "rank": "5", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 0, "destPileType": "foundationPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "s", "rank": "5", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "h", "rank": "J", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 0, "destPileType": "tableauPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "h", "rank": "J", "faceUp": true } ], "cardWasFlipped": false, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 4, "sourceCardIndex": 1, "destPileType": "tableauPiles", "destPileIndex": 1, "cardsMoved": [ { "suit": "s", "rank": "T", "faceUp": true } ], "cardWasFlipped": true, "points": 1 }, { "move": "move", "sourcePileType": "tableauPiles", "sourcePileIndex": 4, "sourceCardIndex": 0, "destPileType": "foundationPiles", "destPileIndex": 2, "cardsMoved": [ { "suit": "s", "rank": "6", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "d", "rank": "5", "faceUp": true } }, { "move": "move", "sourcePileType": "wastePile", "sourcePileIndex": null, "sourceCardIndex": 0, "destPileType": "foundationPiles", "destPileIndex": 3, "cardsMoved": [ { "suit": "d", "rank": "5", "faceUp": true } ], "cardWasFlipped": false, "points": 11 }, { "move": "draw", "card": { "suit": "d", "rank": "6", "faceUp": true } } ], "hardMode": false, "autocompleting": false } + ); } } \ No newline at end of file diff --git a/src/game/solitaire.js b/src/game/solitaire.js index faf0e82..a054603 100644 --- a/src/game/solitaire.js +++ b/src/game/solitaire.js @@ -296,6 +296,71 @@ export function checkWinCondition(gameState) { return foundationCardCount === 52; } +/** + * Checks if the game can be automatically solved (all tableau cards are face-up). + * @param {Object} gameState - The current state of the game. + * @returns {boolean} True if the game can be auto-solved. + */ +export function checkAutoSolve(gameState) { + if (gameState.stockPile.length > 0 || gameState.wastePile.length > 0) return false; + for (const pile of gameState.tableauPiles) { + for (const card of pile) { + if (!card.faceUp) return false; + } + } + return true; +} + +export function autoSolveMoves(gameState) { + const moves = []; + const foundations = gameState.foundationPiles; + const tableau = gameState.tableauPiles; + + function canMoveToFoundation(card) { + const foundationPile = foundations.find(pile => pile[pile.length - 1].suit === card.suit || pile.length === 0); + if (foundationPile.length === 0) { + return card.rank === 'A'; // Only Ace can be placed on empty foundation + } else { + const topCard = foundationPile[foundationPile.length - 1]; + return card.suit === topCard.suit && getRankValue(card.rank) === getRankValue(topCard.rank) + 1; + } + } + + let moved; + do { + moved = false; + + for (let i = 0; i < tableau.length; i++) { + const column = tableau[i]; + if (column.length === 0) continue; + + const card = column[column.length - 1]; // Top card of the tableau column + const foundationIndex = foundations.findIndex(pile => pile[pile.length - 1].suit === card.suit || pile.length === 0); + console.log(card.rank + card.suit + " to " + foundationIndex) + if(canMoveToFoundation(card)) { + tableau[i].pop() + foundations[foundationIndex].push(card) + console.log("moved" + card.rank + card.suit + " to " + foundationIndex) + moved = true; + moves.push({ + sourcePileType: 'tableauPiles', + sourcePileIndex: i, + sourceCardIndex: column.length - 1, + destPileType: 'foundationPiles', + destPileIndex: foundationIndex, + cardsMoved: [card], + cardWasFlipped: false, + points: 11 + }); + } + } + } while (moved)//(foundations.reduce((acc, pile) => acc + pile.length, 0)); + + console.log("Auto-solve moves:"); + console.log(moves); + return moves; +} + /** * Reverts the game state to its previous state based on the last move in the history. * This function mutates the gameState object directly. diff --git a/src/server/routes/solitaire.js b/src/server/routes/solitaire.js index a0b579f..0824fa0 100644 --- a/src/server/routes/solitaire.js +++ b/src/server/routes/solitaire.js @@ -3,7 +3,7 @@ import express from 'express'; // --- Game Logic Imports --- import { createDeck, shuffle, deal, isValidMove, moveCard, drawCard, - checkWinCondition, createSeededRNG, seededShuffle, undoMove, draw3Cards + checkWinCondition, createSeededRNG, seededShuffle, undoMove, draw3Cards, checkAutoSolve, autoSolveMoves } from '../../game/solitaire.js'; // --- Game State & Database Imports --- @@ -60,6 +60,7 @@ export function solitaireRoutes(client, io) { gameState.moves = 0; gameState.hist = []; gameState.hardMode = hardMode ?? false; + gameState.autocompleting = false; activeSolitaireGames[userId] = gameState; res.json({ success: true, gameState }); @@ -94,6 +95,7 @@ export function solitaireRoutes(client, io) { seed: sotd.seed, hist: [], hardMode: false, + autocompleting: false, }; activeSolitaireGames[userId] = gameState; @@ -140,6 +142,13 @@ export function solitaireRoutes(client, io) { moveCard(gameState, moveData); updateGameStats(gameState, 'move', moveData); + const canAutoSolve = checkAutoSolve(gameState); + if (canAutoSolve) { + gameState.autocompleting = true; + // TODO: start auto-completing moves with interval + autoSolveMoves(gameState) + } + const win = checkWinCondition(gameState); if (win) { gameState.isDone = true;