/// import * as React from 'react'; const { useState, useEffect } = React; import { getGameState } from '../services/api'; import { setSoundEnabled, isSoundEnabled, playSound } from '../services/soundService'; interface GameInfoProps { boardTheme: 'brown' | 'grey'; onThemeChange: (theme: 'brown' | 'grey') => void; } const GameInfo: React.FC = ({ boardTheme, onThemeChange }) => { const [soundOn, setSoundOn] = useState(true); const [gameState, setGameState] = useState(null); const [moveHistory, setMoveHistory] = useState([]); const [analysis, setAnalysis] = useState(null); const [whiteCaptured, setWhiteCaptured] = useState([]); const [blackCaptured, setBlackCaptured] = useState([]); useEffect(() => { fetchGameInfo(); const interval = setInterval(fetchGameInfo, 2000); // Poll every 2 seconds return () => clearInterval(interval); }, []); const fetchGameInfo = async () => { try { const response = await getGameState(); // Track captured pieces by comparing current board with previous board if (gameState && response.board_state && response.board_state.fen) { const previousPieces = parseFen(gameState.board_state.fen); const currentPieces = parseFen(response.board_state.fen); // Find pieces that were captured in the last move const capturedWhitePieces = findCapturedPieces(previousPieces, currentPieces, 'white'); const capturedBlackPieces = findCapturedPieces(previousPieces, currentPieces, 'black'); if (capturedWhitePieces.length > 0) { setWhiteCaptured(prev => [...prev, ...capturedWhitePieces]); } if (capturedBlackPieces.length > 0) { setBlackCaptured(prev => [...prev, ...capturedBlackPieces]); } } setGameState(response); if (response.last_analysis) { setAnalysis(response.last_analysis); } // Update move history if available if (response.board_state && response.board_state.move_count > moveHistory.length) { // In a real implementation, you would get the actual moves from the API // For now, we'll create placeholder moves with algebraic notation if (response.player_move && response.ai_move) { setMoveHistory(prev => [ ...prev, response.player_move, response.ai_move ]); } else if (response.player_move) { setMoveHistory(prev => [...prev, response.player_move]); } else if (response.ai_move) { setMoveHistory(prev => [...prev, response.ai_move]); } else { // Fallback if no specific moves are provided setMoveHistory(prev => [...prev, `Move ${prev.length + 1}`]); } } } catch (error) { console.error('Error fetching game info:', error); } }; // Helper function to parse FEN string and get pieces const parseFen = (fenString: string): {type: string, color: string}[] => { const pieces: {type: string, color: string}[] = []; const fenParts = fenString.split(' '); const ranks = fenParts[0].split('/'); ranks.forEach((rank) => { let fileIndex = 0; for (let i = 0; i < rank.length; i++) { const char = rank[i]; if (!isNaN(parseInt(char))) { fileIndex += parseInt(char); } else { const color = char === char.toUpperCase() ? 'white' : 'black'; const type = char.toLowerCase(); pieces.push({ type, color }); fileIndex++; } } }); return pieces; }; // Helper function to find captured pieces const findCapturedPieces = ( previousPieces: {type: string, color: string}[], currentPieces: {type: string, color: string}[], color: string ): string[] => { const captured: string[] = []; // Count pieces by type in previous and current board const previousCount: Record = {}; const currentCount: Record = {}; previousPieces.forEach(piece => { if (piece.color === color) { const key = piece.type; previousCount[key] = (previousCount[key] || 0) + 1; } }); currentPieces.forEach(piece => { if (piece.color === color) { const key = piece.type; currentCount[key] = (currentCount[key] || 0) + 1; } }); // Find pieces that were captured (more in previous than current) Object.keys(previousCount).forEach(type => { const diff = previousCount[type] - (currentCount[type] || 0); for (let i = 0; i < diff; i++) { captured.push(type); } }); return captured; }; const renderGameStatus = () => { if (!gameState) return

