chore: solitaire auto-complete first steps

This commit is contained in:
Milo
2025-10-14 17:05:15 +02:00
parent 6afa3d8e6b
commit ebbc28f52c
3 changed files with 81 additions and 2 deletions

File diff suppressed because one or more lines are too long

View File

@@ -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.

View File

@@ -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;