diff options
Diffstat (limited to 'html/cards/script.js')
-rw-r--r-- | html/cards/script.js | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/html/cards/script.js b/html/cards/script.js new file mode 100644 index 0000000..64c145b --- /dev/null +++ b/html/cards/script.js @@ -0,0 +1,183 @@ +// Constants +const CARD_WIDTH = 100; +const CARD_HEIGHT = 150; +const PADDING = 10; +const SUITS = ['❤️', '♦️', '♣️', '♠️']; +const VALUES = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']; +const CARD_BACK_COLOR = '#0066cc'; +const PATTERN_SIZE = 10; + +// Canvas setup +const canvas = document.getElementById('cards'); +const ctx = canvas.getContext('2d'); +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 createDeck = () => + SUITS.flatMap(suit => VALUES.map(value => ({ suit, value }))); + +const createCard = (x, y, cardData) => ({ + x: x + 20, + y: y + 20, + card: cardData, + isFaceUp: false // Cards start face down +}); + +// Function to check if a point is within a card +const isPointInCard = (x, y, card) => + x >= card.x && + x <= card.x + CARD_WIDTH && + y >= card.y && + y <= card.y + CARD_HEIGHT; + +// Rendering functions +const clearCanvas = () => { + ctx.fillStyle = 'beige'; + ctx.fillRect(0, 0, canvas.width, canvas.height); +}; + +const renderCardBack = card => { + // Draw blue background + ctx.fillStyle = CARD_BACK_COLOR; + ctx.fillRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT); + + // Draw checkered pattern + ctx.strokeStyle = '#003366'; + for (let i = 0; i < CARD_WIDTH; i += PATTERN_SIZE) { + for (let j = 0; j < CARD_HEIGHT; j += PATTERN_SIZE) { + if ((i + j) % (PATTERN_SIZE * 2) === 0) { + ctx.fillStyle = '#0055aa'; + ctx.fillRect(card.x + i, card.y + j, PATTERN_SIZE, PATTERN_SIZE); + } + } + } + + // Draw border + ctx.strokeStyle = 'black'; + ctx.strokeRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT); +}; + +const renderCardFront = card => { + ctx.fillStyle = 'white'; + ctx.fillRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT); + ctx.fillStyle = 'black'; + ctx.font = '20px Arial'; + ctx.strokeRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT); + ctx.fillText(card.card.value, card.x + 10, card.y + 30); + ctx.fillText(card.card.suit, card.x + 10, card.y + 60); +}; + +const renderCard = card => { + if (card.isFaceUp) { + renderCardFront(card); + } else { + renderCardBack(card); + } +}; + +const renderAllCards = cards => { + clearCanvas(); + cards.forEach(renderCard); +}; + +// State management +const gameState = { + cards: [], + draggingCard: null, + deck: shuffle(createDeck()), + stackPosition: { + x: 0, + y: 0 + } +}; + +// Event handlers +const handleMouseMove = e => { + if (!gameState.draggingCard) return; + + const rect = canvas.getBoundingClientRect(); + gameState.draggingCard.x = e.clientX - rect.left; + gameState.draggingCard.y = e.clientY - rect.top; + + renderAllCards(gameState.cards); +}; + +const handleMouseUp = () => { + gameState.draggingCard = null; + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); +}; + +// Define handleMouseDown before using it +const handleMouseDown = e => { + const rect = canvas.getBoundingClientRect(); + const x = e.clientX - rect.left; + const y = e.clientY - rect.top; + + // Handle right click for card flipping + if (e.button === 2) { // Right click + e.preventDefault(); + const clickedCard = gameState.cards.find(card => + isPointInCard(x, y, card) && + (card.x !== gameState.stackPosition.x || card.y !== gameState.stackPosition.y) + ); + if (clickedCard) { + clickedCard.isFaceUp = !clickedCard.isFaceUp; + renderAllCards(gameState.cards); + } + return; + } + + // Find the top-most clicked card + const clickedCard = gameState.cards.slice().reverse().find(card => isPointInCard(x, y, card)); + + if (clickedCard) { + // If it's a card in the stack, handle drawing it + if (clickedCard.x === gameState.stackPosition.x && + clickedCard.y === gameState.stackPosition.y) { + clickedCard.isFaceUp = true; + } + + // Allow dragging regardless of where the card is + gameState.draggingCard = clickedCard; + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + } +}; + +// Initialize game +const initializeGame = () => { + // Create a full deck of cards + gameState.deck = shuffle(createDeck()); + gameState.cards = gameState.deck.map(cardData => createCard(0, 0, cardData)); + + // Draw cards in a pile with their reverse side showing + gameState.cards.forEach((card, index) => { + card.x = 20; // Pile at 20 pixels from the left + card.y = 20 + index * 5; // Stack cards with a slight offset for visibility + }); + + clearCanvas(); + renderAllCards(gameState.cards); + + // Add event listeners + canvas.addEventListener('mousedown', handleMouseDown); + canvas.addEventListener('contextmenu', e => e.preventDefault()); +}; + +// Start the game +initializeGame(); + +// Clean up on window unload +window.addEventListener('unload', () => { + canvas.removeEventListener('mousedown', handleMouseDown); + canvas.removeEventListener('contextmenu', e => e.preventDefault()); +}); \ No newline at end of file |