darkmaria / templates /index.html
Docfile's picture
Update templates/index.html
39851f5 verified
raw
history blame
14.5 kB
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chess vs Stockfish</title>
<!-- Chess.js et Chessboard.js -->
<link rel="stylesheet" href="https://unpkg.com/@chrisoakman/[email protected]/dist/chessboard-1.0.0.min.css">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://unpkg.com/[email protected]/chess.min.js"></script>
<script src="https://unpkg.com/@chrisoakman/[email protected]/dist/chessboard-1.0.0.min.js"></script>
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
box-sizing: border-box;
}
.container {
background: rgba(255, 255, 255, 0.95);
border-radius: 20px;
padding: 30px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
backdrop-filter: blur(10px);
}
h1 {
text-align: center;
color: #333;
margin-bottom: 30px;
font-size: 2.5em;
text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
}
.game-container {
display: flex;
gap: 30px;
justify-content: center;
align-items: flex-start;
flex-wrap: wrap;
}
.board-container {
flex-shrink: 0;
}
#myBoard {
border: 4px solid #8B4513;
border-radius: 10px;
box-shadow: 0 10px 25px rgba(0,0,0,0.3);
}
.info-panel {
background: #f8f9fa;
border-radius: 15px;
padding: 25px;
min-width: 300px;
box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}
.status {
font-size: 1.2em;
font-weight: bold;
margin-bottom: 15px;
padding: 15px;
border-radius: 10px;
text-align: center;
}
.status.playing {
background: linear-gradient(45deg, #4CAF50, #45a049);
color: white;
}
.status.game-over {
background: linear-gradient(45deg, #f44336, #d32f2f);
color: white;
}
.controls {
display: flex;
flex-direction: column;
gap: 15px;
margin-top: 20px;
}
button {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border: none;
padding: 12px 20px;
border-radius: 8px;
cursor: pointer;
font-size: 1em;
font-weight: bold;
transition: all 0.3s ease;
box-shadow: 0 4px 10px rgba(0,0,0,0.2);
}
button:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 6px 15px rgba(0,0,0,0.3);
}
button:disabled {
background: #ccc;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.evaluation {
background: #e3f2fd;
padding: 15px;
border-radius: 10px;
margin: 15px 0;
border-left: 4px solid #2196F3;
}
.evaluation h3 {
margin: 0 0 10px 0;
color: #1976D2;
}
.move-history {
background: #fff3e0;
padding: 15px;
border-radius: 10px;
margin: 15px 0;
border-left: 4px solid #FF9800;
max-height: 200px;
overflow-y: auto;
}
.move-history h3 {
margin: 0 0 10px 0;
color: #F57C00;
}
.loading {
display: none;
text-align: center;
color: #666;
font-style: italic;
margin: 10px 0;
}
.loading.show {
display: block;
}
.error {
background: #ffebee;
color: #c62828;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
border-left: 4px solid #f44336;
}
@media (max-width: 768px) {
.game-container {
flex-direction: column;
align-items: center;
}
.info-panel {
min-width: auto;
width: 100%;
max-width: 500px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>🏁 Chess vs Stockfish</h1>
<div class="game-container">
<div class="board-container">
<div id="myBoard" style="width: 400px"></div>
</div>
<div class="info-panel">
<div id="status" class="status playing">À vous de jouer !</div>
<div class="loading" id="loading">
Stockfish réfléchit... ⏳
</div>
<div class="evaluation">
<h3>📊 Évaluation</h3>
<div id="evaluation">Position de départ</div>
</div>
<div class="move-history">
<h3>📝 Derniers coups</h3>
<div id="moveHistory">Nouvelle partie</div>
</div>
<div class="controls">
<button id="newGameBtn">🔄 Nouvelle partie</button>
<button id="analyzeBtn">🔍 Analyser position</button>
<button id="flipBtn">🔄 Retourner échiquier</button>
</div>
<div id="error" class="error" style="display: none;"></div>
</div>
</div>
</div>
<script>
let game = new Chess();
let board = null;
let gameOver = false;
let moveHistory = [];
// Configuration de l'échiquier
const config = {
draggable: true,
position: 'start',
onDragStart: onDragStart,
onDrop: onDrop,
onSnapEnd: onSnapEnd
};
board = Chessboard('myBoard', config);
function onDragStart(source, piece, position, orientation) {
// Ne pas permettre de déplacer les pièces si c'est terminé
if (gameOver) return false;
// Ne permettre de déplacer que les pièces blanches (joueur)
if (piece.search(/^b/) !== -1) return false;
// Ne pas permettre de déplacer si ce n'est pas le tour des blancs
if (game.turn() === 'b') return false;
}
function onDrop(source, target) {
// Voir si le coup est légal
const move = game.move({
from: source,
to: target,
promotion: 'q' // Toujours promouvoir en dame pour simplifier
});
// Coup illégal
if (move === null) return 'snapback';
// Coup légal - envoyer au serveur
makeMove(move.san);
}
function onSnapEnd() {
board.position(game.fen());
}
function makeMove(userMove) {
if (gameOver) return;
showLoading(true);
hideError();
fetch('/api/move', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
fen: game.fen(),
move: userMove
})
})
.then(response => response.json())
.then(data => {
showLoading(false);
if (data.error) {
showError(data.error);
// Rétablir la position précédente
game.undo();
board.position(game.fen());
return;
}
// Mettre à jour le jeu avec la nouvelle position
game.load(data.fen);
board.position(game.fen());
// Ajouter les coups à l'historique
if (data.stockfish_move) {
addToMoveHistory(userMove, data.stockfish_move);
} else {
addToMoveHistory(userMove, null);
}
// Mettre à jour l'évaluation
updateEvaluation(data.evaluation);
// Vérifier si la partie est terminée
if (data.game_over) {
gameOver = true;
updateStatus(data.result || 'Partie terminée', true);
} else {
updateStatus('À vous de jouer !', false);
}
})
.catch(error => {
showLoading(false);
showError('Erreur de communication: ' + error.message);
// Rétablir la position précédente
game.undo();
board.position(game.fen());
});
}
function showLoading(show) {
const loading = document.getElementById('loading');
if (show) {
loading.classList.add('show');
} else {
loading.classList.remove('show');
}
}
function showError(message) {
const errorDiv = document.getElementById('error');
errorDiv.textContent = message;
errorDiv.style.display = 'block';
}
function hideError() {
document.getElementById('error').style.display = 'none';
}
function updateStatus(message, isGameOver = false) {
const statusDiv = document.getElementById('status');
statusDiv.textContent = message;
statusDiv.className = isGameOver ? 'status game-over' : 'status playing';
}
function updateEvaluation(evaluation) {
const evalDiv = document.getElementById('evaluation');
if (evaluation.type === 'cp') {
const centipawns = evaluation.value;
const pawns = (centipawns / 100).toFixed(2);
if (pawns > 0) {
evalDiv.textContent = `Blancs +${pawns}`;
} else if (pawns < 0) {
evalDiv.textContent = `Noirs +${Math.abs(pawns)}`;
} else {
evalDiv.textContent = 'Position équilibrée';
}
} else if (evaluation.type === 'mate') {
const mateIn = evaluation.value;
if (mateIn > 0) {
evalDiv.textContent = `Mat en ${mateIn} pour les blancs`;
} else if (mateIn < 0) {
evalDiv.textContent = `Mat en ${Math.abs(mateIn)} pour les noirs`;
} else {
evalDiv.textContent = 'Mat ou Pat';
}
}
}
function addToMoveHistory(userMove, stockfishMove) {
moveHistory.push({user: userMove, stockfish: stockfishMove});
const historyDiv = document.getElementById('moveHistory');
const lastMoves = moveHistory.slice(-5); // Garder les 5 derniers coups
let historyText = '';
lastMoves.forEach((moves, index) => {
const moveNum = moveHistory.length - lastMoves.length + index + 1;
historyText += `${moveNum}. ${moves.user}`;
if (moves.stockfish) {
historyText += ` ${moves.stockfish}`;
}
historyText += '\n';
});
historyDiv.textContent = historyText || 'Aucun coup joué';
}
// Gestionnaires d'événements pour les boutons
document.getElementById('newGameBtn').addEventListener('click', function() {
fetch('/api/new_game', {method: 'POST'})
.then(response => response.json())
.then(data => {
game = new Chess();
board.start();
gameOver = false;
moveHistory = [];
updateStatus('À vous de jouer !', false);
updateEvaluation({type: 'cp', value: 0});
document.getElementById('moveHistory').textContent = 'Nouvelle partie';
hideError();
})
.catch(error => {
showError('Erreur lors du démarrage: ' + error.message);
});
});
document.getElementById('analyzeBtn').addEventListener('click', function() {
fetch('/api/analyze', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({fen: game.fen()})
})
.then(response => response.json())
.then(data => {
if (data.error) {
showError(data.error);
return;
}
updateEvaluation(data.evaluation);
if (data.best_move) {
showError(`Meilleur coup suggéré: ${data.best_move}`);
}
})
.catch(error => {
showError('Erreur d\'analyse: ' + error.message);
});
});
document.getElementById('flipBtn').addEventListener('click', function() {
board.flip();
});
// Initialiser l'évaluation de départ
updateEvaluation({type: 'cp', value: 0});
</script>
</body>
</html>