game-hub / index.html
CroissantWhyNot's picture
Add 3 files
1b99887 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Game Hub</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Custom styles */
.game-card {
transition: all 0.3s ease;
transform-style: preserve-3d;
}
.game-card:hover {
transform: translateY(-5px) scale(1.02);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
/* Pong game styles */
#pongCanvas {
background-color: #111;
border-radius: 8px;
}
/* Blackjack table */
.blackjack-table {
background: linear-gradient(135deg, #1a5f1a, #0d3b0d);
border-radius: 16px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
}
.card {
width: 80px;
height: 120px;
background: white;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
margin: 0 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
font-size: 24px;
font-weight: bold;
position: relative;
user-select: none;
}
.card.red {
color: red;
}
.card.black {
color: black;
}
.card-back {
background: linear-gradient(135deg, #d10000, #8b0000);
color: white;
display: flex;
justify-content: center;
align-items: center;
}
/* Memory game */
.memory-card {
width: 80px;
height: 120px;
perspective: 1000px;
margin: 5px;
}
.memory-card-inner {
position: relative;
width: 100%;
height: 100%;
transition: transform 0.6s;
transform-style: preserve-3d;
}
.memory-card.flipped .memory-card-inner {
transform: rotateY(180deg);
}
.memory-card-front, .memory-card-back {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
font-size: 36px;
font-weight: bold;
}
.memory-card-front {
background: linear-gradient(135deg, #d10000, #8b0000);
color: white;
}
.memory-card-back {
background: white;
transform: rotateY(180deg);
color: #333;
}
/* Hide all game screens initially */
.game-screen {
display: none;
}
/* Solitaire styles */
.solitaire-card {
width: 80px;
height: 120px;
background: white;
border-radius: 8px;
position: absolute;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
font-size: 24px;
font-weight: bold;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 5px;
user-select: none;
cursor: pointer;
transition: transform 0.2s;
}
.solitaire-card.red {
color: red;
}
.solitaire-card.black {
color: black;
}
.solitaire-card.dragging {
z-index: 1000;
transform: scale(1.05);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.solitaire-card .card-value {
font-size: 20px;
align-self: flex-start;
}
.solitaire-card .card-suit {
font-size: 16px;
align-self: flex-end;
}
.solitaire-pile {
position: relative;
min-width: 80px;
min-height: 120px;
margin-bottom: 20px;
}
.solitaire-foundation {
width: 80px;
height: 120px;
border: 2px dashed #444;
border-radius: 8px;
margin-bottom: 20px;
}
.solitaire-stock {
width: 80px;
height: 120px;
background: linear-gradient(135deg, #d10000, #8b0000);
border-radius: 8px;
display: flex;
justify-content: center;
align-items: center;
color: white;
cursor: pointer;
margin-bottom: 20px;
}
.solitaire-waste {
width: 80px;
height: 120px;
position: relative;
margin-bottom: 20px;
}
.solitaire-tableau {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 20px;
margin-top: 20px;
}
.solitaire-top-area {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
}
.solitaire-foundations {
display: flex;
gap: 20px;
}
.drop-target {
border: 2px dashed transparent;
}
.drop-target.highlight {
border-color: gold;
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen">
<!-- Main Menu -->
<div id="mainMenu" class="container mx-auto px-4 py-8">
<header class="flex justify-between items-center mb-12">
<h1 class="text-4xl font-bold bg-gradient-to-r from-purple-500 to-blue-500 bg-clip-text text-transparent">Game Hub</h1>
<div class="flex space-x-4">
<button id="soundToggle" class="p-2 rounded-full bg-gray-800 hover:bg-gray-700 transition">
<i class="fas fa-volume-up"></i>
</button>
</div>
</header>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<!-- Pong Card -->
<div class="game-card bg-gray-800 rounded-xl p-6 cursor-pointer" onclick="loadGame('pong')">
<div class="flex justify-between items-start mb-4">
<h2 class="text-2xl font-bold text-purple-400">Pong</h2>
<div class="bg-purple-500 text-white px-3 py-1 rounded-full text-xs font-bold">ARCADE</div>
</div>
<p class="text-gray-300 mb-4">The classic arcade game. Control your paddle and defeat your opponent!</p>
<div class="bg-gray-700 rounded-lg h-32 flex items-center justify-center">
<i class="fas fa-table-tennis text-4xl text-purple-400"></i>
</div>
</div>
<!-- Blackjack Card -->
<div class="game-card bg-gray-800 rounded-xl p-6 cursor-pointer" onclick="loadGame('blackjack')">
<div class="flex justify-between items-start mb-4">
<h2 class="text-2xl font-bold text-blue-400">Blackjack</h2>
<div class="bg-blue-500 text-white px-3 py-1 rounded-full text-xs font-bold">CARD</div>
</div>
<p class="text-gray-300 mb-4">Try to beat the dealer without going over 21. Double down and split pairs!</p>
<div class="bg-gray-700 rounded-lg h-32 flex items-center justify-center">
<i class="fas fa-club text-4xl text-blue-400"></i>
<i class="fas fa-heart text-4xl text-red-500 ml-2"></i>
</div>
</div>
<!-- Memory Match Card -->
<div class="game-card bg-gray-800 rounded-xl p-6 cursor-pointer" onclick="loadGame('memory')">
<div class="flex justify-between items-start mb-4">
<h2 class="text-2xl font-bold text-green-400">Memory Match</h2>
<div class="bg-green-500 text-white px-3 py-1 rounded-full text-xs font-bold">PUZZLE</div>
</div>
<p class="text-gray-300 mb-4">Test your memory by matching pairs of cards. Find all matches to win!</p>
<div class="bg-gray-700 rounded-lg h-32 flex items-center justify-center">
<i class="fas fa-brain text-4xl text-green-400"></i>
</div>
</div>
<!-- War Card -->
<div class="game-card bg-gray-800 rounded-xl p-6 cursor-pointer" onclick="loadGame('war')">
<div class="flex justify-between items-start mb-4">
<h2 class="text-2xl font-bold text-yellow-400">War</h2>
<div class="bg-yellow-500 text-white px-3 py-1 rounded-full text-xs font-bold">CARD</div>
</div>
<p class="text-gray-300 mb-4">The classic card game of War. Highest card wins each round!</p>
<div class="bg-gray-700 rounded-lg h-32 flex items-center justify-center">
<i class="fas fa-flag text-4xl text-yellow-400"></i>
</div>
</div>
<!-- Solitaire Card -->
<div class="game-card bg-gray-800 rounded-xl p-6 cursor-pointer" onclick="loadGame('solitaire')">
<div class="flex justify-between items-start mb-4">
<h2 class="text-2xl font-bold text-red-400">Solitaire</h2>
<div class="bg-red-500 text-white px-3 py-1 rounded-full text-xs font-bold">CLASSIC</div>
</div>
<p class="text-gray-300 mb-4">The timeless single-player card game. Sort all cards by suit in ascending order.</p>
<div class="bg-gray-700 rounded-lg h-32 flex items-center justify-center">
<i class="fas fa-crown text-4xl text-red-400"></i>
</div>
</div>
<!-- Coming Soon Card -->
<div class="game-card bg-gray-800 rounded-xl p-6">
<div class="flex justify-between items-start mb-4">
<h2 class="text-2xl font-bold text-pink-400">More Games</h2>
<div class="bg-pink-500 text-white px-3 py-1 rounded-full text-xs font-bold">COMING SOON</div>
</div>
<p class="text-gray-300 mb-4">We're working on adding more exciting games to our collection!</p>
<div class="bg-gray-700 rounded-lg h-32 flex items-center justify-center">
<i class="fas fa-gamepad text-4xl text-pink-400"></i>
</div>
</div>
</div>
</div>
<!-- Pong Game Screen -->
<div id="pongScreen" class="game-screen container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<button onclick="returnToMenu()" class="flex items-center text-white hover:text-purple-400 transition">
<i class="fas fa-arrow-left mr-2"></i> Back to Menu
</button>
<h2 class="text-2xl font-bold text-purple-400">Pong</h2>
<div class="text-xl font-mono">
Player: <span id="pongPlayerScore">0</span> - <span id="pongComputerScore">0</span> :Computer
</div>
</div>
<div class="flex justify-center">
<canvas id="pongCanvas" width="800" height="500" class="border-2 border-purple-500"></canvas>
</div>
<div class="mt-6 text-center">
<p class="text-gray-400 mb-4">Use <span class="font-bold">W/S</span> keys to move your paddle up and down</p>
<button id="pongPauseBtn" class="bg-purple-600 hover:bg-purple-700 text-white px-6 py-2 rounded-full font-bold mr-4">
<i class="fas fa-pause mr-2"></i>Pause
</button>
<button id="pongResetBtn" class="bg-gray-700 hover:bg-gray-600 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-redo mr-2"></i>Reset
</button>
</div>
</div>
<!-- Blackjack Game Screen -->
<div id="blackjackScreen" class="game-screen container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<button onclick="returnToMenu()" class="flex items-center text-white hover:text-blue-400 transition">
<i class="fas fa-arrow-left mr-2"></i> Back to Menu
</button>
<h2 class="text-2xl font-bold text-blue-400">Blackjack</h2>
<div class="text-xl font-mono">
Chips: $<span id="blackjackChips">1000</span>
</div>
</div>
<div class="blackjack-table p-8 mb-8">
<div class="text-center mb-8">
<h3 class="text-xl font-bold text-white mb-2">Dealer</h3>
<div id="dealerHand" class="flex justify-center mb-4">
<!-- Dealer cards will be added here -->
</div>
<div id="dealerTotal" class="text-white font-bold">Total: ?</div>
</div>
<div class="text-center">
<h3 class="text-xl font-bold text-white mb-2">Player</h3>
<div id="playerHand" class="flex justify-center mb-4">
<!-- Player cards will be added here -->
</div>
<div id="playerTotal" class="text-white font-bold">Total: 0</div>
</div>
</div>
<div id="blackjackBetControls" class="bg-gray-800 p-6 rounded-xl mb-6">
<h3 class="text-lg font-bold mb-4">Place Your Bet</h3>
<div class="flex items-center mb-4">
<span class="mr-4">Bet Amount:</span>
<input type="range" id="betSlider" min="10" max="500" step="10" value="50" class="flex-1 mr-4">
<span id="betAmount" class="font-bold">$50</span>
</div>
<button id="dealBtn" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-play mr-2"></i>Deal
</button>
</div>
<div id="blackjackGameControls" class="bg-gray-800 p-6 rounded-xl hidden">
<div class="flex justify-center space-x-4">
<button id="hitBtn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-plus mr-2"></i>Hit
</button>
<button id="standBtn" class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-hand-paper mr-2"></i>Stand
</button>
<button id="doubleBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-times mr-2"></i>Double
</button>
</div>
</div>
<div id="blackjackMessage" class="text-center text-xl font-bold mt-6 hidden"></div>
</div>
<!-- Memory Match Game Screen -->
<div id="memoryScreen" class="game-screen container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<button onclick="returnToMenu()" class="flex items-center text-white hover:text-green-400 transition">
<i class="fas fa-arrow-left mr-2"></i> Back to Menu
</button>
<h2 class="text-2xl font-bold text-green-400">Memory Match</h2>
<div class="text-xl font-mono">
Moves: <span id="memoryMoves">0</span> | Pairs: <span id="memoryPairs">0</span>/8
</div>
</div>
<div class="flex flex-col items-center">
<div id="memoryBoard" class="grid grid-cols-4 gap-4 mb-6">
<!-- Memory cards will be added here -->
</div>
<button id="memoryResetBtn" class="bg-green-600 hover:bg-green-700 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-redo mr-2"></i>New Game
</button>
</div>
</div>
<!-- War Game Screen -->
<div id="warScreen" class="game-screen container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<button onclick="returnToMenu()" class="flex items-center text-white hover:text-yellow-400 transition">
<i class="fas fa-arrow-left mr-2"></i> Back to Menu
</button>
<h2 class="text-2xl font-bold text-yellow-400">War</h2>
<div class="text-xl font-mono">
Rounds: <span id="warRounds">0</span>
</div>
</div>
<div class="flex flex-col items-center">
<div class="flex justify-center space-x-16 mb-8">
<div class="text-center">
<h3 class="text-xl font-bold mb-4">Player</h3>
<div id="playerWarCard" class="card flex items-center justify-center text-4xl">
<!-- Player's war card will be shown here -->
</div>
<div class="mt-4">Cards: <span id="playerWarCount">26</span></div>
</div>
<div class="text-center">
<h3 class="text-xl font-bold mb-4">Computer</h3>
<div id="computerWarCard" class="card flex items-center justify-center text-4xl">
<!-- Computer's war card will be shown here -->
</div>
<div class="mt-4">Cards: <span id="computerWarCount">26</span></div>
</div>
</div>
<div id="warMessage" class="text-center text-xl font-bold mb-6"></div>
<div class="flex space-x-4">
<button id="warPlayBtn" class="bg-yellow-600 hover:bg-yellow-700 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-play mr-2"></i>Play Round
</button>
<button id="warResetBtn" class="bg-gray-700 hover:bg-gray-600 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-redo mr-2"></i>New Game
</button>
</div>
</div>
</div>
<!-- Solitaire Game Screen -->
<div id="solitaireScreen" class="game-screen container mx-auto px-4 py-8">
<div class="flex justify-between items-center mb-6">
<button onclick="returnToMenu()" class="flex items-center text-white hover:text-red-400 transition">
<i class="fas fa-arrow-left mr-2"></i> Back to Menu
</button>
<h2 class="text-2xl font-bold text-red-400">Solitaire</h2>
<div class="text-xl font-mono">
Time: <span id="solitaireTime">00:00</span>
</div>
</div>
<div class="bg-green-800 p-6 rounded-xl">
<div class="solitaire-top-area">
<div class="flex space-x-4">
<div id="stockPile" class="solitaire-stock">
<i class="fas fa-crown"></i>
</div>
<div id="wastePile" class="solitaire-waste"></div>
</div>
<div class="solitaire-foundations">
<div id="foundationHeart" class="solitaire-foundation drop-target" data-suit="hearts"></div>
<div id="foundationDiamond" class="solitaire-foundation drop-target" data-suit="diamonds"></div>
<div id="foundationClub" class="solitaire-foundation drop-target" data-suit="clubs"></div>
<div id="foundationSpade" class="solitaire-foundation drop-target" data-suit="spades"></div>
</div>
</div>
<div id="tableau" class="solitaire-tableau">
<div id="pile1" class="solitaire-pile drop-target" data-pile="1"></div>
<div id="pile2" class="solitaire-pile drop-target" data-pile="2"></div>
<div id="pile3" class="solitaire-pile drop-target" data-pile="3"></div>
<div id="pile4" class="solitaire-pile drop-target" data-pile="4"></div>
<div id="pile5" class="solitaire-pile drop-target" data-pile="5"></div>
<div id="pile6" class="solitaire-pile drop-target" data-pile="6"></div>
<div id="pile7" class="solitaire-pile drop-target" data-pile="7"></div>
</div>
</div>
<div class="mt-6 text-center">
<button id="solitaireResetBtn" class="bg-red-600 hover:bg-red-700 text-white px-6 py-2 rounded-full font-bold">
<i class="fas fa-redo mr-2"></i>New Game
</button>
</div>
</div>
<script>
// Game selector functionality
function loadGame(game) {
document.getElementById('mainMenu').style.display = 'none';
document.getElementById(game + 'Screen').style.display = 'block';
// Initialize the selected game
switch(game) {
case 'pong':
initPong();
break;
case 'blackjack':
initBlackjack();
break;
case 'memory':
initMemory();
break;
case 'war':
initWar();
break;
case 'solitaire':
initSolitaire();
break;
}
}
function returnToMenu() {
// Hide all game screens
document.querySelectorAll('.game-screen').forEach(screen => {
screen.style.display = 'none';
});
// Show main menu
document.getElementById('mainMenu').style.display = 'block';
}
// Sound toggle
document.getElementById('soundToggle').addEventListener('click', function() {
const icon = this.querySelector('i');
if (icon.classList.contains('fa-volume-up')) {
icon.classList.remove('fa-volume-up');
icon.classList.add('fa-volume-mute');
// Mute all game sounds
} else {
icon.classList.remove('fa-volume-mute');
icon.classList.add('fa-volume-up');
// Unmute all game sounds
}
});
// Pong Game
function initPong() {
const canvas = document.getElementById('pongCanvas');
const ctx = canvas.getContext('2d');
const playerScoreEl = document.getElementById('pongPlayerScore');
const computerScoreEl = document.getElementById('pongComputerScore');
const pauseBtn = document.getElementById('pongPauseBtn');
const resetBtn = document.getElementById('pongResetBtn');
// Game state
let gameRunning = true;
let playerScore = 0;
let computerScore = 0;
// Paddle and ball properties
const paddleWidth = 15;
const paddleHeight = 100;
const ballSize = 15;
let playerPaddle = {
x: 10,
y: canvas.height / 2 - paddleHeight / 2,
width: paddleWidth,
height: paddleHeight,
speed: 8
};
let computerPaddle = {
x: canvas.width - 10 - paddleWidth,
y: canvas.height / 2 - paddleHeight / 2,
width: paddleWidth,
height: paddleHeight,
speed: 5
};
let ball = {
x: canvas.width / 2,
y: canvas.height / 2,
size: ballSize,
speedX: 5,
speedY: 5
};
// Keyboard controls
let upPressed = false;
let downPressed = false;
document.addEventListener('keydown', (e) => {
if (e.key === 'w' || e.key === 'W') {
upPressed = true;
} else if (e.key === 's' || e.key === 'S') {
downPressed = true;
}
});
document.addEventListener('keyup', (e) => {
if (e.key === 'w' || e.key === 'W') {
upPressed = false;
} else if (e.key === 's' || e.key === 'S') {
downPressed = false;
}
});
// Pause/Resume game
pauseBtn.addEventListener('click', () => {
gameRunning = !gameRunning;
if (gameRunning) {
pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i>Pause';
gameLoop();
} else {
pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i>Resume';
}
});
// Reset game
resetBtn.addEventListener('click', resetPong);
function resetPong() {
playerScore = 0;
computerScore = 0;
playerScoreEl.textContent = '0';
computerScoreEl.textContent = '0';
playerPaddle.y = canvas.height / 2 - paddleHeight / 2;
computerPaddle.y = canvas.height / 2 - paddleHeight / 2;
ball.x = canvas.width / 2;
ball.y = canvas.height / 2;
ball.speedX = 5 * (Math.random() > 0.5 ? 1 : -1);
ball.speedY = 5 * (Math.random() > 0.5 ? 1 : -1);
if (!gameRunning) {
gameRunning = true;
pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i>Pause';
gameLoop();
}
}
// Game loop
function gameLoop() {
if (!gameRunning) return;
// Clear canvas
ctx.fillStyle = '#111';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw center line
ctx.strokeStyle = '#333';
ctx.setLineDash([10, 10]);
ctx.beginPath();
ctx.moveTo(canvas.width / 2, 0);
ctx.lineTo(canvas.width / 2, canvas.height);
ctx.stroke();
ctx.setLineDash([]);
// Draw paddles
ctx.fillStyle = '#fff';
ctx.fillRect(playerPaddle.x, playerPaddle.y, playerPaddle.width, playerPaddle.height);
ctx.fillRect(computerPaddle.x, computerPaddle.y, computerPaddle.width, computerPaddle.height);
// Draw ball
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.size, 0, Math.PI * 2);
ctx.fillStyle = '#fff';
ctx.fill();
// Move player paddle
if (upPressed && playerPaddle.y > 0) {
playerPaddle.y -= playerPaddle.speed;
}
if (downPressed && playerPaddle.y < canvas.height - playerPaddle.height) {
playerPaddle.y += playerPaddle.speed;
}
// Simple AI for computer paddle
if (computerPaddle.y + computerPaddle.height / 2 < ball.y - 10) {
computerPaddle.y += computerPaddle.speed;
} else if (computerPaddle.y + computerPaddle.height / 2 > ball.y + 10) {
computerPaddle.y -= computerPaddle.speed;
}
// Keep computer paddle in bounds
if (computerPaddle.y < 0) {
computerPaddle.y = 0;
} else if (computerPaddle.y > canvas.height - computerPaddle.height) {
computerPaddle.y = canvas.height - computerPaddle.height;
}
// Move ball
ball.x += ball.speedX;
ball.y += ball.speedY;
// Ball collision with top and bottom walls
if (ball.y - ball.size <= 0 || ball.y + ball.size >= canvas.height) {
ball.speedY = -ball.speedY;
}
// Ball collision with paddles
if (
ball.x - ball.size <= playerPaddle.x + playerPaddle.width &&
ball.y >= playerPaddle.y &&
ball.y <= playerPaddle.y + playerPaddle.height
) {
ball.speedX = -ball.speedX * 1.05; // Increase speed slightly
// Add some angle based on where ball hits paddle
const hitPos = (ball.y - (playerPaddle.y + playerPaddle.height / 2)) / (playerPaddle.height / 2);
ball.speedY = hitPos * 5;
}
if (
ball.x + ball.size >= computerPaddle.x &&
ball.y >= computerPaddle.y &&
ball.y <= computerPaddle.y + computerPaddle.height
) {
ball.speedX = -ball.speedX * 1.05; // Increase speed slightly
// Add some angle based on where ball hits paddle
const hitPos = (ball.y - (computerPaddle.y + computerPaddle.height / 2)) / (computerPaddle.height / 2);
ball.speedY = hitPos * 5;
}
// Ball out of bounds - score points
if (ball.x - ball.size <= 0) {
computerScore++;
computerScoreEl.textContent = computerScore;
resetBall();
}
if (ball.x + ball.size >= canvas.width) {
playerScore++;
playerScoreEl.textContent = playerScore;
resetBall();
}
requestAnimationFrame(gameLoop);
}
function resetBall() {
ball.x = canvas.width / 2;
ball.y = canvas.height / 2;
ball.speedX = 5 * (Math.random() > 0.5 ? 1 : -1);
ball.speedY = 5 * (Math.random() > 0.5 ? 1 : -1);
// Pause briefly before resuming
gameRunning = false;
pauseBtn.innerHTML = '<i class="fas fa-play mr-2"></i>Resume';
setTimeout(() => {
gameRunning = true;
pauseBtn.innerHTML = '<i class="fas fa-pause mr-2"></i>Pause';
gameLoop();
}, 1000);
}
// Start the game
gameLoop();
}
// Blackjack Game
function initBlackjack() {
const dealerHandEl = document.getElementById('dealerHand');
const playerHandEl = document.getElementById('playerHand');
const dealerTotalEl = document.getElementById('dealerTotal');
const playerTotalEl = document.getElementById('playerTotal');
const chipsEl = document.getElementById('blackjackChips');
const betSlider = document.getElementById('betSlider');
const betAmountEl = document.getElementById('betAmount');
const dealBtn = document.getElementById('dealBtn');
const hitBtn = document.getElementById('hitBtn');
const standBtn = document.getElementById('standBtn');
const doubleBtn = document.getElementById('doubleBtn');
const gameControls = document.getElementById('blackjackGameControls');
const betControls = document.getElementById('blackjackBetControls');
const messageEl = document.getElementById('blackjackMessage');
// Game state
let deck = [];
let dealerHand = [];
let playerHand = [];
let chips = 1000;
let currentBet = 50;
let gameInProgress = false;
let canDouble = true;
// Update bet amount display
betSlider.addEventListener('input', () => {
currentBet = parseInt(betSlider.value);
betAmountEl.textContent = currentBet;
});
// Deal button
dealBtn.addEventListener('click', deal);
// Game action buttons
hitBtn.addEventListener('click', hit);
standBtn.addEventListener('click', stand);
doubleBtn.addEventListener('click', doubleDown);
// Initialize game
function newDeck() {
const suits = ['hearts', 'diamonds', 'clubs', 'spades'];
const values = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
deck = [];
for (let suit of suits) {
for (let value of values) {
deck.push({ suit, value });
}
}
// Shuffle 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]];
}
}
function deal() {
if (gameInProgress) return;
if (currentBet > chips) {
messageEl.textContent = "You don't have enough chips!";
messageEl.classList.remove('hidden');
return;
}
// Reset game state
dealerHand = [];
playerHand = [];
gameInProgress = true;
canDouble = true;
messageEl.classList.add('hidden');
// Update UI
chips -= currentBet;
chipsEl.textContent = chips;
// Hide bet controls, show game controls
betControls.classList.add('hidden');
gameControls.classList.remove('hidden');
// Create new deck and deal cards
newDeck();
// Deal initial cards (player first, then dealer, then player, then dealer)
playerHand.push(deck.pop());
dealerHand.push(deck.pop());
playerHand.push(deck.pop());
dealerHand.push(deck.pop());
// Update display
updateDisplay();
// Check for blackjack
if (calculateHandValue(playerHand) === 21) {
// Player has blackjack
endGame(true);
}
}
function hit() {
if (!gameInProgress) return;
// Add card to player's hand
playerHand.push(deck.pop());
canDouble = false;
// Update display
updateDisplay();
// Check if player busted
if (calculateHandValue(playerHand) > 21) {
endGame(false);
}
}
function stand() {
if (!gameInProgress) return;
// Dealer draws until they have at least 17
while (calculateHandValue(dealerHand) < 17) {
dealerHand.push(deck.pop());
}
// Update display (show all dealer cards)
updateDisplay(true);
// Determine winner
const playerValue = calculateHandValue(playerHand);
const dealerValue = calculateHandValue(dealerHand);
if (dealerValue > 21 || playerValue > dealerValue) {
// Player wins
endGame(true);
} else if (playerValue < dealerValue) {
// Dealer wins
endGame(false);
} else {
// Push
endGame(null);
}
}
function doubleDown() {
if (!gameInProgress || !canDouble) return;
if (currentBet > chips) {
messageEl.textContent = "You don't have enough chips to double!";
messageEl.classList.remove('hidden');
return;
}
// Double the bet
chips -= currentBet;
currentBet *= 2;
chipsEl.textContent = chips;
betAmountEl.textContent = currentBet;
// Take one more card
hit();
// Automatically stand
stand();
}
function endGame(playerWins) {
gameInProgress = false;
// Show all dealer cards
updateDisplay(true);
// Payout
if (playerWins === true) {
const isBlackjack = calculateHandValue(playerHand) === 21 && playerHand.length === 2;
const payout = isBlackjack ? Math.floor(currentBet * 2.5) : currentBet * 2;
chips += payout;
messageEl.textContent = isBlackjack ? "Blackjack! You win $" + payout : "You win $" + payout;
} else if (playerWins === false) {
messageEl.textContent = "Dealer wins!";
} else {
// Push
chips += currentBet;
messageEl.textContent = "Push! Bet returned";
}
chipsEl.textContent = chips;
messageEl.classList.remove('hidden');
// Reset bet to minimum
currentBet = 50;
betSlider.value = currentBet;
betAmountEl.textContent = currentBet;
// Show bet controls, hide game controls
gameControls.classList.add('hidden');
betControls.classList.remove('hidden');
}
function updateDisplay(showAllDealerCards = false) {
// Clear hands
dealerHandEl.innerHTML = '';
playerHandEl.innerHTML = '';
// Display dealer's hand
dealerHand.forEach((card, index) => {
if (index === 0 && !showAllDealerCards) {
// First card is hidden
const cardEl = document.createElement('div');
cardEl.className = 'card card-back';
dealerHandEl.appendChild(cardEl);
} else {
// Show card
const cardEl = document.createElement('div');
cardEl.className = `card ${card.suit === 'hearts' || card.suit === 'diamonds' ? 'red' : 'black'}`;
cardEl.textContent = card.value;
// Add suit symbol
const suitSymbol = document.createElement('div');
suitSymbol.className = 'absolute bottom-1 right-1 text-xs';
switch(card.suit) {
case 'hearts':
suitSymbol.innerHTML = '&hearts;';
break;
case 'diamonds':
suitSymbol.innerHTML = '&diams;';
break;
case 'clubs':
suitSymbol.innerHTML = '&clubs;';
break;
case 'spades':
suitSymbol.innerHTML = '&spades;';
break;
}
cardEl.appendChild(suitSymbol);
dealerHandEl.appendChild(cardEl);
}
});
// Display player's hand
playerHand.forEach(card => {
const cardEl = document.createElement('div');
cardEl.className = `card ${card.suit === 'hearts' || card.suit === 'diamonds' ? 'red' : 'black'}`;
cardEl.textContent = card.value;
// Add suit symbol
const suitSymbol = document.createElement('div');
suitSymbol.className = 'absolute bottom-1 right-1 text-xs';
switch(card.suit) {
case 'hearts':
suitSymbol.innerHTML = '&hearts;';
break;
case 'diamonds':
suitSymbol.innerHTML = '&diams;';
break;
case 'clubs':
suitSymbol.innerHTML = '&clubs;';
break;
case 'spades':
suitSymbol.innerHTML = '&spades;';
break;
}
cardEl.appendChild(suitSymbol);
playerHandEl.appendChild(cardEl);
});
// Update totals
if (showAllDealerCards) {
dealerTotalEl.textContent = 'Total: ' + calculateHandValue(dealerHand);
} else {
// Only show value of dealer's up card
const upCardValue = dealerHand[1].value;
dealerTotalEl.textContent = 'Total: ?';
}
playerTotalEl.textContent = 'Total: ' + calculateHandValue(playerHand);
}
function calculateHandValue(hand) {
let value = 0;
let aces = 0;
for (let card of hand) {
if (card.value === 'A') {
aces++;
value += 11;
} else if (['K', 'Q', 'J'].includes(card.value)) {
value += 10;
} else {
value += parseInt(card.value);
}
}
// Adjust for aces if needed
while (value > 21 && aces > 0) {
value -= 10;
aces--;
}
return value;
}
}
// Memory Match Game
function initMemory() {
const memoryBoard = document.getElementById('memoryBoard');
const movesEl = document.getElementById('memoryMoves');
const pairsEl = document.getElementById('memoryPairs');
const resetBtn = document.getElementById('memoryResetBtn');
// Game state
let cards = [];
let flippedCards = [];
let moves = 0;
let pairsFound = 0;
let canFlip = true;
// Card values (8 pairs of letters)
const cardValues = ['A', 'A', 'B', 'B', 'C', 'C', 'D', 'D', 'E', 'E', 'F', 'F', 'G', 'G', 'H', 'H'];
// Initialize game
resetBtn.addEventListener('click', newGame);
newGame();
function newGame() {
// Reset game state
moves = 0;
pairsFound = 0;
flippedCards = [];
canFlip = true;
// Update UI
movesEl.textContent = moves;
pairsEl.textContent = pairsFound;
// Create shuffled deck
cards = [...cardValues];
for (let i = cards.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[cards[i], cards[j]] = [cards[j], cards[i]];
}
// Create card elements
memoryBoard.innerHTML = '';
cards.forEach((value, index) => {
const cardEl = document.createElement('div');
cardEl.className = 'memory-card';
cardEl.dataset.index = index;
cardEl.innerHTML = `
<div class="memory-card-inner">
<div class="memory-card-front"></div>
<div class="memory-card-back">${value}</div>
</div>
`;
cardEl.addEventListener('click', flipCard);
memoryBoard.appendChild(cardEl);
});
}
function flipCard() {
if (!canFlip || this.classList.contains('flipped')) return;
const index = parseInt(this.dataset.index);
// Don't allow flipping more than 2 cards
if (flippedCards.length >= 2) return;
// Flip the card
this.classList.add('flipped');
flippedCards.push({ element: this, value: cards[index] });
// If two cards are flipped, check for a match
if (flippedCards.length === 2) {
moves++;
movesEl.textContent = moves;
canFlip = false;
if (flippedCards[0].value === flippedCards[1].value) {
// Match found
pairsFound++;
pairsEl.textContent = pairsFound;
// Remove event listeners from matched cards
flippedCards[0].element.removeEventListener('click', flipCard);
flippedCards[1].element.removeEventListener('click', flipCard);
// Check if game is won
if (pairsFound === 8) {
setTimeout(() => {
alert(`Congratulations! You won in ${moves} moves!`);
}, 500);
}
flippedCards = [];
canFlip = true;
} else {
// No match - flip cards back after delay
setTimeout(() => {
flippedCards.forEach(card => {
card.element.classList.remove('flipped');
});
flippedCards = [];
canFlip = true;
}, 1000);
}
}
}
}
// War Game
function initWar() {
const playerCardEl = document.getElementById('playerWarCard');
const computerCardEl = document.getElementById('computerWarCard');
const playerCountEl = document.getElementById('playerWarCount');
const computerCountEl = document.getElementById('computerWarCount');
const roundsEl = document.getElementById('warRounds');
const messageEl = document.getElementById('warMessage');
const playBtn = document.getElementById('warPlayBtn');
const resetBtn = document.getElementById('warResetBtn');
// Game state
let deck = [];
let playerDeck = [];
let computerDeck = [];
let rounds = 0;
let gameOver = false;
// Initialize game
resetBtn.addEventListener('click', newGame);
playBtn.addEventListener('click', playRound);
newGame();
function newGame() {
// Reset game state
rounds = 0;
gameOver = false;
messageEl.textContent = '';
// Create and shuffle deck
const suits = ['hearts', 'diamonds', 'clubs', 'spades'];
const values = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
deck = [];
for (let suit of suits) {
for (let value of values) {
deck.push({ suit, value });
}
}
// Shuffle 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]];
}
// Deal cards to players
playerDeck = deck.slice(0, 26);
computerDeck = deck.slice(26);
// Update UI
updateUI();
}
function playRound() {
if (gameOver) return;
// Check if either player is out of cards
if (playerDeck.length === 0 || computerDeck.length === 0) {
endGame();
return;
}
// Increment round
rounds++;
roundsEl.textContent = rounds;
// Draw cards
const playerCard = playerDeck.shift();
const computerCard = computerDeck.shift();
// Display cards
displayCard(playerCard, playerCardEl);
displayCard(computerCard, computerCardEl);
// Compare cards
const playerValue = getCardValue(playerCard.value);
const computerValue = getCardValue(computerCard.value);
if (playerValue > computerValue) {
// Player wins the round
playerDeck.push(playerCard, computerCard);
messageEl.textContent = "You win this round!";
} else if (computerValue > playerValue) {
// Computer wins the round
computerDeck.push(playerCard, computerCard);
messageEl.textContent = "Computer wins this round!";
} else {
// War!
messageEl.textContent = "War!";
// Check if players have enough cards for war
if (playerDeck.length < 4 || computerDeck.length < 4) {
endGame();
return;
}
// Each player puts 3 cards face down and 1 face up
const playerFaceDown = playerDeck.splice(0, 3);
const computerFaceDown = computerDeck.splice(0, 3);
const playerWarCard = playerDeck.shift();
const computerWarCard = computerDeck.shift();
// Display war cards after a delay
setTimeout(() => {
displayCard(playerWarCard, playerCardEl);
displayCard(computerWarCard, computerCardEl);
const playerWarValue = getCardValue(playerWarCard.value);
const computerWarValue = getCardValue(computerWarCard.value);
if (playerWarValue > computerWarValue) {
// Player wins the war
playerDeck.push(
playerCard, computerCard,
...playerFaceDown, ...computerFaceDown,
playerWarCard, computerWarCard
);
messageEl.textContent = "You win the war!";
} else if (computerWarValue > playerWarValue) {
// Computer wins the war
computerDeck.push(
playerCard, computerCard,
...playerFaceDown, ...computerFaceDown,
playerWarCard, computerWarCard
);
messageEl.textContent = "Computer wins the war!";
} else {
// Another war - for simplicity, we'll just split the pot
playerDeck.push(...playerFaceDown, playerWarCard);
computerDeck.push(...computerFaceDown, computerWarCard);
messageEl.textContent = "Another war! Cards split.";
}
// Update UI
updateUI();
}, 1000);
}
// Update UI
updateUI();
}
function displayCard(card, element) {
element.className = `card ${card.suit === 'hearts' || card.suit === 'diamonds' ? 'red' : 'black'}`;
element.textContent = card.value;
// Add suit symbol
const suitSymbol = document.createElement('div');
suitSymbol.className = 'absolute bottom-1 right-1 text-xs';
switch(card.suit) {
case 'hearts':
suitSymbol.innerHTML = '&hearts;';
break;
case 'diamonds':
suitSymbol.innerHTML = '&diams;';
break;
case 'clubs':
suitSymbol.innerHTML = '&clubs;';
break;
case 'spades':
suitSymbol.innerHTML = '&spades;';
break;
}
element.appendChild(suitSymbol);
}
function getCardValue(value) {
const values = {
'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8,
'9': 9, '10': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14
};
return values[value];
}
function updateUI() {
playerCountEl.textContent = playerDeck.length;
computerCountEl.textContent = computerDeck.length;
}
function endGame() {
gameOver = true;
if (playerDeck.length > computerDeck.length) {
messageEl.textContent = "You win the game!";
} else if (computerDeck.length > playerDeck.length) {
messageEl.textContent = "Computer wins the game!";
} else {
messageEl.textContent = "The game is a tie!";
}
}
}
// Solitaire Game
function initSolitaire() {
const stockPileEl = document.getElementById('stockPile');
const wastePileEl = document.getElementById('wastePile');
const foundationPiles = {
'hearts': document.getElementById('foundationHeart'),
'diamonds': document.getElementById('foundationDiamond'),
'clubs': document.getElementById('foundationClub'),
'spades': document.getElementById('foundationSpade')
};
const tableauPiles = [
document.getElementById('pile1'),
document.getElementById('pile2'),
document.getElementById('pile3'),
document.getElementById('pile4'),
document.getElementById('pile5'),
document.getElementById('pile6'),
document.getElementById('pile7')
];
const timeEl = document.getElementById('solitaireTime');
const resetBtn = document.getElementById('solitaireResetBtn');
// Game state
let deck = [];
let stock = [];
let waste = [];
let foundations = {
'hearts': [],
'diamonds': [],
'clubs': [],
'spades': []
};
let tableau = [[], [], [], [], [], [], []];
let timer = null;
let seconds = 0;
let draggedCard = null;
let draggedCards = [];
let offsetX = 0;
let offsetY = 0;
// Initialize game
resetBtn.addEventListener('click', newGame);
stockPileEl.addEventListener('click', drawFromStock);
newGame();
// Set up drag and drop
document.addEventListener('mousedown', startDrag);
document.addEventListener('mousemove', dragCard);
document.addEventListener('mouseup', endDrag);
function newGame() {
// Reset timer
if (timer) clearInterval(timer);
seconds = 0;
updateTimer();
timer = setInterval(updateTimer, 1000);
// Create and shuffle deck
const suits = ['hearts', 'diamonds', 'clubs', 'spades'];
const values = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
deck = [];
for (let suit of suits) {
for (let value of values) {
deck.push({ suit, value, faceUp: false });
}
}
// Shuffle 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]];
}
// Reset game state
stock = [];
waste = [];
foundations = {
'hearts': [],
'diamonds': [],
'clubs': [],
'spades': []
};
tableau = [[], [], [], [], [], [], []];
// Deal to tableau
for (let i = 0; i < 7; i++) {
for (let j = 0; j <= i; j++) {
const card = deck.pop();
if (j === i) {
// Last card in pile is face up
card.faceUp = true;
}
tableau[i].push(card);
}
}
// Remaining cards go to stock
stock = [...deck];
// Update UI
updateUI();
}
function drawFromStock() {
if (stock.length === 0) {
// If stock is empty, recycle waste back to stock
stock = [...waste.reverse()];
waste = [];
stock.forEach(card => card.faceUp = false);
} else {
// Draw 1 card from stock to waste
const card = stock.pop();
card.faceUp = true;
waste.push(card);
}
updateUI();
}
function updateTimer() {
seconds++;
const minutes = Math.floor(seconds / 60);
const remainingSeconds = seconds % 60;
timeEl.textContent = `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
}
function updateUI() {
// Clear all piles
wastePileEl.innerHTML = '';
tableauPiles.forEach(pile => pile.innerHTML = '');
for (let suit in foundationPiles) {
foundationPiles[suit].innerHTML = '';
}
// Update stock
stockPileEl.innerHTML = stock.length > 0 ? '<i class="fas fa-crown"></i>' : '';
// Update waste
if (waste.length > 0) {
const topCard = waste[waste.length - 1];
createCardElement(topCard, wastePileEl, true);
}
// Update foundations
for (let suit in foundations) {
const pile = foundations[suit];
if (pile.length > 0) {
const topCard = pile[pile.length - 1];
createCardElement(topCard, foundationPiles[suit], true);
}
}
// Update tableau
for (let i = 0; i < 7; i++) {
const pile = tableau[i];
const pileEl = tableauPiles[i];
for (let j = 0; j < pile.length; j++) {
const card = pile[j];
createCardElement(card, pileEl, false, j * 20);
}
}
}
function createCardElement(card, parent, isTopCard, offset = 0) {
const cardEl = document.createElement('div');
cardEl.className = `solitaire-card ${card.suit === 'hearts' || card.suit === 'diamonds' ? 'red' : 'black'}`;
cardEl.style.top = `${offset}px`;
cardEl.dataset.suit = card.suit;
cardEl.dataset.value = card.value;
cardEl.dataset.faceUp = card.faceUp;
if (card.faceUp) {
cardEl.innerHTML = `
<div class="card-value">${card.value}</div>
<div class="card-suit">${getSuitSymbol(card.suit)}</div>
`;
} else {
cardEl.className += ' card-back';
}
if (isTopCard) {
cardEl.dataset.topCard = 'true';
}
parent.appendChild(cardEl);
return cardEl;
}
function getSuitSymbol(suit) {
switch(suit) {
case 'hearts': return '♥';
case 'diamonds': return '♦';
case 'clubs': return '♣';
case 'spades': return '♠';
}
}
function startDrag(e) {
if (!e.target.classList.contains('solitaire-card') || e.target.classList.contains('card-back')) return;
draggedCard = e.target;
draggedCards = [draggedCard];
// Calculate offset
const rect = draggedCard.getBoundingClientRect();
offsetX = e.clientX - rect.left;
offsetY = e.clientY - rect.top;
// If this is a tableau card, check if there are cards below it
const parentPile = draggedCard.parentElement;
if (parentPile.classList.contains('solitaire-pile')) {
const cards = Array.from(parentPile.querySelectorAll('.solitaire-card'));
const cardIndex = cards.indexOf(draggedCard);
// Add all cards below this one to draggedCards
for (let i = cardIndex + 1; i < cards.length; i++) {
draggedCards.push(cards[i]);
}
}
// Style the dragged cards
draggedCards.forEach((card, index) => {
card.style.position = 'absolute';
card.style.zIndex = '1000';
card.style.transform = `translate(${e.clientX - offsetX}px, ${e.clientY - offsetY + (index * 20)}px)`;
card.classList.add('dragging');
});
// Highlight valid drop targets
highlightDropTargets(true);
}
function dragCard(e) {
if (!draggedCard) return;
// Move all dragged cards
draggedCards.forEach((card, index) => {
card.style.transform = `translate(${e.clientX - offsetX}px, ${e.clientY - offsetY + (index * 20)}px)`;
});
}
function endDrag(e) {
if (!draggedCard) return;
// Remove highlight from drop targets
highlightDropTargets(false);
// Find the drop target
const dropTarget = document.elementFromPoint(e.clientX, e.clientY);
const validDrop = dropTarget && dropTarget.classList.contains('drop-target');
if (validDrop) {
// Check if the move is valid
const sourcePile = draggedCard.parentElement;
const sourceType = sourcePile.id.startsWith('pile') ? 'tableau' :
sourcePile.id.startsWith('foundation') ? 'foundation' :
sourcePile.id === 'wastePile' ? 'waste' : null;
const targetType = dropTarget.id.startsWith('pile') ? 'tableau' :
dropTarget.id.startsWith('foundation') ? 'foundation' : null;
// Get the card data
const cardData = {
suit: draggedCard.dataset.suit,
value: draggedCard.dataset.value,
faceUp: true
};
// Check if the move is valid
if (targetType === 'foundation') {
const targetSuit = dropTarget.dataset.suit;
const foundation = foundations[targetSuit];
// Check if the card can be placed on the foundation
if (canMoveToFoundation(cardData, foundation)) {
// Remove card from source
if (sourceType === 'tableau') {
const pileIndex = parseInt(sourcePile.dataset.pile) - 1;
const cardIndex = tableau[pileIndex].findIndex(c =>
c.suit === cardData.suit && c.value === cardData.value && c.faceUp
);
if (cardIndex !== -1) {
// Remove this card and all below it
const removedCards = tableau[pileIndex].splice(cardIndex);
foundations[targetSuit].push(removedCards[0]);
// Flip the next card if there is one
if (tableau[pileIndex].length > 0 && !tableau[pileIndex][tableau[pileIndex].length - 1].faceUp) {
tableau[pileIndex][tableau[pileIndex].length - 1].faceUp = true;
}
}
} else if (sourceType === 'waste') {
const wasteCard = waste.pop();
foundations[targetSuit].push(wasteCard);
}
}
} else if (targetType === 'tableau') {
const pileIndex = parseInt(dropTarget.dataset.pile) - 1;
const targetPile = tableau[pileIndex];
// Check if the card can be placed on the tableau pile
if (canMoveToTableau(cardData, targetPile)) {
// Remove card from source
if (sourceType === 'tableau') {
const sourcePileIndex = parseInt(sourcePile.dataset.pile) - 1;
const cardIndex = tableau[sourcePileIndex].findIndex(c =>
c.suit === cardData.suit && c.value === cardData.value && c.faceUp
);
if (cardIndex !== -1) {
// Remove this card and all below it
const removedCards = tableau[sourcePileIndex].splice(cardIndex);
tableau[pileIndex].push(...removedCards);
// Flip the next card if there is one
if (tableau[sourcePileIndex].length > 0 && !tableau[sourcePileIndex][tableau[sourcePileIndex].length - 1].faceUp) {
tableau[sourcePileIndex][tableau[sourcePileIndex].length - 1].faceUp = true;
}
}
} else if (sourceType === 'waste') {
const wasteCard = waste.pop();
tableau[pileIndex].push(wasteCard);
} else if (sourceType === 'foundation') {
const sourceSuit = sourcePile.dataset.suit;
const foundationCard = foundations[sourceSuit].pop();
tableau[pileIndex].push(foundationCard);
}
}
}
}
// Reset dragged card
draggedCards.forEach(card => {
card.style.position = '';
card.style.zIndex = '';
card.style.transform = '';
card.classList.remove('dragging');
});
draggedCard = null;
draggedCards = [];
// Update UI
updateUI();
// Check for win
checkWin();
}
function highlightDropTargets(highlight) {
document.querySelectorAll('.drop-target').forEach(target => {
const targetType = target.id.startsWith('pile') ? 'tableau' :
target.id.startsWith('foundation') ? 'foundation' : null;
if (!draggedCard) return;
const cardData = {
suit: draggedCard.dataset.suit,
value: draggedCard.dataset.value,
faceUp: true
};
let isValid = false;
if (targetType === 'foundation') {
const targetSuit = target.dataset.suit;
isValid = canMoveToFoundation(cardData, foundations[targetSuit]);
} else if (targetType === 'tableau') {
const pileIndex = parseInt(target.dataset.pile) - 1;
isValid = canMoveToTableau(cardData, tableau[pileIndex]);
}
if (highlight && isValid) {
target.classList.add('highlight');
} else {
target.classList.remove('highlight');
}
});
}
function canMoveToFoundation(card, foundation) {
if (foundation.length === 0) {
return card.value === 'A';
} else {
const topCard = foundation[foundation.length - 1];
const cardValues = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
const currentIndex = cardValues.indexOf(topCard.value);
return card.suit === topCard.suit && cardValues.indexOf(card.value) === currentIndex + 1;
}
}
function canMoveToTableau(card, pile) {
if (pile.length === 0) {
return card.value === 'K';
} else {
const topCard = pile[pile.length - 1];
const cardValues = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
const currentIndex = cardValues.indexOf(topCard.value);
const newIndex = cardValues.indexOf(card.value);
const differentColor =
(topCard.suit === 'hearts' || topCard.suit === 'diamonds') !==
(card.suit === 'hearts' || card.suit === 'diamonds');
return differentColor && newIndex === currentIndex - 1;
}
}
function checkWin() {
for (let suit in foundations) {
if (foundations[suit].length !== 13) return false;
}
// All foundations are complete
alert('Congratulations! You won the game!');
return true;
}
}
</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=CroissantWhyNot/game-hub" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>