cards27 / index.html
manyone's picture
finally there is no need to show me a panel where i have to press the card to memorize then indicate that i've memorized it. i can just memorize my card in my head at the first deal. - Initial Deployment
dbc283e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Card Trick Game</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
.card {
width: 80px;
height: 120px;
perspective: 1000px;
cursor: pointer;
transition: all 0.3s ease;
}
.card-inner {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: transform 0.6s;
}
.card .card-inner.flipped {
transform: rotateY(180deg);
}
.card-front, .card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.card-front {
background: white;
transform: rotateY(180deg);
font-weight: bold;
font-size: 1.2rem;
}
.card-back {
background: linear-gradient(135deg, #4f46e5, #8b5cf6);
color: white;
}
.highlight-card {
box-shadow: 0 0 15px 5px rgba(255, 215, 0, 0.7);
transform: scale(1.05);
}
.pile-button {
transition: all 0.3s ease;
}
.pile-button:hover {
transform: translateY(-3px);
}
.pile-button:active {
transform: translateY(1px);
}
@media (max-width: 768px) {
.card {
width: 60px;
height: 90px;
}
}
</style>
</head>
<body class="bg-gray-100 min-h-screen flex flex-col items-center py-8">
<div class="container mx-auto px-4">
<h1 class="text-4xl font-bold text-center text-indigo-800 mb-2">Magical Card Trick</h1>
<p class="text-center text-gray-600 mb-8">I'll read your mind through your favorite number!</p>
<div id="game-container" class="flex flex-col items-center">
<!-- Game phases will be rendered here -->
</div>
</div>
<script>
// Game state
const gameState = {
phase: 'number-input', // 'number-input', 'card-selection', 'pile-selection', 'result'
favoriteNumber: null,
deck: [],
currentRound: 0,
ternaryDigits: [],
selectedPiles: [],
memorizedCard: null,
memorizedCardPosition: null
};
// Card suits and values
const suits = ['♥', '♦', '♠', '♣'];
const values = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
// Initialize the game
function initGame() {
renderGame();
}
// Render the game based on current phase
function renderGame() {
const container = document.getElementById('game-container');
container.innerHTML = '';
switch (gameState.phase) {
case 'number-input':
renderNumberInput(container);
break;
case 'pile-selection':
renderPileSelection(container);
break;
case 'result':
renderResult(container);
break;
}
}
// Render number input phase
function renderNumberInput(container) {
const div = document.createElement('div');
div.className = 'bg-white p-8 rounded-lg shadow-lg max-w-md w-full';
div.innerHTML = `
<h2 class="text-2xl font-semibold text-indigo-700 mb-4">Enter Your Favorite Number</h2>
<p class="text-gray-600 mb-6">Choose a number between 1 and 27. This will help me find your card later!</p>
<div class="flex flex-col space-y-4">
<input
type="number"
id="favorite-number"
min="1"
max="27"
placeholder="1-27"
class="border-2 border-indigo-200 rounded-lg px-4 py-2 focus:outline-none focus:border-indigo-500 text-center text-xl"
>
<button
id="submit-number"
class="bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-6 rounded-lg transition duration-200"
>
Start the Magic!
</button>
</div>
`;
container.appendChild(div);
document.getElementById('submit-number').addEventListener('click', () => {
const numberInput = document.getElementById('favorite-number');
const number = parseInt(numberInput.value);
if (isNaN(number) || number < 1 || number > 27) {
alert('Please enter a number between 1 and 27');
return;
}
gameState.favoriteNumber = number;
gameState.phase = 'pile-selection';
gameState.currentRound = 0;
// Calculate ternary digits
const num = number - 1;
gameState.ternaryDigits = num.toString(3).padStart(3, '0').split('').reverse();
// Create and shuffle deck
gameState.deck = createDeck();
shuffleDeck(gameState.deck);
renderGame();
});
}
// Render pile selection phase
function renderPileSelection(container) {
const div = document.createElement('div');
div.className = 'bg-white p-6 rounded-lg shadow-lg w-full';
div.innerHTML = `
<h2 class="text-2xl font-semibold text-indigo-700 mb-4">Round ${gameState.currentRound + 1} of 3</h2>
<p class="text-gray-600 mb-6">Look at the cards below and memorize one in your mind. Then select the pile where your card is located:</p>
<div id="pile-grid" class="grid grid-cols-3 gap-4 mb-8"></div>
<div class="flex justify-center space-x-4">
<button
id="pile-0"
class="pile-button bg-red-500 hover:bg-red-600 text-white font-bold py-3 px-6 rounded-lg transition duration-200"
>
Pile 1
</button>
<button
id="pile-1"
class="pile-button bg-blue-500 hover:bg-blue-600 text-white font-bold py-3 px-6 rounded-lg transition duration-200"
>
Pile 2
</button>
<button
id="pile-2"
class="pile-button bg-green-500 hover:bg-green-600 text-white font-bold py-3 px-6 rounded-lg transition duration-200"
>
Pile 3
</button>
</div>
`;
container.appendChild(div);
// Display the current piles
const pileGrid = document.getElementById('pile-grid');
const piles = splitIntoPiles(gameState.deck);
for (let row = 0; row < 9; row++) {
for (let col = 0; col < 3; col++) {
const card = piles[col][row];
const cardElement = createCardElement(card, row * 3 + col, true);
pileGrid.appendChild(cardElement);
}
}
// Add event listeners to pile buttons
document.getElementById('pile-0').addEventListener('click', () => handlePileSelection(0));
document.getElementById('pile-1').addEventListener('click', () => handlePileSelection(1));
document.getElementById('pile-2').addEventListener('click', () => handlePileSelection(2));
}
// Render result phase
function renderResult(container) {
const position = gameState.memorizedCardPosition + 1; // Convert to 1-based index
const div = document.createElement('div');
div.className = 'bg-white p-8 rounded-lg shadow-lg max-w-3xl w-full';
div.innerHTML = `
<h2 class="text-3xl font-bold text-indigo-700 mb-4 text-center">✨ The Magic Revealed! ✨</h2>
<div class="mb-8 text-center">
<p class="text-xl text-gray-700 mb-2">Your favorite number was <span class="font-bold text-indigo-600">${gameState.favoriteNumber}</span></p>
<p class="text-xl text-gray-700">Your card is at position <span class="font-bold text-indigo-600">${position}</span> in the deck!</p>
</div>
<div id="result-deck" class="grid grid-cols-9 gap-1 mb-8">
<!-- Cards will be inserted here face up -->
</div>
<div class="text-center">
<p class="text-gray-600 mb-6">See? I knew your card would be at position ${position} all along!</p>
<button
id="play-again"
class="bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-8 rounded-lg transition duration-200"
>
Play Again
</button>
</div>
`;
container.appendChild(div);
// Display the final deck with highlighted card
const resultDeck = document.getElementById('result-deck');
gameState.deck.forEach((card, index) => {
const cardElement = document.createElement('div');
cardElement.className = `flex flex-col items-center p-2 rounded ${index === gameState.memorizedCardPosition ? 'bg-yellow-100 highlight-card' : 'bg-gray-50'}`;
cardElement.innerHTML = `
<div class="text-xs font-semibold text-gray-500 mb-1">${index + 1}</div>
<div class="card">
<div class="card-inner flipped">
<div class="card-front">${card.value}${card.suit}</div>
<div class="card-back"></div>
</div>
</div>
`;
resultDeck.appendChild(cardElement);
});
document.getElementById('play-again').addEventListener('click', resetGame);
}
// Create a card element
function createCardElement(card, index, clickable = true) {
const cardElement = document.createElement('div');
cardElement.className = 'card';
cardElement.dataset.index = index;
// Always show card face (especially during memorization)
const showFace = true;
cardElement.innerHTML = `
<div class="card-inner ${showFace ? 'flipped' : ''}">
<div class="card-front">${card.value}${card.suit}</div>
<div class="card-back"></div>
</div>
`;
if (clickable) {
cardElement.addEventListener('click', () => {
// Remove highlight from all cards
document.querySelectorAll('.card').forEach(c => {
c.classList.remove('highlight-card');
});
// Highlight selected card
cardElement.classList.add('highlight-card');
// Store memorized card
gameState.memorizedCard = card;
gameState.memorizedCardPosition = index;
});
}
return cardElement;
}
// Handle pile selection
function handlePileSelection(pileIndex) {
gameState.selectedPiles[gameState.currentRound] = pileIndex;
// Gather the piles based on the ternary digit
const ternaryDigit = parseInt(gameState.ternaryDigits[gameState.currentRound]);
const piles = splitIntoPiles(gameState.deck);
let gatheredPiles = [];
switch (ternaryDigit) {
case 0:
// Chosen pile first
gatheredPiles = [...piles[pileIndex], ...piles[(pileIndex + 1) % 3], ...piles[(pileIndex + 2) % 3]];
break;
case 1:
// Chosen pile in middle
gatheredPiles = [...piles[(pileIndex + 1) % 3], ...piles[pileIndex], ...piles[(pileIndex + 2) % 3]];
break;
case 2:
// Chosen pile last
gatheredPiles = [...piles[(pileIndex + 1) % 3], ...piles[(pileIndex + 2) % 3], ...piles[pileIndex]];
break;
}
gameState.deck = gatheredPiles;
gameState.currentRound++;
if (gameState.currentRound < 3) {
renderGame();
} else {
// Calculate final position
const ternaryStr = (gameState.favoriteNumber - 1).toString(3).padStart(3, '0');
const digits = ternaryStr.split('').reverse().map(Number);
// Calculate position: 9*d0 + 3*d1 + 1*d2 (convert to 0-based)
gameState.memorizedCardPosition =
9 * digits[2] + 3 * digits[1] + digits[0];
gameState.phase = 'result';
renderGame();
}
}
// Create a deck of cards
function createDeck() {
const deck = [];
for (const suit of suits) {
for (const value of values) {
deck.push({ suit, value });
}
}
return deck;
}
// Shuffle the deck
function shuffleDeck(deck) {
for (let i = deck.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[deck[i], deck[j]] = [deck[j], deck[i]];
}
}
// Split deck into 3 piles (9 cards each)
function splitIntoPiles(deck) {
const piles = [[], [], []];
for (let i = 0; i < 27; i++) {
const pileIndex = i % 3;
piles[pileIndex].push(deck[i]);
}
return piles;
}
// Reset the game
function resetGame() {
gameState.phase = 'number-input';
gameState.favoriteNumber = null;
gameState.deck = [];
gameState.currentRound = 0;
gameState.ternaryDigits = [];
gameState.selectedPiles = [];
gameState.memorizedCard = null;
gameState.memorizedCardPosition = null;
renderGame();
}
// Initialize the game when page loads
window.onload = initGame;
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=manyone/manyone-cards27" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>