diff options
author | elioat <elioat@tilde.institute> | 2025-01-11 12:24:36 -0500 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2025-01-11 12:24:36 -0500 |
commit | 49338d20b0e95e05cf3502b5394996b97e44ae03 (patch) | |
tree | 07237b172141ac9c95142fd6179069d35857e853 /html | |
parent | 95067512ffb2ee129581146cc433ddd9c79c3b49 (diff) | |
download | tour-49338d20b0e95e05cf3502b5394996b97e44ae03.tar.gz |
*
Diffstat (limited to 'html')
-rw-r--r-- | html/cards/script.js | 133 |
1 files changed, 93 insertions, 40 deletions
diff --git a/html/cards/script.js b/html/cards/script.js index 8df9453..049f91f 100644 --- a/html/cards/script.js +++ b/html/cards/script.js @@ -1,3 +1,25 @@ +/** + * @typedef {Object} Card + * @property {number} x + * @property {number} y + * @property {CardData} card + * @property {boolean} isFaceUp + */ + +/** + * @typedef {Object} CardData + * @property {string} suit + * @property {string} value + */ + +/** + * @typedef {Object} GameState + * @property {Card[]} cards + * @property {Card|null} draggingCard + * @property {CardData[]} deck + * @property {{x: number, y: number}} stackPosition + */ + // Constants const CARD_WIDTH = 100; const CARD_HEIGHT = 150; @@ -18,19 +40,23 @@ canvas.width = window.innerWidth; canvas.height = window.innerHeight; // Pure functions -const shuffle = array => [...array].reduce((acc, _, i) => { - const j = Math.floor(Math.random() * (i + 1)); - [acc[i], acc[j]] = [acc[j], acc[i]]; - return acc; -}, [...array]); +const shuffle = array => { + const result = [...array]; + for (let i = result.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [result[i], result[j]] = [result[j], result[i]]; + } + return result; +}; const createDeck = () => SUITS.flatMap(suit => VALUES.map(value => ({ suit, value }))); -const createCard = (x, y, cardData) => ({ +// Create a more functional card factory +const createCard = (x, y, cardData) => Object.freeze({ x: x + PADDING, y: y + PADDING, - card: cardData, - isFaceUp: false // Cards start face down + card: Object.freeze({ ...cardData }), + isFaceUp: false }); // Function to check if a point is within a card @@ -105,25 +131,27 @@ const initializeGameState = () => ({ }); const initializeGame = () => { - gameState = initializeGameState(); - gameState.cards = gameState.deck.map(cardData => createCard(INITIAL_CARD_X, INITIAL_CARD_Y, cardData)); - - gameState.cards.forEach((card, index) => { - card.y += index * 5; // Stack cards with a slight offset for visibility - }); + try { + gameState = initializeGameState(); + gameState.cards = gameState.deck.map((cardData, index) => + createCard(INITIAL_CARD_X, INITIAL_CARD_Y + index * 5, cardData) + ); + + clearCanvas(); + renderAllCards(gameState.cards); + + setupEventListeners(); + } catch (error) { + console.error('Failed to initialize game:', error); + alert('Failed to initialize game. Please refresh the page.'); + } +}; - clearCanvas(); - renderAllCards(gameState.cards); - - // Add event listeners +const setupEventListeners = () => { canvas.addEventListener('mousedown', handleMouseDown); canvas.addEventListener('contextmenu', e => e.preventDefault()); - - // Add event listener for the 'r' key document.addEventListener('keydown', e => { - if (e.key === 'q') { - handleResetGame(); - } + if (e.key === 'q') handleResetGame(); }); }; @@ -132,9 +160,15 @@ const handleMouseMove = e => { if (!gameState.draggingCard) return; const rect = canvas.getBoundingClientRect(); - // Update the card's position using the offset - gameState.draggingCard.x = e.clientX - rect.left - dragOffset.x; - gameState.draggingCard.y = e.clientY - rect.top - dragOffset.y; + const newX = e.clientX - rect.left - dragOffset.x; + const newY = e.clientY - rect.top - dragOffset.y; + + // Update the card's position immutably + const updatedCard = moveCard(gameState.draggingCard, newX, newY); + gameState.cards = gameState.cards.map(card => + card === gameState.draggingCard ? updatedCard : card + ); + gameState.draggingCard = updatedCard; renderAllCards(gameState.cards); }; @@ -162,33 +196,41 @@ const handleMouseUp = e => { let dragOffset = { x: 0, y: 0 }; // To store the offset of the click position +const findClickedCard = (x, y, cards) => + cards.slice().reverse().find(card => isPointInCard(x, y, card)); + +const moveCardToTop = (targetCard, cards) => [ + ...cards.filter(card => card !== targetCard), + targetCard +]; + const handleMouseDown = e => { const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; - if (e.button === 2) { // Right click + if (e.button === 2) { e.preventDefault(); - const clickedCard = gameState.cards.find(card => isPointInCard(x, y, card)); + const clickedCard = findClickedCard(x, y, gameState.cards); if (clickedCard) { - clickedCard.isFaceUp = !clickedCard.isFaceUp; // Toggle card face - renderAllCards(gameState.cards); // Re-render all cards + const updatedCard = toggleCardFace(clickedCard); + gameState.cards = gameState.cards.map(card => + card === clickedCard ? updatedCard : card + ); + renderAllCards(gameState.cards); } return; } - const clickedCard = gameState.cards.slice().reverse().find(card => isPointInCard(x, y, card)); + const clickedCard = findClickedCard(x, y, gameState.cards); if (clickedCard) { gameState.draggingCard = clickedCard; - - // Calculate the offset between the mouse position and the card's position - dragOffset.x = x - clickedCard.x; - dragOffset.y = y - clickedCard.y; - - // Move the dragged card to the top of the stack - gameState.cards = gameState.cards.filter(card => card !== clickedCard); - gameState.cards.push(clickedCard); - + dragOffset = { + x: x - clickedCard.x, + y: y - clickedCard.y + }; + gameState.cards = moveCardToTop(clickedCard, gameState.cards); + document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); } @@ -201,6 +243,17 @@ const handleResetGame = () => { } }; +const moveCard = (card, newX, newY) => ({ + ...card, + x: newX, + y: newY +}); + +const toggleCardFace = card => ({ + ...card, + isFaceUp: !card.isFaceUp +}); + // Start the game initializeGame(); |