/// import { Cell, computed, Default, handler, lift, NAME, pattern, UI, } from "commontools"; // Card suits and ranks const SUITS = ["hearts", "diamonds", "clubs", "spades"] as const; const RANKS = [ "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", ] as const; type Suit = (typeof SUITS)[number]; type Rank = (typeof RANKS)[number]; // Card interface interface Card { suit: Suit; rank: Rank; } // Generate unique random cards for defaults const defaultPile1: Card[] = [ { suit: "hearts", rank: "A" }, { suit: "spades", rank: "K" }, { suit: "diamonds", rank: "7" }, ]; const defaultPile2: Card[] = [ { suit: "clubs", rank: "Q" }, { suit: "hearts", rank: "10" }, { suit: "spades", rank: "3" }, ]; interface CardPilesInput { pile1: Default; pile2: Default; } interface CardPilesOutput { pile1: Card[]; pile2: Card[]; } // Get suit symbol const getSuitSymbol = lift((suit: Suit): string => { switch (suit) { case "hearts": return "♥"; case "diamonds": return "♦"; case "clubs": return "♣"; case "spades": return "♠"; } }); // Get suit color const getSuitColor = lift((suit: Suit): string => { return suit === "hearts" || suit === "diamonds" ? "#dc2626" : "#1e293b"; }); // Handler to move a card to pile 1 const moveToPile1 = handler< { detail: { sourceCell: Cell } }, { pile1: Cell; pile2: Cell } >((event, { pile1, pile2 }) => { const sourceCard = event.detail?.sourceCell?.get() as Card; if (!sourceCard) return; // Remove from pile2 if present const p2 = pile2.get(); const idx2 = p2.findIndex( (c) => c.rank === sourceCard.rank && c.suit === sourceCard.suit, ); if (idx2 >= 0) { pile2.set(p2.filter((_, i) => i !== idx2)); pile1.push(sourceCard); } }); // Handler to move a card to pile 2 const moveToPile2 = handler< { detail: { sourceCell: Cell } }, { pile1: Cell; pile2: Cell } >((event, { pile1, pile2 }) => { const sourceCard = event.detail?.sourceCell?.get() as Card; if (!sourceCard) return; // Remove from pile1 if present const p1 = pile1.get(); const idx1 = p1.findIndex( (c) => c.rank === sourceCard.rank && c.suit === sourceCard.suit, ); if (idx1 >= 0) { pile1.set(p1.filter((_, i) => i !== idx1)); pile2.push(sourceCard); } }); export default pattern(({ pile1, pile2 }) => { // Create computed versions to ensure reactivity const cards1 = computed(() => pile1); const cards2 = computed(() => pile2); return { [NAME]: "Card Piles", [UI]: ( PILE 1 {cards1.map((card) => ( {card.rank} {getSuitSymbol(card.suit)} {getSuitSymbol(card.suit)} {card.rank} {getSuitSymbol(card.suit)} ))} PILE 2 {cards2.map((card) => ( {card.rank} {getSuitSymbol(card.suit)} {getSuitSymbol(card.suit)} {card.rank} {getSuitSymbol(card.suit)} ))} ), pile1, pile2, }; });