From 38c40670e85ae6d421dc68e88fa30cde24116baa Mon Sep 17 00:00:00 2001 From: Lewis Cowles Date: Sun, 15 Sep 2024 11:02:30 +0100 Subject: [PATCH] feat: card selection in foundation --- components/klondike-solitaire.tsx | 46 ++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/components/klondike-solitaire.tsx b/components/klondike-solitaire.tsx index 83c8be3..7a1501c 100644 --- a/components/klondike-solitaire.tsx +++ b/components/klondike-solitaire.tsx @@ -110,16 +110,20 @@ export function KlondikeSolitaireComponent() { const moveCards = (sourceIndex: number, targetIndex: number, isFromWaste: boolean = false) => { const sourcePile = isFromWaste ? [waste[0]] : tableau[sourceIndex]; const targetPile = tableau[targetIndex]; - const cardsToMove = isFromWaste ? sourcePile : sourcePile.slice(sourcePile.findIndex(card => card.faceUp)); - + + // Only move the currently selected cards + const cardsToMove = isFromWaste ? sourcePile : selectedCards; + if ( cardsToMove.length > 0 && - (targetPile.length === 0 && cardsToMove[0].rank === 'K' || + (targetPile.length === 0 && cardsToMove[0].rank === 'K' || // Move to empty tableau with King targetPile.length > 0 && RANKS.indexOf(cardsToMove[0].rank) === RANKS.indexOf(targetPile[targetPile.length - 1].rank) - 1 && ['♠', '♣'].includes(cardsToMove[0].suit) !== ['♠', '♣'].includes(targetPile[targetPile.length - 1].suit)) ) { const newTableau = [...tableau]; + + // Remove the moved cards from the source pile if (!isFromWaste) { newTableau[sourceIndex] = sourcePile.slice(0, sourcePile.length - cardsToMove.length); if (newTableau[sourceIndex].length > 0) { @@ -128,16 +132,19 @@ export function KlondikeSolitaireComponent() { } else { setWaste(waste.slice(1)); } + + // Add the moved cards to the target pile newTableau[targetIndex] = [...targetPile, ...cardsToMove]; + setTableau(newTableau); setSelectedColumn(null); - setSelectedCards([]); + setSelectedCards([]); // Clear the selection setSelectedWasteCard(false); return true; } - + return false; - }; + }; const tryMoveToFoundation = () => { if (selectedWasteCard && waste.length > 0) { @@ -174,14 +181,23 @@ export function KlondikeSolitaireComponent() { case '7': const columnIndex = parseInt(e.key) - 1; if (selectedWasteCard) { - moveCards(0, columnIndex, true); + moveCards(0, columnIndex, true); // Move from waste to tableau } else if (selectedColumn === null) { + // No column selected yet, select the column setSelectedColumn(columnIndex); setSelectedCards(tableau[columnIndex].filter(card => card.faceUp)); + } else if (selectedColumn === columnIndex) { + // If the same column is selected again, allow partial selection by reducing selectedCards + const viableCardsToSelect = tableau[columnIndex].filter(card => card.faceUp); + const allSelected = viableCardsToSelect.length == selectedCards.length; + const noneSelected = selectedCards.length == 0; + const cardsUpToSelected = (noneSelected ? viableCardsToSelect : ((!allSelected ? [viableCardsToSelect[viableCardsToSelect.findIndex((card) => card == selectedCards[0]) - 1], ...selectedCards] : [viableCardsToSelect.at(-1)]).filter((val) => val) ?? [])) + setSelectedCards(cardsUpToSelected as Card[]); } else { + // Try to move the selected cards to the new column moveCards(selectedColumn, columnIndex); } - break; + break; case 'escape': setSelectedColumn(null); setSelectedCards([]); @@ -201,7 +217,7 @@ export function KlondikeSolitaireComponent() { ) : 'bg-blue-500'} flex items-center justify-center`}> {card.faceUp ? `${card.rank}${card.suit}` : ''} - ); + ); return ( @@ -238,7 +254,7 @@ export function KlondikeSolitaireComponent() {
{column.map((card, cardIndex) => (
- {renderCard(card, selectedColumn === columnIndex && cardIndex >= column.length - selectedCards.length)} + {renderCard(card, selectedColumn === columnIndex && selectedCards.includes(card))}
))}
@@ -253,6 +269,16 @@ export function KlondikeSolitaireComponent() { )} + {false && ( +
+

Selected cards

+ {selectedCards.map((selectedCard, selectedCardIndex) => ( +
+ {renderCard(selectedCard, false)} +
+ ))} +
+ )}

Controls: