import React, { useState, useEffect } from 'react';
// Types de cartes éléments et leurs valeurs
const ELEMENT_COLORS = ['violet', 'blue', 'orange', 'green', 'gray'];
const ELEMENT_VALUES = [1, 2, 3, 5, 8];
// Création du deck complet d'éléments
const createElementDeck = () => {
const deck = [];
ELEMENT_COLORS.forEach(color => {
ELEMENT_VALUES.forEach(value => {
deck.push({ color, value });
});
});
return deck;
};
// Mélanger un array (Fisher-Yates shuffle)
const shuffleArray = (array) => {
const shuffled = [...array];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled;
};
const CHARACTERS = {
tigreblanc: {
name: "Tigre Blanc",
stats: [7, 4, 2, 5, 2],
ability: "Fidèles Compagnons"
},
barbare: {
name: "Barbare Squelette",
stats: [4, 6, 3, 3, 8],
ability: "Carnage"
}
};
const LegendsGame = () => {
const [gameState, setGameState] = useState({
playerHand: [], // Cartes du joueur
enemyPlacement: [], // Cartes placées du Barbare
playerPlacements: {}, // Cartes placées par le joueur
selectedCard: null, // Carte sélectionnée pour placement
phase: 'setup', // 'setup', 'playing', 'finished'
currentRound: 1, // Round actuel
score: { player: 0, enemy: 0 }, // Score de la partie
drawPile: [], // Pioche restante
tieBreakers: {} // Cartes de départage pour chaque round
});
// Fonction pour initialiser une nouvelle partie
const initializeGame = () => {
const deck = shuffleArray(createElementDeck());
const playerHand = deck.slice(0, 4);
const enemyCards = deck.slice(4, 7);
const enemyPlacement = enemyCards.map(card => ({ ...card }));
const drawPile = deck.slice(7); // Le reste des cartes va dans la pioche
setGameState({
playerHand,
enemyPlacement,
playerPlacements: {},
selectedCard: null,
phase: 'setup',
currentRound: 1,
score: { player: 0, enemy: 0 },
drawPile,
tieBreakers: {}
});
};
// Initialisation au montage du composant
useEffect(() => {
initializeGame();
}, []);
// Sélectionner une carte de la main
const selectCard = (index) => {
if (gameState.phase !== 'setup') return;
setGameState(prev => ({
...prev,
selectedCard: index
}));
};
// Placer une carte sur un round
const placeCard = (round) => {
if (gameState.phase !== 'setup' || gameState.selectedCard === null) return;
if (gameState.playerPlacements[round]) return; // Déjà une carte sur ce round
const newPlacements = {
...gameState.playerPlacements,
[round]: gameState.playerHand[gameState.selectedCard]
};
// Retirer la carte de la main
const newHand = gameState.playerHand.filter((_, idx) => idx !== gameState.selectedCard);
// Vérifier si toutes les cartes sont placées
const allCardsPlaced = Object.keys(newPlacements).length === 3;
setGameState(prev => ({
...prev,
playerPlacements: newPlacements,
playerHand: newHand,
selectedCard: null,
phase: allCardsPlaced ? 'playing' : 'setup'
}));
};
// Résoudre un round
const resolveRound = () => {
const currentRound = gameState.currentRound;
// Calculer les valeurs totales
const playerValue = (gameState.playerPlacements[currentRound]?.value || 0) +
CHARACTERS.tigreblanc.stats[currentRound - 1];
const enemyValue = (gameState.enemyPlacement[currentRound - 1]?.value || 0) +
CHARACTERS.barbare.stats[currentRound - 1];
// En cas d'égalité, piocher une carte pour départager
let tieBreaker = null;
if (playerValue === enemyValue && gameState.drawPile.length > 0) {
const [newCard, ...remainingDeck] = gameState.drawPile;
tieBreaker = newCard;
const newTieBreakers = {
...gameState.tieBreakers,
[currentRound]: newCard
};
setGameState(prev => ({
...prev,
drawPile: remainingDeck,
tieBreakers: newTieBreakers
}));
}
// Mettre à jour le score
const newScore = { ...gameState.score };
const finalPlayerValue = playerValue + (tieBreaker?.value || 0);
const finalEnemyValue = enemyValue + (tieBreaker?.value || 0);
if (finalPlayerValue > finalEnemyValue) {
newScore.player += 1;
} else if (finalEnemyValue > finalPlayerValue) {
newScore.enemy += 1;
}
// Vérifier si la partie est terminée
const isGameOver = currentRound === 3 || newScore.player === 2 || newScore.enemy === 2;
setGameState(prev => ({
...prev,
currentRound: currentRound + 1,
score: newScore,
phase: isGameOver ? 'finished' : 'playing'
}));
};
return (
<div className="min-h-screen bg-gray-900 text-white p-8">
<div className="flex gap-8">
{/* Zone principale du jeu */}
<div className="flex-1">
{/* En-tête du jeu */}
<div className="mb-8 text-center">
<h1 className="text-3xl font-bold mb-4">Legends</h1>
<div className="text-xl">
{gameState.phase === 'setup' && "Placez vos cartes sur les rounds"}
{gameState.phase === 'playing' && `Round ${gameState.currentRound}`}
{gameState.phase === 'finished' && "Partie terminée"}
</div>
<div className="text-xl mt-2">
Score - Tigre Blanc: {gameState.score.player} | Barbare: {gameState.score.enemy}
</div>
</div>
{/* Zone de l'ennemi */}
<div className="mb-12">
<div className="flex gap-8 items-center">
{/* Carte du Barbare Squelette */}
<div className="w-48 bg-gray-800 rounded-lg shadow-lg flex">
<div className="w-12 py-4 flex flex-col items-center gap-2">
<div className="w-8 h-8 bg-red-600 rounded-full flex items-center justify-center text-white font-bold">4</div>
<div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center text-white font-bold">6</div>
<div className="w-8 h-8 bg-purple-600 rounded-full flex items-center justify-center text-white font-bold">3</div>
<div className="w-8 h-8 bg-green-600 rounded-full flex items-center justify-center text-white font-bold">3</div>
<div className="w-8 h-8 bg-gray-600 rounded-full flex items-center justify-center text-white font-bold">8</div>
</div>
<div className="flex-1 p-4">
<h3 className="text-lg font-bold mb-2">{CHARACTERS.barbare.name}</h3>
<p className="text-sm text-gray-300">{CHARACTERS.barbare.ability}</p>
</div>
</div>
{/* Cartes placées de l'ennemi */}
<div className="flex gap-8">
{[1, 2, 3].map(round => (
<div key={round} className="relative">
<span className="absolute -top-6 w-full text-center">Round {round}</span>
<div className="w-32 h-48 bg-gray-800 rounded-lg flex items-center justify-center">
{gameState.phase === 'finished' || round < gameState.currentRound ? (
<div className={`w-full h-full rounded-lg flex items-center justify-center
${gameState.enemyPlacement[round-1]?.color === 'violet' ? 'bg-purple-700' :
gameState.enemyPlacement[round-1]?.color === 'blue' ? 'bg-blue-700' :
gameState.enemyPlacement[round-1]?.color === 'orange' ? 'bg-orange-700' :
gameState.enemyPlacement[round-1]?.color === 'green' ? 'bg-green-700' :
'bg-gray-700'}`}>
<span className="text-2xl font-bold">
+{gameState.enemyPlacement[round-1]?.value}
</span>
</div>
) : (
<div className="w-full h-full bg-gradient-to-br from-amber-900 to-yellow-800 rounded-lg" />
)}
</div>
</div>
))}
</div>
</div>
</div>
{/* Zone du joueur */}
<div className="mb-8">
<div className="flex gap-8 items-center">
{/* Carte du Tigre Blanc */}
<div className="w-48 bg-gray-800 rounded-lg shadow-lg flex">
<div className="w-12 py-4 flex flex-col items-center gap-2">
<div className="w-8 h-8 bg-red-600 rounded-full flex items-center justify-center text-white font-bold">7</div>
<div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center text-white font-bold">4</div>
<div className="w-8 h-8 bg-purple-600 rounded-full flex items-center justify-center text-white font-bold">2</div>
<div className="w-8 h-8 bg-green-600 rounded-full flex items-center justify-center text-white font-bold">5</div>
<div className="w-8 h-8 bg-gray-600 rounded-full flex items-center justify-center text-white font-bold">2</div>
</div>
<div className="flex-1 p-4">
<h3 className="text-lg font-bold mb-2">{CHARACTERS.tigreblanc.name}</h3>
<p className="text-sm text-gray-300">{CHARACTERS.tigreblanc.ability}</p>
</div>
</div>
{/* Emplacements pour placer les cartes */}
<div className="flex gap-8">
{[1, 2, 3].map(round => (
<div
key={round}
onClick={() => placeCard(round)}
className={`relative cursor-pointer ${gameState.selectedCard !== null ? 'hover:scale-105 transition-transform' : ''}`}
>
<span className="absolute -top-6 w-full text-center">Round {round}</span>
<div className="w-32 h-48 bg-gray-800 rounded-lg flex items-center justify-center">
{gameState.playerPlacements[round] && (
<div className={`w-full h-full rounded-lg flex items-center justify-center
${gameState.playerPlacements[round].color === 'violet' ? 'bg-purple-700' :
gameState.playerPlacements[round].color === 'blue' ? 'bg-blue-700' :
gameState.playerPlacements[round].color === 'orange' ? 'bg-orange-700' :
gameState.playerPlacements[round].color === 'green' ? 'bg-green-700' :
'bg-gray-700'}`}>
<span className="text-2xl font-bold">
+{gameState.playerPlacements[round].value}
</span>
</div>
)}
</div>
</div>
))}
</div>
</div>
{/* Main du joueur */}
{gameState.phase === 'setup' && (
<div className="flex gap-8 mt-8 justify-center">
{gameState.playerHand.map((card, index) => (
<button
key={index}
onClick={() => selectCard(index)}
className={`w-32 h-48 rounded-lg flex items-center justify-center text-2xl font-bold
transform transition-all
${gameState.selectedCard === index ? 'ring-4 ring-yellow-400 scale-105' : 'hover:scale-105'}
${card.color === 'violet' ? 'bg-purple-700' :
card.color === 'blue' ? 'bg-blue-700' :
card.color === 'orange' ? 'bg-orange-700' :
card.color === 'green' ? 'bg-green-700' :
'bg-gray-700'}`}
>
+{card.value}
</button>
))}
</div>
)}
{/* Bouton pour résoudre le round */}
{gameState.phase === 'playing' && (
<div className="flex justify-center mt-8">
<button
onClick={resol