Skip to main content
Glama
positionPrompter.js17.7 kB
import { TacticalBoard } from "../themes/tacticalBoard.js"; import { Chess } from "chess.js"; import { TempoCalculator } from "../themes/temoCalculator.js"; export class PositionPrompter { state; sections; tactical; tempoCalculator; constructor(state) { this.state = state; this.tactical = new TacticalBoard(state.fen); this.tempoCalculator = new TempoCalculator(this.state, this.tactical, new Chess(state.fen).turn()); this.sections = []; } generatePrompt() { if (!this.state) { return "<board_state>Invalid FEN provided</board_state>"; } this.sections = []; this.sections.push("<detailed_board_analysis>"); this.addGameStatus(); this.addMaterialAnalysis(); this.addPiecePositions(); this.addKingSafetyAnalysis(); this.addCastlingRights(); this.addPieceMobility(); this.addSpaceControl(); this.addSquareColorControl(); this.addPawnStructureAnalysis(); this.addTacticalAnalysis(); this.addTempoAnalysis(); this.addAttackDefenseDetails(); this.sections.push("</detailed_board_analysis>"); return this.sections.join("\n"); } addGameStatus() { this.sections.push("<game_status>"); this.sections.push(`FEN: ${this.state.fen}`); this.sections.push(`Move Number: ${this.state.moveNumber}`); this.sections.push(`Active Player: ${this.state.sidetomove === "white" ? "White to move" : "Black to move"}`); this.sections.push(`Game Phase: ${this.state.gamePhase.toUpperCase()}`); if (this.state.isCheckmate) { this.sections.push("Game Status: CHECKMATE - Game is over"); } else if (this.state.isStalemate) { this.sections.push("Game Status: STALEMATE - Game is drawn"); } else if (this.state.isGameOver) { this.sections.push("Game Status: GAME OVER - No legal moves available"); } else { this.sections.push("Game Status: ACTIVE GAME - Normal play continues"); } this.sections.push(`Total Legal Moves Available: ${this.state.legalMoves.length}`); if (this.state.legalMoves.length > 0 && this.state.legalMoves.length <= 15) { this.sections.push(`All Legal Moves: ${this.state.legalMoves.join(", ")}`); } else if (this.state.legalMoves.length > 15) { this.sections.push(`Sample Legal Moves: ${this.state.legalMoves .slice(0, 15) .join(", ")}... (${this.state.legalMoves.length - 15} more)`); } this.sections.push("</game_status>"); } addTempoAnalysis() { const tempoDetails = this.tempoCalculator.getTempoExplanation(); for (const detail of tempoDetails) { this.sections.push(detail); } } addMaterialAnalysis() { this.sections.push("\n<material_analysis>"); const materialDiff = this.state.white.materialScore.materialvalue - this.state.black.materialScore.materialvalue; this.addPlayerMaterial("WHITE", this.state.white.materialScore); this.addPlayerMaterial("BLACK", this.state.black.materialScore); this.sections.push("\nMATERIAL BALANCE:"); if (materialDiff > 0) { this.sections.push(` White has a material advantage of +${materialDiff} points`); this.addMaterialAdvantageDescription(materialDiff); } else if (materialDiff < 0) { const absMatDiff = Math.abs(materialDiff); this.sections.push(` Black has a material advantage of +${absMatDiff} points`); this.addMaterialAdvantageDescription(absMatDiff); } else { this.sections.push(` Material is EQUAL - both sides have ${this.state.white.materialScore.materialvalue} points`); } this.sections.push("</material_analysis>"); } addPlayerMaterial(color, materialScore) { this.sections.push(`${color} PIECES:`); this.sections.push(` Total Material Value: ${materialScore.materialvalue} points`); this.sections.push(` Queens: ${materialScore.piececount.queens} (${materialScore.piececount.queens * 9} points)`); this.sections.push(` Rooks: ${materialScore.piececount.rooks} (${materialScore.piececount.rooks * 5} points)`); this.sections.push(` Bishops: ${materialScore.piececount.bishops} (${materialScore.piececount.bishops * 3} points)`); this.sections.push(` Knights: ${materialScore.piececount.knights} (${materialScore.piececount.knights * 3} points)`); this.sections.push(` Pawns: ${materialScore.piececount.pawns} (${materialScore.piececount.pawns * 1} points)`); this.sections.push(` Bishop Pair Bonus: ${materialScore.bishoppair ? "YES (+0.5 points strategic value)" : "NO"}`); if (color === "WHITE") this.sections.push(""); // Add spacing between white and black } addMaterialAdvantageDescription(advantage) { if (advantage >= 9) { this.sections.push(` This is equivalent to approximately a QUEEN advantage`); } else if (advantage >= 5) { this.sections.push(` This is equivalent to approximately a ROOK advantage`); } else if (advantage >= 3) { this.sections.push(` This is equivalent to approximately a MINOR PIECE advantage`); } else if (advantage >= 1) { this.sections.push(` This is equivalent to approximately a PAWN advantage`); } } addPiecePositions() { this.sections.push("\n<piece_positions>"); this.addPlayerPiecePositions("WHITE", this.state.white.pieceplacementScore); this.addPlayerPiecePositions("BLACK", this.state.black.pieceplacementScore); this.sections.push("</piece_positions>"); } addPlayerPiecePositions(color, placement) { this.sections.push(`${color} PIECE LOCATIONS:`); this.sections.push(` King: ${placement.kingplacement[0] || "MISSING"}`); this.sections.push(` Queens: ${placement.queenplacement.length > 0 ? placement.queenplacement.join(", ") : "None"}`); this.sections.push(` Rooks: ${placement.rookplacement.length > 0 ? placement.rookplacement.join(", ") : "None"}`); this.sections.push(` Bishops: ${placement.bishopplacement.length > 0 ? placement.bishopplacement.join(", ") : "None"}`); this.sections.push(` Knights: ${placement.knightplacement.length > 0 ? placement.knightplacement.join(", ") : "None"}`); this.sections.push(` Pawns: ${placement.pawnplacement.length > 0 ? placement.pawnplacement.join(", ") : "None"}`); if (color === "WHITE") this.sections.push(""); // Add spacing } addKingSafetyAnalysis() { this.sections.push("\n<king_safety_analysis>"); this.addPlayerKingSafety("WHITE", this.state.white.kingSafetyScore); this.addPlayerKingSafety("BLACK", this.state.black.kingSafetyScore); this.sections.push("</king_safety_analysis>"); } addPlayerKingSafety(color, kingSafety) { this.sections.push(`${color} KING SAFETY:`); this.sections.push(` King Position: ${kingSafety.kingsquare}`); this.sections.push(` Enemy Attackers on King: ${kingSafety.attackerscount} pieces attacking the king`); this.sections.push(` Friendly Defenders of King: ${kingSafety.defenderscount} (higher = better) pieces defending the king`); this.sections.push(` Pawn Shield Strength: ${kingSafety.pawnshield} (higher is better protection)`); if (color === "WHITE") { this.sections.push(` King Safety Advantage: ${kingSafety.kingsafetysadvantage} (higher is safer, negative means danger)`); } else { this.sections.push(` King Safety Advantage: ${kingSafety.kingsafetysadvantage} (higher is danger, negative means safer)`); } this.sections.push(` Castling Status: ${kingSafety.hascastled ? "King HAS castled (safer)" : "King has NOT castled"}`); this.sections.push(` Castling Rights: ${kingSafety.cancastle ? "Can still castle" : "Cannot castle anymore"}`); if (color === "WHITE") this.sections.push(""); // Add spacing } addCastlingRights() { this.sections.push("\n<castling_rights>"); this.sections.push("WHITE CASTLING:"); this.sections.push(` Kingside (O-O): ${this.state.white.castlingScore.kingside ? "AVAILABLE" : "NOT AVAILABLE"}`); this.sections.push(` Queenside (O-O-O): ${this.state.white.castlingScore.queenside ? "AVAILABLE" : "NOT AVAILABLE"}`); this.sections.push("\nBLACK CASTLING:"); this.sections.push(` Kingside (O-O): ${this.state.black.castlingScore.kingside ? "AVAILABLE" : "NOT AVAILABLE"}`); this.sections.push(` Queenside (O-O-O): ${this.state.black.castlingScore.queenside ? "AVAILABLE" : "NOT AVAILABLE"}`); this.sections.push("</castling_rights>"); } addPieceMobility() { this.sections.push("\n<piece_mobility>"); this.addPlayerMobility("WHITE", this.state.white.pieceMobilityScore); this.addPlayerMobility("BLACK", this.state.black.pieceMobilityScore); const mobilityDiff = this.state.white.pieceMobilityScore.totalmobility - this.state.black.pieceMobilityScore.totalmobility; if (mobilityDiff > 5) { this.sections.push(`\nMOBILITY ADVANTAGE: White has ${mobilityDiff} more squares of mobility (significantly more active pieces)`); } else if (mobilityDiff < -5) { this.sections.push(`\nMOBILITY ADVANTAGE: Black has ${Math.abs(mobilityDiff)} more squares of mobility (significantly more active pieces)`); } else if (mobilityDiff !== 0) { this.sections.push(`\nMOBILITY: ${mobilityDiff > 0 ? 'White' : 'Black'} has a slight mobility advantage (${Math.abs(mobilityDiff)} squares)`); } else { this.sections.push(`\nMOBILITY: Both sides have equal piece mobility (${this.state.white.pieceMobilityScore.totalmobility} squares each)`); } this.sections.push("</piece_mobility>"); } addPlayerMobility(color, mobility) { this.sections.push(`${color} PIECE MOBILITY (number of squares each piece type can move to):`); this.sections.push(` Queen Mobility: ${mobility.queenmobility} squares`); this.sections.push(` Rook Mobility: ${mobility.rookmobility} squares`); this.sections.push(` Bishop Mobility: ${mobility.bishopmobility} squares`); this.sections.push(` Knight Mobility: ${mobility.knightmobility} squares`); this.sections.push(` Total Mobility Score: ${mobility.totalmobility} squares (higher = more active pieces)`); if (color === "WHITE") this.sections.push(""); } addSpaceControl() { this.sections.push("\n<space_control>"); this.addPlayerSpaceControl("WHITE", this.state.white.spaceScore); this.addPlayerSpaceControl("BLACK", this.state.black.spaceScore); const centerControlDiff = this.state.white.spaceScore.centerspacecontrolscore - this.state.black.spaceScore.centerspacecontrolscore; const totalSpaceDiff = this.state.white.spaceScore.totalspacecontrolscore - this.state.black.spaceScore.totalspacecontrolscore; if (centerControlDiff > 3) { this.sections.push(`\nCENTER CONTROL: White dominates the center (+${centerControlDiff} advantage)`); } else if (centerControlDiff < -3) { this.sections.push(`\nCENTER CONTROL: Black dominates the center (+${Math.abs(centerControlDiff)} advantage)`); } else if (centerControlDiff !== 0) { this.sections.push(`\nCENTER CONTROL: ${centerControlDiff > 0 ? 'White' : 'Black'} has slight center advantage (+${Math.abs(centerControlDiff)})`); } else { this.sections.push(`\nCENTER CONTROL: Both sides have equal center control`); } if (totalSpaceDiff > 5) { this.sections.push(`OVERALL SPACE: White has significantly more space (+${totalSpaceDiff} total advantage)`); } else if (totalSpaceDiff < -5) { this.sections.push(`OVERALL SPACE: Black has significantly more space (+${Math.abs(totalSpaceDiff)} total advantage)`); } else if (totalSpaceDiff !== 0) { this.sections.push(`OVERALL SPACE: ${totalSpaceDiff > 0 ? 'White' : 'Black'} has slight space advantage (+${Math.abs(totalSpaceDiff)})`); } else { this.sections.push(`OVERALL SPACE: Both sides control equal space`); } this.sections.push("</space_control>"); } addPlayerSpaceControl(color, spaceScore) { this.sections.push(`${color} SPACE CONTROL:`); this.sections.push(` Center Control Score: ${spaceScore.centerspacecontrolscore} (attacks on central squares d4,d5,e4,e5,c4,c5,f4,f5)`); this.sections.push(` Flank Control Score: ${spaceScore.flankspacecontrolscore} (attacks on flank squares a4,a5,b4,b5,g4,g5,h4,h5)`); this.sections.push(` Total Space Control: ${spaceScore.totalspacecontrolscore} (higher is better)`); if (color === "WHITE") this.sections.push(""); // Add spacing } addSquareColorControl() { this.sections.push("\n<square_color_control>"); this.addPlayerSquareControl("WHITE", this.state.white.squareControlScore); this.addPlayerSquareControl("BLACK", this.state.black.squareControlScore); this.sections.push("</square_color_control>"); } addPlayerSquareControl(color, squareControl) { this.sections.push(`${color} SQUARE COLOR INFLUENCE:`); this.sections.push(` Light Squares Controlled: ${squareControl.lightSquareControl} pieces on light squares`); this.sections.push(` Dark Squares Controlled: ${squareControl.darkSqaureControl} pieces on dark squares`); this.sections.push(` Light Square Pieces: ${squareControl.lightSquares.join(", ") || "None"}`); this.sections.push(` Dark Square Pieces: ${squareControl.darkSquares.join(", ") || "None"}`); if (color === "WHITE") this.sections.push(""); // Add spacing } addPawnStructureAnalysis() { this.sections.push("\n<pawn_structure_analysis>"); this.addPlayerPawnStructure("WHITE", this.state.white.positionalScore); this.addPlayerPawnStructure("BLACK", this.state.black.positionalScore); this.sections.push("</pawn_structure_analysis>"); } addPlayerPawnStructure(color, positional) { this.sections.push(`${color} PAWN STRUCTURE:`); this.sections.push(` Doubled Pawns: ${positional.doublepawncount} (weakness - pawns on same file)`); this.sections.push(` Isolated Pawns: ${positional.isolatedpawncount} (weakness - no friendly pawns on adjacent files)`); this.sections.push(` Backward Pawns: ${positional.backwardpawncount} (weakness - pawns that cannot advance safely)`); this.sections.push(` Passed Pawns: ${positional.passedpawncount} (strength - no enemy pawns blocking path to promotion)`); if (color === "WHITE") { this.sections.push(` Pawn Structure Advantage Score: ${positional.positionalAdvatange} (higher is better - negative is worse pawn structure)`); } else { this.sections.push(` Pawn Structure Advantage Score: ${positional.positionalAdvatange} (negative is better - positive is worse pawn strucutre)`); } if (color === "WHITE") this.sections.push(""); // Add spacing } addTacticalAnalysis() { this.sections.push("\n<tactical_analysis>"); // Get the full tactical summary const tacticalSummary = this.tactical.toString(); // Split into lines and add each line to sections const lines = tacticalSummary.split('\n'); for (const line of lines) { this.sections.push(line); } this.sections.push("</tactical_analysis>"); } addAttackDefenseDetails() { this.sections.push("\n<attack_defense_details>"); this.addPlayerAttackDefense("WHITE", this.state.whitepieceattackerdefenderinfo); this.addPlayerAttackDefense("BLACK", this.state.blackpieceattackerdefenderinfo); this.sections.push("</attack_defense_details>"); } addPlayerAttackDefense(color, attackDefenseInfo) { this.sections.push(`${color} PIECE ATTACK/DEFENSE STATUS:`); this.sections.push(` Pawns: ${attackDefenseInfo.pawnInfo.attackerscount} attackers, ${attackDefenseInfo.pawnInfo.defenderscount} defenders`); this.sections.push(` Knights: ${attackDefenseInfo.knightInfo.attackerscount} attackers, ${attackDefenseInfo.knightInfo.defenderscount} defenders`); this.sections.push(` Bishops: ${attackDefenseInfo.bishopInfo.attackerscount} attackers, ${attackDefenseInfo.bishopInfo.defenderscount} defenders`); this.sections.push(` Rooks: ${attackDefenseInfo.rookInfo.attackerscount} attackers, ${attackDefenseInfo.rookInfo.defenderscount} defenders`); this.sections.push(` Queens: ${attackDefenseInfo.queenInfo.attackerscount} attackers, ${attackDefenseInfo.queenInfo.defenderscount} defenders`); if (color === "WHITE") this.sections.push(""); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jalpp/chessagine-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server