Loading game state...

; const { status, board_state, player_color } = gameState; let statusText = 'Game in progress'; let statusClass = 'text-gradio-blue'; if (status === 'game_over') { statusText = gameState.result === 'draw' ? 'Game ended in a draw' : `${gameState.winner} wins by ${gameState.reason}`; statusClass = 'text-gradio-red'; } else if (board_state.game_state === 'check') { statusText = `${board_state.turn} is in check`; statusClass = 'text-gradio-orange'; } return (

Game Status

{statusText}

Turn: {board_state.turn}
Playing as: {player_color}
{gameState.difficulty && (
Difficulty: {gameState.difficulty}
)}
); }; const renderAnalysis = () => { if (!analysis) return null; return (

Position Analysis

Evaluation: {analysis.evaluation.total > 0 ? '+' : ''}{analysis.evaluation.total.toFixed(2)}

0 ? 'bg-blue-600' : 'bg-black'}`} style={{ width: `${Math.min(Math.abs(analysis.evaluation.total) * 10, 100)}%`, marginLeft: analysis.evaluation.total > 0 ? '50%' : undefined, marginRight: analysis.evaluation.total < 0 ? '50%' : undefined, }} >

Material: {analysis.evaluation.material.toFixed(2)} | Position: {analysis.evaluation.positional.toFixed(2)} | Safety: {analysis.evaluation.safety.toFixed(2)}

); }; const renderMoveHistory = () => { if (moveHistory.length === 0) return

No moves yet

; // Group moves by pairs (white and black) const moveGroups = []; for (let i = 0; i < moveHistory.length; i += 2) { moveGroups.push({ number: Math.floor(i / 2) + 1, white: moveHistory[i], black: i + 1 < moveHistory.length ? moveHistory[i + 1] : null }); } return (
{moveGroups.map((group) => ( ))}
# White Black
{group.number}. {group.white} {group.black}
); }; // Initialize sound settings useEffect(() => { setSoundEnabled(soundOn); }, [soundOn]); return (

Game Information

{/* Sound Controls */}

Settings

{/* Theme selection removed but kept in code for future reference
Board Theme:
*/}
Sound Effects:
{renderGameStatus()}

Captured Pieces

White captured:

{whiteCaptured.map((piece, index) => ( {piece === 'p' ? '♙' : piece === 'r' ? '♖' : piece === 'n' ? '♘' : piece === 'b' ? '♗' : piece === 'q' ? '♕' : '♔'} ))} {whiteCaptured.length === 0 && None}

Black captured:

{blackCaptured.map((piece, index) => ( {piece === 'p' ? '♟' : piece === 'r' ? '♜' : piece === 'n' ? '♞' : piece === 'b' ? '♝' : piece === 'q' ? '♛' : '♚'} ))} {blackCaptured.length === 0 && None}

Move History

{moveHistory.length === 0 ? ( ) : ( Array.from({ length: Math.ceil(moveHistory.length / 2) }).map((_, i) => ( )) )}
# White Black
No moves yet
{i + 1}. {moveHistory[i * 2] || ''} {moveHistory[i * 2 + 1] || ''}
{analysis && (

Position Analysis

Evaluation: {analysis.evaluation.total > 0 ? '+' : ''}{analysis.evaluation.total.toFixed(2)}

0 ? 'bg-gradio-blue' : 'bg-gradio-red'}`} style={{ width: `${Math.min(Math.abs(analysis.evaluation.total) * 10, 100)}%`, marginLeft: analysis.evaluation.total > 0 ? '50%' : undefined, marginRight: analysis.evaluation.total < 0 ? '50%' : undefined, }} >
Material: {analysis.evaluation.material.toFixed(2)}
Position: {analysis.evaluation.positional.toFixed(2)}
Safety: {analysis.evaluation.safety.toFixed(2)}
Mobility: {analysis.evaluation.mobility.toFixed(2)}
)}
); }; export default GameInfo;