about summary refs log tree commit diff stats
path: root/html
diff options
context:
space:
mode:
authorelioat <elioat@tilde.institute>2025-01-10 20:31:26 -0500
committerelioat <elioat@tilde.institute>2025-01-10 20:31:26 -0500
commit23a9b6fe9bd7fa07a92f42eb43ef91799de2986c (patch)
treede76bbdf54f9658ce57aa69ba2a0b451590b3691 /html
parentbf01d51d4b849ce716eae0303a669841d4b914f3 (diff)
downloadtour-23a9b6fe9bd7fa07a92f42eb43ef91799de2986c.tar.gz
*
Diffstat (limited to 'html')
-rw-r--r--html/cards/index.html228
-rw-r--r--html/cards/script.js183
2 files changed, 184 insertions, 227 deletions
diff --git a/html/cards/index.html b/html/cards/index.html
index 537920b..4e38953 100644
--- a/html/cards/index.html
+++ b/html/cards/index.html
@@ -17,232 +17,6 @@
 </head>
 <body>
     <canvas id="cards"></canvas>
-    <script>
-        // 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
-        });
-
-        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
-            }
-        };
-
-        // Add function to get top card
-        const getTopStackCard = () => {
-            return gameState.cards.find(card => 
-                card.x === gameState.stackPosition.x && 
-                card.y === gameState.stackPosition.y
-            );
-        };
-
-        // 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);
-        };
-
-        // Add this function to distribute cards evenly with overlap
-        const distributeCards = () => {
-            const totalCards = gameState.cards.length;
-            const cols = Math.floor((canvas.width - 20) / (CARD_WIDTH / 2)); // Allow overlap by halving the width and accounting for border
-            const rows = Math.ceil(totalCards / cols); // Calculate number of rows
-
-            const cardWidthWithPadding = CARD_WIDTH / 2; // Allow overlap
-            const cardHeightWithPadding = CARD_HEIGHT / 2; // Allow overlap
-
-            // Calculate starting positions
-            const startX = 20 + (canvas.width - (cols * cardWidthWithPadding)) / 2; // Start from 20 pixels from the left
-            const startY = 20 + (canvas.height - (rows * cardHeightWithPadding)) / 2; // Start from 20 pixels from the top
-
-            // Distribute cards
-            gameState.cards.forEach((card, index) => {
-                const row = Math.floor(index / cols);
-                const col = index % cols;
-                card.x = startX + col * cardWidthWithPadding + (Math.random() * 20 - 10); // Random offset for overlap
-                card.y = startY + row * cardHeightWithPadding + (Math.random() * 20 - 10); // Random offset for overlap
-                card.isFaceUp = true; // Flip cards face up when distributed
-            });
-
-            renderAllCards(gameState.cards);
-        };
-
-        // Update handleMouseDown to include double-click detection
-        let lastClickTime = 0;
-        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;
-            }
-
-            // Check for double-click
-            const currentTime = new Date().getTime();
-            if (currentTime - lastClickTime < 300) { // 300 ms for double-click
-                distributeCards(); // Show all cards when double-clicked
-                lastClickTime = 0; // Reset last click time
-                return;
-            }
-            lastClickTime = currentTime;
-
-            // Find any clicked card
-            const clickedCard = gameState.cards.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()); // Ensure we have a full deck
-            gameState.cards = gameState.deck.map(cardData => createCard(0, 0, cardData)); // Create cards with initial position (0, 0)
-
-            // 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());
-        });
-    </script>
+    <script src="script.js"></script>
 </body>
 </html>
\ No newline at end of file
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