Spaces:
Sleeping
Sleeping
File size: 4,677 Bytes
100a6dd d086f83 100a6dd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
import axios from 'axios';
// In development, the API URL is '/api', but in production, it's just '/'
const API_URL = '';
// Define types based on the backend API
export interface NewGameOptions {
player_color: 'white' | 'black';
difficulty: 'beginner' | 'easy' | 'medium' | 'hard' | 'expert' | 'master';
time_limit: number;
use_opening_book: boolean;
enable_analysis: boolean;
}
export interface MoveRequest {
move: string;
}
// Promotion-related types
export type PromotionPiece = 'queen' | 'rook' | 'bishop' | 'knight';
export interface PromotionMove {
from: string; // e.g., "e7"
to: string; // e.g., "e8"
piece?: PromotionPiece; // promotion piece selection
required: boolean; // true if promotion piece selection is required
}
export interface PromotionRequirement {
from: string;
to: string;
available_pieces: PromotionPiece[];
}
export interface PromotionRequest {
move: string;
promotion_piece: PromotionPiece;
}
export interface GameState {
fen: string;
turn: 'white' | 'black';
game_state: string;
legal_moves: string[];
in_check: boolean;
move_count: number;
}
export interface GameResponse {
status: string;
message?: string;
board_state: GameState;
player_color?: 'white' | 'black';
player_move?: string;
ai_move?: string;
analysis?: any;
result?: string;
winner?: string;
reason?: string;
// Promotion support
promotion_required?: PromotionRequirement;
}
export interface HintResponse {
status: string;
hint: string;
explanation: string;
board_state: GameState;
}
// API functions
export const startNewGame = async (options: NewGameOptions): Promise<GameResponse> => {
const response = await axios.post(`${API_URL}/game/new`, options);
return response.data;
};
export const makeMove = async (move: string, promotionPiece?: PromotionPiece): Promise<GameResponse> => {
try {
// If promotion piece is specified, append it to the move in UCI notation
const moveWithPromotion = promotionPiece ? createPromotionMove(move.substring(0, 2), move.substring(2, 4), promotionPiece) : move;
const response = await axios.post(`${API_URL}/game/move`, { move: moveWithPromotion });
return response.data;
} catch (error) {
// Handle promotion-required errors specifically
if (axios.isAxiosError(error) && error.response?.status === 400) {
const errorData = error.response.data;
// Check if this is a promotion-required error
if (errorData.status === 'promotion_required' || errorData.promotion_details) {
return {
status: 'promotion_required',
message: errorData.message || 'Pawn promotion requires piece selection',
board_state: errorData.board_state || {} as GameState,
promotion_required: {
from: errorData.promotion_details?.from || move.substring(0, 2),
to: errorData.promotion_details?.to || move.substring(2, 4),
available_pieces: errorData.promotion_details?.available_pieces || ['queen', 'rook', 'bishop', 'knight']
}
};
}
}
// Re-throw other errors
throw error;
}
};
export const getGameState = async (): Promise<GameResponse> => {
const response = await axios.get(`${API_URL}/game/state`);
return response.data;
};
export const getHint = async (): Promise<HintResponse> => {
const response = await axios.post(`${API_URL}/game/hint`);
return response.data;
};
export const undoMove = async (count: number = 2): Promise<GameResponse> => {
const response = await axios.post(`${API_URL}/game/undo`, { count });
return response.data;
};
export const resignGame = async (): Promise<GameResponse> => {
const response = await axios.post(`${API_URL}/game/resign`);
return response.data;
};
// Utility functions for promotion handling
export const isPromotionRequired = (response: GameResponse): boolean => {
return response.status === 'promotion_required' && !!response.promotion_required;
};
export const getPromotionRequirement = (response: GameResponse): PromotionRequirement | null => {
return response.promotion_required || null;
};
export const createPromotionMove = (from: string, to: string, piece: PromotionPiece): string => {
// Map promotion pieces to UCI notation
const pieceMap: Record<PromotionPiece, string> = {
'queen': 'q',
'rook': 'r',
'bishop': 'b',
'knight': 'n' // Knight uses 'n' in UCI notation, not 'k'
};
return `${from}${to}${pieceMap[piece]}`;
}; |