fixes
This commit is contained in:
@@ -1 +0,0 @@
|
|||||||
404: Not Found
|
|
||||||
@@ -199,12 +199,13 @@ export default function ChessGame({ initialFen, initialPgn, initialPersonality,
|
|||||||
|
|
||||||
// Pre-Analysis (P0)
|
// Pre-Analysis (P0)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (stockfish && gameRef.current.turn() === 'w' && !isAnalyzing && !gameOverState) {
|
const playerTurn = playerColor === 'white' ? 'w' : 'b';
|
||||||
|
if (stockfish && gameRef.current.turn() === playerTurn && !isAnalyzing && !gameOverState) {
|
||||||
stockfish.evaluate(gameRef.current.fen(), stockfishDepth).then(evalResult => {
|
stockfish.evaluate(gameRef.current.fen(), stockfishDepth).then(evalResult => {
|
||||||
setEvalP0(evalResult);
|
setEvalP0(evalResult);
|
||||||
}).catch(err => console.error("Pre-analysis failed:", err));
|
}).catch(err => console.error("Pre-analysis failed:", err));
|
||||||
}
|
}
|
||||||
}, [fen, stockfish, stockfishDepth, isAnalyzing, gameOverState]);
|
}, [playerColor, fen, stockfish, stockfishDepth, isAnalyzing, gameOverState]);
|
||||||
|
|
||||||
const updateCapturedPieces = useCallback(() => {
|
const updateCapturedPieces = useCallback(() => {
|
||||||
const history = gameRef.current.history({ verbose: true });
|
const history = gameRef.current.history({ verbose: true });
|
||||||
|
|||||||
@@ -38,19 +38,22 @@ export function GameAnalysisModal({ fen, stockfish, apiKey, language, onClose }:
|
|||||||
// 3. LLM Summary
|
// 3. LLM Summary
|
||||||
if (apiKey && evalResult) {
|
if (apiKey && evalResult) {
|
||||||
const model = getGenAIModel(apiKey, "gemini-2.5-flash");
|
const model = getGenAIModel(apiKey, "gemini-2.5-flash");
|
||||||
|
const evalInPawns = (evalResult.score / 100).toFixed(2);
|
||||||
const prompt = `
|
const prompt = `
|
||||||
You are a Chess Grandmaster Analyst.
|
You are a Chess Grandmaster Analyst.
|
||||||
Analyze this position for the user.
|
Analyze this position for the user.
|
||||||
|
|
||||||
DATA:
|
DATA:
|
||||||
- FEN: ${fen}
|
- FEN: ${fen}
|
||||||
- Evaluation: ${evalResult.score} cp (positive = White advantage, negative = Black advantage)
|
- Evaluation: ${evalInPawns} pawns (${evalResult.score} centipawns)
|
||||||
|
Note: Positive = White advantage, Negative = Black advantage
|
||||||
|
100 centipawns = 1 pawn
|
||||||
- Mate in: ${evalResult.mate ?? "N/A"}
|
- Mate in: ${evalResult.mate ?? "N/A"}
|
||||||
- Best Move: ${evalResult.bestMove}
|
- Best Move: ${evalResult.bestMove}
|
||||||
- Opening: ${openingData ? `${openingData.name} (${openingData.eco})` : "Unknown/Midgame"}
|
- Opening: ${openingData ? `${openingData.name} (${openingData.eco})` : "Unknown/Midgame"}
|
||||||
|
|
||||||
INSTRUCTIONS:
|
INSTRUCTIONS:
|
||||||
1. Summarize who is winning and why (based on score).
|
1. Summarize who is winning and why (based on score). Use the pawn value (e.g., "White is up 2.5 pawns" not "250 centipawns").
|
||||||
2. Identify the key strategic factors (space, piece activity, king safety).
|
2. Identify the key strategic factors (space, piece activity, king safety).
|
||||||
3. Mention the opening if relevant.
|
3. Mention the opening if relevant.
|
||||||
4. Keep it concise (max 3-4 sentences).
|
4. Keep it concise (max 3-4 sentences).
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ export interface MoveHistoryItem {
|
|||||||
evalBefore: number; // cp
|
evalBefore: number; // cp
|
||||||
evalAfter: number; // cp
|
evalAfter: number; // cp
|
||||||
bestMove?: string;
|
bestMove?: string;
|
||||||
|
category?: 'inaccuracy' | 'mistake' | 'blunder';
|
||||||
|
cpLoss?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GameOverModalProps {
|
interface GameOverModalProps {
|
||||||
@@ -31,41 +33,56 @@ export function GameOverModal({ result, winner, history, apiKey, language, onClo
|
|||||||
const analyzeGame = async () => {
|
const analyzeGame = async () => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
try {
|
try {
|
||||||
// 1. Identify Mistakes (Blunders)
|
// 1. Identify Mistakes with proper categorization
|
||||||
// A blunder is roughly a drop of > 100cp (1 pawn) or missing a mate
|
// Standard chess analysis thresholds:
|
||||||
const detectedMistakes = history.filter(item => {
|
// - Inaccuracy: 50-100 centipawns loss
|
||||||
const delta = item.evalAfter - item.evalBefore;
|
// - Mistake: 100-300 centipawns loss
|
||||||
// Note: eval is from White's perspective.
|
// - Blunder: 300+ centipawns loss
|
||||||
// If White moves, eval should ideally go up or stay same.
|
const detectedMistakes = history.map(item => {
|
||||||
// If eval drops significantly, it's a mistake.
|
const delta = item.evalBefore - item.evalAfter; // Positive = eval got worse for player
|
||||||
return delta <= -100;
|
let category: 'inaccuracy' | 'mistake' | 'blunder' | null = null;
|
||||||
});
|
|
||||||
|
if (delta >= 300) category = 'blunder';
|
||||||
|
else if (delta >= 100) category = 'mistake';
|
||||||
|
else if (delta >= 50) category = 'inaccuracy';
|
||||||
|
|
||||||
|
return { ...item, category, cpLoss: delta };
|
||||||
|
}).filter(item => item.category !== null) as MoveHistoryItem[];
|
||||||
|
|
||||||
setMistakes(detectedMistakes);
|
setMistakes(detectedMistakes);
|
||||||
|
|
||||||
// 2. LLM Analysis
|
// 2. LLM Analysis
|
||||||
if (apiKey) {
|
if (apiKey) {
|
||||||
const model = getGenAIModel(apiKey, "gemini-2.5-flash");
|
const model = getGenAIModel(apiKey, "gemini-2.5-flash");
|
||||||
|
|
||||||
|
const blunders = detectedMistakes.filter(m => m.category === 'blunder');
|
||||||
|
const mistakes = detectedMistakes.filter(m => m.category === 'mistake');
|
||||||
|
const inaccuracies = detectedMistakes.filter(m => m.category === 'inaccuracy');
|
||||||
|
|
||||||
const mistakesText = detectedMistakes.map(m =>
|
const mistakesText = detectedMistakes.map(m =>
|
||||||
`Move ${m.moveNumber}: Played ${m.move} (Eval dropped from ${m.evalBefore} to ${m.evalAfter}). Best move was likely ${m.bestMove}.`
|
`Move ${m.moveNumber}: ${m.move} (${m.category?.toUpperCase()}: -${m.cpLoss}cp, eval ${m.evalBefore} → ${m.evalAfter}). Best: ${m.bestMove}`
|
||||||
).join("\n");
|
).join("\n");
|
||||||
|
|
||||||
const prompt = `
|
const prompt = `
|
||||||
You are a Chess Coach. The game is over.
|
You are a Chess Coach. The game is over.
|
||||||
Result: ${result} (${winner === "Draw" ? "Draw" : winner + " Won"}).
|
Result: ${result} (${winner === "Draw" ? "Draw" : winner + " Won"}).
|
||||||
|
|
||||||
Here are the player's (White) key mistakes (Blunders):
|
Player's Performance Summary:
|
||||||
${mistakesText || "No major blunders detected."}
|
- Blunders (300+ cp loss): ${blunders.length}
|
||||||
|
- Mistakes (100-300 cp loss): ${mistakes.length}
|
||||||
|
- Inaccuracies (50-100 cp loss): ${inaccuracies.length}
|
||||||
|
|
||||||
|
${mistakesText ? `Detailed Mistakes:\n${mistakesText}` : "No significant mistakes detected - excellent play!"}
|
||||||
|
|
||||||
INSTRUCTIONS:
|
INSTRUCTIONS:
|
||||||
1. Briefly comment on the game result.
|
1. Briefly comment on the game result.
|
||||||
2. If there were mistakes, explain WHY they were bad and what the player should have looked for (tactics, hanging pieces, etc.).
|
2. If there were mistakes, explain WHY the worst ones were bad and what the player should have looked for (tactics, hanging pieces, positional errors, etc.).
|
||||||
3. If no mistakes, praise the solid play.
|
3. If no mistakes, praise the solid play and suggest areas for improvement.
|
||||||
4. Be encouraging but educational.
|
4. Be encouraging but educational. Focus on learning.
|
||||||
5. Respond in ${language.toUpperCase()}.
|
5. Respond in ${language.toUpperCase()}.
|
||||||
|
|
||||||
OUTPUT FORMAT:
|
OUTPUT FORMAT:
|
||||||
Plain text paragraph.
|
Plain text paragraph (2-3 sentences).
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const resultGen = await model.generateContent(prompt);
|
const resultGen = await model.generateContent(prompt);
|
||||||
@@ -112,18 +129,35 @@ Plain text paragraph.
|
|||||||
Key Moments / Mistakes
|
Key Moments / Mistakes
|
||||||
</h3>
|
</h3>
|
||||||
<div className="max-h-40 overflow-y-auto space-y-2 pr-2">
|
<div className="max-h-40 overflow-y-auto space-y-2 pr-2">
|
||||||
{mistakes.map((m, idx) => (
|
{mistakes.map((m, idx) => {
|
||||||
<div key={idx} className="p-3 bg-orange-50 dark:bg-orange-900/10 border border-orange-100 dark:border-orange-900/30 rounded-lg text-sm">
|
const categoryColors = {
|
||||||
<span className="font-bold text-gray-900 dark:text-white">Move {m.moveNumber}: {m.move}</span>
|
inaccuracy: 'bg-yellow-50 dark:bg-yellow-900/10 border-yellow-200 dark:border-yellow-900/30 text-yellow-700 dark:text-yellow-400',
|
||||||
<span className="mx-2 text-gray-400">|</span>
|
mistake: 'bg-orange-50 dark:bg-orange-900/10 border-orange-200 dark:border-orange-900/30 text-orange-700 dark:text-orange-400',
|
||||||
<span className="text-red-600 dark:text-red-400">Eval: {m.evalBefore} ➝ {m.evalAfter}</span>
|
blunder: 'bg-red-50 dark:bg-red-900/10 border-red-200 dark:border-red-900/30 text-red-700 dark:text-red-400'
|
||||||
{m.bestMove && (
|
};
|
||||||
<div className="text-gray-500 dark:text-gray-400 mt-1">
|
const categoryColor = categoryColors[m.category || 'inaccuracy'];
|
||||||
Best was likely: <span className="font-mono">{m.bestMove}</span>
|
|
||||||
|
return (
|
||||||
|
<div key={idx} className={`p-3 border rounded-lg text-sm ${categoryColor}`}>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className="font-bold text-gray-900 dark:text-white">Move {m.moveNumber}: {m.move}</span>
|
||||||
|
<span className="px-2 py-0.5 rounded text-xs font-semibold uppercase bg-white/50 dark:bg-black/20">
|
||||||
|
{m.category}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className="mt-1 text-xs">
|
||||||
</div>
|
<span className="font-medium">Loss: -{m.cpLoss}cp</span>
|
||||||
))}
|
<span className="mx-2 text-gray-400">|</span>
|
||||||
|
<span>Eval: {m.evalBefore} → {m.evalAfter}</span>
|
||||||
|
</div>
|
||||||
|
{m.bestMove && (
|
||||||
|
<div className="text-gray-600 dark:text-gray-400 mt-1 text-xs">
|
||||||
|
Best: <span className="font-mono">{m.bestMove}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user