|
|
|
|
@ -14,11 +14,6 @@
|
|
|
|
|
//#define START_FEN "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
|
|
|
|
|
#define START_FEN "rnbqkbnr/PPppppPP/8/8/8/8/ppPPPPpp/RNBQKBNR w KQkq - 0 1"
|
|
|
|
|
|
|
|
|
|
#define drawPiece(file, rank, piece) do { \
|
|
|
|
|
const RsvgRectangle rect = {xOffset + (file) * fieldSize, yOffset + (rank) * fieldSize, fieldSize, fieldSize};\
|
|
|
|
|
rsvg_handle_render_document(piecesSvg[pieceToSvgI(piece)], cr, &rect, NULL); \
|
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
struct drawData_t {
|
|
|
|
|
RsvgHandle **piecesSvg;
|
|
|
|
|
struct gameState_t *gameState;
|
|
|
|
|
@ -33,12 +28,19 @@ struct drawData_t {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const uint_least8_t PROMOTION_PIECES[] = {QUEEN, KNIGHT, BISHOP, ROOK};
|
|
|
|
|
static bool turn = WHITE;
|
|
|
|
|
|
|
|
|
|
static uint_least8_t pieceToSvgI(struct piece_t piece) {
|
|
|
|
|
return piece.color == WHITE ? piece.type | 8 : piece.type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void drawPiece(struct drawData_t *ctx, cairo_t *cr, uint_least8_t field, struct piece_t piece) {
|
|
|
|
|
const uint_least8_t file = field % BOARD_SIZE;
|
|
|
|
|
const uint_least8_t rank = field / BOARD_SIZE;
|
|
|
|
|
const RsvgRectangle rect = {ctx->xOffset + file * ctx->fieldSize, ctx->yOffset + rank * ctx->fieldSize, ctx->fieldSize, ctx->fieldSize};\
|
|
|
|
|
rsvg_handle_render_document(ctx->piecesSvg[pieceToSvgI(piece)], cr, &rect, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void selectCircle(cairo_t *cr, const struct drawData_t *drawData, uint_least8_t field, double radius) {
|
|
|
|
|
uint_least8_t file = field % BOARD_SIZE;
|
|
|
|
|
uint_least8_t rank = field / BOARD_SIZE;
|
|
|
|
|
@ -50,17 +52,19 @@ static void selectCircle(cairo_t *cr, const struct drawData_t *drawData, uint_le
|
|
|
|
|
|
|
|
|
|
static struct gameState_t userMove(struct gameState_t gameState, struct move_t move) {
|
|
|
|
|
gameState = makeMove(gameState, move);
|
|
|
|
|
#ifdef NO_COMPUTER
|
|
|
|
|
turn = !turn;
|
|
|
|
|
#else
|
|
|
|
|
#ifndef NO_COMPUTER
|
|
|
|
|
move = bestMove(gameState);
|
|
|
|
|
gameState = makeMove(gameState, move);
|
|
|
|
|
#endif
|
|
|
|
|
return gameState;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static uint_least8_t promotionUiPos(uint_least8_t dst) {
|
|
|
|
|
return dst >= 1 ? dst - 1 : 0;
|
|
|
|
|
static uint_least8_t promotionUiPos(uint_least8_t dst, bool color) {
|
|
|
|
|
const uint_least8_t rankI = getBaseRankI(!color);
|
|
|
|
|
uint_least8_t uiPos = dst >= rankI + 1 ? dst - 1 : dst;
|
|
|
|
|
const uint_least8_t overflowI = rankI + BOARD_SIZE;
|
|
|
|
|
if(uiPos + LENGTH(PROMOTION_PIECES) > overflowI) uiPos = overflowI - LENGTH(PROMOTION_PIECES);
|
|
|
|
|
return uiPos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer data) {
|
|
|
|
|
@ -68,7 +72,8 @@ static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height,
|
|
|
|
|
const double xOffset = (width - fieldSize * BOARD_SIZE) / 2;
|
|
|
|
|
const double yOffset = (height - fieldSize * BOARD_SIZE) / 2;
|
|
|
|
|
struct drawData_t *drawData = (struct drawData_t*)data;
|
|
|
|
|
const uint_least64_t *board = drawData->gameState->board;
|
|
|
|
|
const struct gameState_t *gameState = drawData->gameState;
|
|
|
|
|
const uint_least64_t *board = gameState->board;
|
|
|
|
|
RsvgHandle **piecesSvg = drawData->piecesSvg;
|
|
|
|
|
drawData->xOffset = xOffset;
|
|
|
|
|
drawData->yOffset = yOffset;
|
|
|
|
|
@ -82,7 +87,7 @@ static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height,
|
|
|
|
|
cairo_fill(cr);
|
|
|
|
|
if(bitboardGetAllPieces(board, field)) {
|
|
|
|
|
const struct piece_t piece = pieceAtField(board, rank * BOARD_SIZE + file);
|
|
|
|
|
drawPiece(file, rank, piece);
|
|
|
|
|
drawPiece(drawData, cr, field, piece);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -97,14 +102,13 @@ static void draw_event(GtkDrawingArea *area, cairo_t *cr, int width, int height,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(drawData->selectDst != NOT_SELECTED) {
|
|
|
|
|
uint_least8_t uiPos = promotionUiPos(drawData->selectDst);
|
|
|
|
|
if(uiPos + 3 >= BOARD_SIZE) uiPos = BOARD_SIZE - LENGTH(PROMOTION_PIECES);
|
|
|
|
|
uint_least8_t uiPos = promotionUiPos(drawData->selectDst, gameState->color);
|
|
|
|
|
cairo_set_source_rgb(cr, 0.5, 0.5, 0.5);
|
|
|
|
|
cairo_rectangle(cr, xOffset + uiPos * fieldSize, yOffset, 4 * fieldSize, fieldSize);
|
|
|
|
|
cairo_fill(cr);
|
|
|
|
|
for(uint_least8_t i = 0; i < LENGTH(PROMOTION_PIECES); ++i) {
|
|
|
|
|
const struct piece_t piece = {PROMOTION_PIECES[i], true};
|
|
|
|
|
drawPiece(uiPos + i, 0, piece);
|
|
|
|
|
const struct piece_t piece = {PROMOTION_PIECES[i], gameState->color};
|
|
|
|
|
drawPiece(drawData, cr, uiPos + i, piece);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -121,9 +125,9 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y,
|
|
|
|
|
const uint_least8_t file = adjustedX / fieldSize;
|
|
|
|
|
const uint_least8_t rank = adjustedY / fieldSize;
|
|
|
|
|
const uint_least8_t field = file + rank * BOARD_SIZE;
|
|
|
|
|
const bool promotion_field = rank == (gameState->color == WHITE ? 0 : BOARD_SIZE - 1);
|
|
|
|
|
const bool onPromotionField = rank == getBaseRank(!gameState->color);
|
|
|
|
|
if(drawData->selectDst == NOT_SELECTED) {
|
|
|
|
|
const struct piece_t allPiece = {ALL_PIECES, turn};
|
|
|
|
|
const struct piece_t allPiece = {ALL_PIECES, gameState->color};
|
|
|
|
|
if(bitboardGet(board, allPiece, field)) {
|
|
|
|
|
// deactivated piece by clicking on it again
|
|
|
|
|
if(field == drawData->clickedPiece) {
|
|
|
|
|
@ -146,7 +150,7 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y,
|
|
|
|
|
}
|
|
|
|
|
if(isValidDst) {
|
|
|
|
|
const struct piece_t piece = pieceAtField(board, drawData->clickedPiece);
|
|
|
|
|
if(piece.type == PAWN && promotion_field) { // promotion
|
|
|
|
|
if(piece.type == PAWN && onPromotionField) { // promotion
|
|
|
|
|
drawData->selectDst = field;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
@ -166,11 +170,11 @@ static void on_click(GtkGestureClick *gesture, int n_press, double x, double y,
|
|
|
|
|
drawData->movesLength = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(promotion_field) {
|
|
|
|
|
const uint_least8_t uiPos = promotionUiPos(drawData->selectDst);
|
|
|
|
|
const uint_least8_t i = file - uiPos;
|
|
|
|
|
else if(onPromotionField) {
|
|
|
|
|
const uint_least8_t uiPos = promotionUiPos(drawData->selectDst, gameState->color);
|
|
|
|
|
const uint_least8_t i = field - uiPos;
|
|
|
|
|
if(i >= LENGTH(PROMOTION_PIECES)) return;
|
|
|
|
|
const uint_least8_t dstPiece = PROMOTION_PIECES[file - uiPos];
|
|
|
|
|
const uint_least8_t dstPiece = PROMOTION_PIECES[i];
|
|
|
|
|
const uint_least8_t capturedPiece = pieceAtField(board, drawData->selectDst).type;
|
|
|
|
|
const struct move_t move = {drawData->clickedPiece, drawData->selectDst, 0, PAWN, dstPiece, capturedPiece};
|
|
|
|
|
*gameState = userMove(*gameState, move);
|
|
|
|
|
|