Can someone compile a chess AI .g4m for fx-CG100?
Posté le 08/03/2026 04:37
Hi! I have a chess add-in written in C using Gint but I can't get the toolchain working on Windows WSL. Could someone please compile it into a .g4m for fx-CG100?
Here is the main.c source code:
/*
* chess.g4m – Chess AI for CASIO fx-CG100 / Graph 90+E / fx-CG50
*
* Built with fxSDK + Gint (https://gitea.planet-casio.com/Lephenixnoir/gint)
* Compiler : sh-elf-gcc (SH4A-nofpu, fxSDK toolchain)
*
* Features
* · Full legal chess (castling, en-passant, promotion, 50-move draw)
* · AI: minimax + alpha-beta pruning, 3 difficulty levels
* · Per-side clock
* · Captured-material score
* · Last-move & check highlight
* · Move hints (dots / red border for captures)
*/
#include <gint/gint.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/timer.h>
#include <gint/rtc.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
/* ── Screen dimensions (fx-CG100 QVGA colour screen) ─────────────────────── */
#define SW 384
#define SH 216
/* ── Board pixel layout ───────────────────────────────────────────────────── */
#define BX 14 /* board left edge */
#define BY 12 /* board top edge */
#define CS 24 /* cell size (px) */
#define PANEL_X (BX + CS*8 + 6) /* right info panel */
/* ── Piece constants ─────────────────────────────────────────────────────── */
#define EMPTY 0
#define PAWN 1
#define KNIGHT 2
#define BISHOP 3
#define ROOK 4
#define QUEEN 5
#define KING 6
/* positive = white, negative = black */
#define P_WHITE(p) ((p) > 0)
#define P_BLACK(p) ((p) < 0)
#define P_TYPE(p) abs(p)
#define P_SIGN(w) ((w) ? 1 : -1)
/* ── Colours (RGB565) ────────────────────────────────────────────────────── */
#define C_BG C_RGB(2, 2, 4)
#define C_PANEL C_RGB(3, 3, 7)
#define C_LIGHT_SQ C_RGB(30, 27, 22)
#define C_DARK_SQ C_RGB(22, 17, 12)
#define C_CURSOR C_RGB(6, 28, 8)
#define C_SELECTED C_RGB(4, 26, 4)
#define C_HINT C_RGB(8, 16, 28)
#define C_CAPTURE C_RGB(28, 8, 8)
#define C_CHECK C_RGB(31, 4, 4)
#define C_LASTMOVE C_RGB(26, 22, 6)
#define C_WHITE_P C_RGB(31, 31, 30)
#define C_BLACK_P C_RGB(4, 4, 5)
#define C_TEXT C_RGB(27, 27, 27)
#define C_DIM C_RGB(14, 14, 18)
#define C_GOLD C_RGB(31, 25, 4)
#define C_GREEN C_RGB(8, 28, 12)
#define C_RED C_RGB(28, 6, 6)
#define C_TITLE C_RGB(20, 14, 31)
#define C_EASY C_RGB(8, 26, 14)
#define C_MED C_RGB(30, 22, 4)
#define C_HARD C_RGB(28, 8, 8)
#define C_OUTLINE C_RGB(10, 10, 12)
/* ── Piece values (centipawns) ───────────────────────────────────────────── */
static const int PIECE_VAL[7] = {0, 100, 320, 330, 500, 900, 20000};
/* ── Piece-square tables (white perspective, flipped for black) ─────────── */
static const int PST_PAWN[8][8] = {
{ 0, 0, 0, 0, 0, 0, 0, 0},
{50, 50, 50, 50, 50, 50, 50, 50},
{10, 10, 20, 30, 30, 20, 10, 10},
{ 5, 5, 10, 25, 25, 10, 5, 5},
{ 0, 0, 0, 20, 20, 0, 0, 0},
{ 5, -5,-10, 0, 0,-10, -5, 5},
{ 5, 10, 10,-20,-20, 10, 10, 5},
{ 0, 0, 0, 0, 0, 0, 0, 0},
};
static const int PST_KNIGHT[8][8] = {
{-50,-40,-30,-30,-30,-30,-40,-50},
{-40,-20, 0, 0, 0, 0,-20,-40},
{-30, 0, 10, 15, 15, 10, 0,-30},
{-30, 5, 15, 20, 20, 15, 5,-30},
{-30, 0, 15, 20, 20, 15, 0,-30},
{-30, 5, 10, 15, 15, 10, 5,-30},
{-40,-20, 0, 5, 5, 0,-20,-40},
{-50,-40,-30,-30,-30,-30,-40,-50},
};
static const int PST_KING[8][8] = {
{-30,-40,-40,-50,-50,-40,-40,-30},
{-30,-40,-40,-50,-50,-40,-40,-30},
{-30,-40,-40,-50,-50,-40,-40,-30},
{-30,-40,-40,-50,-50,-40,-40,-30},
{-20,-30,-30,-40,-40,-30,-30,-20},
{-10,-20,-20,-20,-20,-20,-20,-10},
{ 20, 20, 0, 0, 0, 0, 20, 20},
{ 20, 30, 10, 0, 0, 10, 30, 20},
};
/* ═══════════════════════════════════════════════════════════════════════════
* BOARD / GAME STATE
* ═══════════════════════════════════════════════════════════════════════════ */
typedef struct {
int board[8][8];
int ep_r, ep_c; /* en-passant target square (-1 if none) */
int castle; /* bitmask: bit0=WK bit1=WQ bit2=BK bit3=BQ */
int white_turn;
int half_moves; /* 50-move rule counter */
int full_moves;
} Position;
typedef struct {
int fr, fc, tr, tc;
} Move;
static void pos_init(Position *p) {
memset(p, 0, sizeof(*p));
static const int back[8] = {ROOK,KNIGHT,BISHOP,QUEEN,KING,BISHOP,KNIGHT,ROOK};
for (int c=0;c<8;c++) {
p->board[0][c] = -back[c];
p->board[1][c] = -PAWN;
p->board[6][c] = PAWN;
p->board[7][c] = back[c];
}
p->ep_r = -1; p->ep_c = -1;
p->castle = 0xF; /* all rights */
p->white_turn = 1;
p->full_moves = 1;
}
/* ── Move list ───────────────────────────────────────────────────────────── */
#define MAX_MOVES 256
typedef struct { Move m[MAX_MOVES]; int n; } MoveList;
static inline int inb(int r,int c){ return r>=0&&r<8&&c>=0&&c<8; }
/* ── Check detection ─────────────────────────────────────────────────────── */
static int sq_attacked(const Position *p, int r, int c, int by_white) {
int s = by_white ? 1 : -1;
int b[8][8]; memcpy(b, p->board, sizeof(b));
/* Pawns */
int d = by_white ? 1 : -1;
for (int dc=-1;dc<=1;dc+=2)
if (inb(r+d,c+dc) && b[r+d][c+dc]==s*PAWN) return 1;
/* Knights */
static const int kd[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};
for (int i=0;i<8;i++) {
int tr=r+kd[i][0],tc=c+kd[i][1];
if (inb(tr,tc) && b[tr][tc]==s*KNIGHT) return 1;
}
/* Bishops / Queen diagonals */
static const int dd[4][2]={{-1,-1},{-1,1},{1,-1},{1,1}};
for (int i=0;i<4;i++) {
int tr=r+dd[i][0],tc=c+dd[i][1];
while(inb(tr,tc)){
if(b[tr][tc]!=EMPTY){
if(b[tr][tc]==s*BISHOP||b[tr][tc]==s*QUEEN) return 1;
break;
}
tr+=dd[i][0]; tc+=dd[i][1];
}
}
/* Rooks / Queen straights */
static const int sd[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
for (int i=0;i<4;i++) {
int tr=r+sd[i][0],tc=c+sd[i][1];
while(inb(tr,tc)){
if(b[tr][tc]!=EMPTY){
if(b[tr][tc]==s*ROOK||b[tr][tc]==s*QUEEN) return 1;
break;
}
tr+=sd[i][0]; tc+=sd[i][1];
}
}
/* King */
for (int dr=-1;dr<=1;dr++) for (int dc=-1;dc<=1;dc++) {
if(!dr&&!dc) continue;
int tr=r+dr,tc=c+dc;
if(inb(tr,tc)&&b[tr][tc]==s*KING) return 1;
}
return 0;
}
static void find_king(const Position *p, int white, int *kr, int *kc) {
int t = white ? KING : -KING;
for (int r=0;r<8;r++) for (int c=0;c<8;c++)
if(p->board[r][c]==t){ *kr=r; *kc=c; return; }
*kr=0; *kc=0;
}
static int in_check(const Position *p, int white) {
int kr,kc; find_king(p,white,&kr,&kc);
return sq_attacked(p,kr,kc,!white);
}
/* ── Raw move generation ─────────────────────────────────────────────────── */
static void gen_moves_for(const Position *pos, int r, int c, MoveList *ml) {
int piece = pos->board[r][c];
if(!piece) return;
int white = piece>0, pt = abs(piece);
#define ADD(TR,TC) do{ if(ml->n<MAX_MOVES){ \
ml->m[ml->n].fr=r; ml->m[ml->n].fc=c; \
ml->m[ml->n].tr=(TR); ml->m[ml->n].tc=(TC); ml->n++; } }while(0)
#define STEP(DR,DC) do{ int tr=r+(DR),tc=c+(DC); \
if(inb(tr,tc)){ int t=pos->board[tr][tc]; \
if(!t||(t>0)!=white) ADD(tr,tc); } }while(0)
#define SLIDE(DR,DC) do{ int tr=r+(DR),tc=c+(DC); \
while(inb(tr,tc)){ int t=pos->board[tr][tc]; \
if(!t){ ADD(tr,tc); } \
else{ if((t>0)!=white) ADD(tr,tc); break; } \
tr+=(DR); tc+=(DC); } }while(0)
if(pt==PAWN){
int d=white?-1:1, sr=white?6:1;
/* forward */
if(inb(r+d,c)&&!pos->board[r+d][c]){
ADD(r+d,c);
if(r==sr&&!pos->board[r+2*d][c]) ADD(r+2*d,c);
}
/* captures */
for(int dc=-1;dc<=1;dc+=2){
int tr=r+d,tc=c+dc;
if(!inb(tr,tc)) continue;
int t=pos->board[tr][tc];
if(t&&(t>0)!=white) ADD(tr,tc);
else if(tr==pos->ep_r&&tc==pos->ep_c) ADD(tr,tc);
}
} else if(pt==KNIGHT){
static const int kd[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};
for(int i=0;i<8;i++) STEP(kd[i][0],kd[i][1]);
} else if(pt==BISHOP){
SLIDE(-1,-1); SLIDE(-1,1); SLIDE(1,-1); SLIDE(1,1);
} else if(pt==ROOK){
SLIDE(-1,0); SLIDE(1,0); SLIDE(0,-1); SLIDE(0,1);
} else if(pt==QUEEN){
SLIDE(-1,-1); SLIDE(-1,0); SLIDE(-1,1);
SLIDE( 0,-1); SLIDE( 0,1);
SLIDE( 1,-1); SLIDE( 1,0); SLIDE( 1,1);
} else if(pt==KING){
for(int dr=-1;dr<=1;dr++) for(int dc=-1;dc<=1;dc++)
if(dr||dc) STEP(dr,dc);
/* Castling */
int row=white?7:0;
if(r==row&&c==4){
int km=white?0:2, qm=white?1:3;
/* Kingside */
if((pos->castle>>km)&1 &&
!pos->board[row][5] && !pos->board[row][6] &&
!sq_attacked(pos,row,4,!white) &&
!sq_attacked(pos,row,5,!white))
ADD(row,6);
/* Queenside */
if((pos->castle>>qm)&1 &&
!pos->board[row][3] && !pos->board[row][2] && !pos->board[row][1] &&
!sq_attacked(pos,row,4,!white) &&
!sq_attacked(pos,row,3,!white))
ADD(row,2);
}
}
#undef ADD
#undef STEP
#undef SLIDE
}
/* Apply move, return captured piece type (0 if none) */
static int apply_move(Position *pos, Move mv) {
int fr=mv.fr,fc=mv.fc,tr=mv.tr,tc=mv.tc;
int piece=pos->board[fr][fc];
int white=piece>0, pt=abs(piece);
int captured=abs(pos->board[tr][tc]);
pos->board[tr][tc]=piece;
pos->board[fr][fc]=EMPTY;
/* En passant capture */
if(pt==PAWN && tr==pos->ep_r && tc==pos->ep_c){
int cap_r=tr+(white?1:-1);
captured=PAWN;
pos->board[cap_r][tc]=EMPTY;
}
/* New ep square */
if(pt==PAWN && abs(tr-fr)==2){
pos->ep_r=(fr+tr)/2; pos->ep_c=tc;
} else { pos->ep_r=-1; pos->ep_c=-1; }
/* Promotion → Queen */
if(pt==PAWN&&(tr==0||tr==7))
pos->board[tr][tc]=(white?QUEEN:-QUEEN);
/* Castling rook */
if(pt==KING){
int row=white?7:0;
if(tc==6&&fc==4){ pos->board[row][5]=pos->board[row][7]; pos->board[row][7]=EMPTY; }
if(tc==2&&fc==4){ pos->board[row][3]=pos->board[row][0]; pos->board[row][0]=EMPTY; }
if(white) pos->castle&=~0x3; else pos->castle&=~0xC;
}
if(pt==ROOK){
if(fr==7&&fc==7) pos->castle&=~0x1;
if(fr==7&&fc==0) pos->castle&=~0x2;
if(fr==0&&fc==7) pos->castle&=~0x4;
if(fr==0&&fc==0) pos->castle&=~0x8;
}
pos->half_moves = (pt==PAWN||captured) ? 0 : pos->half_moves+1;
if(!white) pos->full_moves++;
pos->white_turn=!pos->white_turn;
return captured;
}
/* Legal move generation (filters out moves leaving king in check) */
static void legal_moves_all(const Position *pos, MoveList *out) {
out->n=0;
int white=pos->white_turn;
for(int r=0;r<8;r++) for(int c=0;c<8;c++){
int p=pos->board[r][c];
if(!p||(p>0)!=white) continue;
MoveList tmp; tmp.n=0;
gen_moves_for(pos,r,c,&tmp);
for(int i=0;i<tmp.n;i++){
Position nb=*pos;
apply_move(&nb,tmp.m[i]);
if(!in_check(&nb,white)){
if(out->n<MAX_MOVES) out->m[out->n++]=tmp.m[i];
}
}
}
}
static void legal_dests_for(const Position *pos, int r, int c, MoveList *out){
out->n=0;
int p=pos->board[r][c]; if(!p) return;
int white=p>0;
MoveList tmp; tmp.n=0;
gen_moves_for(pos,r,c,&tmp);
for(int i=0;i<tmp.n;i++){
Position nb=*pos;
apply_move(&nb,tmp.m[i]);
if(!in_check(&nb,white)){
if(out->n<MAX_MOVES) out->m[out->n++]=tmp.m[i];
}
}
}
/* ═══════════════════════════════════════════════════════════════════════════
* EVALUATION & AI
* ═══════════════════════════════════════════════════════════════════════════ */
static int evaluate(const Position *pos) {
int score=0;
for(int r=0;r<8;r++) for(int c=0;c<8;c++){
int p=pos->board[r][c]; if(!p) continue;
int white=p>0, pt=abs(p);
int v=PIECE_VAL[pt];
int pr=white?r:7-r;
if(pt==PAWN) v+=PST_PAWN[pr][c];
else if(pt==KNIGHT) v+=PST_KNIGHT[pr][c];
else if(pt==KING) v+=PST_KING[pr][c];
score += white?v:-v;
}
return score;
}
/* Move ordering: captures first */
static int move_score(const Position *pos, Move mv){
int cap=abs(pos->board[mv.tr][mv.tc]);
int pt=abs(pos->board[mv.fr][mv.fc]);
return cap?PIECE_VAL[cap]-pt/10:0;
}
static int cmp_moves(const void *a,const void *b){return *(int*)b-*(int*)a;}
static int minimax(const Position *pos, int depth, int alpha, int beta,
int maxi, Move *best_out) {
if(depth==0) return evaluate(pos);
MoveList ml; legal_moves_all(pos,&ml);
if(!ml.n){
if(in_check(pos,pos->white_turn)) return maxi?-90000:90000;
return 0;
}
/* Simple capture-first ordering */
int scores[MAX_MOVES];
for(int i=0;i<ml.n;i++) scores[i]=move_score(pos,ml.m[i]);
/* bubble sort (small lists) */
for(int i=0;i<ml.n-1;i++) for(int j=i+1;j<ml.n;j++)
if(scores[j]>scores[i]){
int ts=scores[i]; scores[i]=scores[j]; scores[j]=ts;
Move tm=ml.m[i]; ml.m[i]=ml.m[j]; ml.m[j]=tm;
}
Move local_best=ml.m[0];
int best = maxi?-100000:100000;
for(int i=0;i<ml.n;i++){
Position nb=*pos;
apply_move(&nb,ml.m[i]);
int v=minimax(&nb,depth-1,alpha,beta,!maxi,NULL);
if(maxi){
if(v>best){ best=v; local_best=ml.m[i]; }
if(v>alpha) alpha=v;
} else {
if(v<best){ best=v; local_best=ml.m[i]; }
if(v<beta) beta=v;
}
if(beta<=alpha) break;
}
if(best_out) *best_out=local_best;
return best;
}
static const int AI_DEPTH[3]={1,3,4}; /* easy, medium, hard */
/* ═══════════════════════════════════════════════════════════════════════════
* DRAWING
* ═══════════════════════════════════════════════════════════════════════════ */
/* Gint colour helper: drect fills a rectangle */
static void fill(int x,int y,int w,int h,int c){
drect(x,y,x+w-1,y+h-1,c);
}
/* Small 5×7 piece bitmaps (1 row per int, bit4=leftmost) */
static const uint8_t GLYPH[7][7]={
{0}, /* EMPTY */
{0x0E,0x0E,0x04,0x0E,0x1F,0x1F,0x00}, /* PAWN */
{0x0E,0x1E,0x1F,0x0F,0x06,0x1F,0x00}, /* KNIGHT */
{0x04,0x0E,0x0E,0x04,0x0E,0x1F,0x00}, /* BISHOP */
{0x15,0x1F,0x0E,0x0E,0x0E,0x1F,0x00}, /* ROOK */
{0x15,0x15,0x1F,0x0E,0x0E,0x1F,0x00}, /* QUEEN */
{0x04,0x1F,0x04,0x0E,0x0E,0x1F,0x00}, /* KING */
};
static void draw_glyph(int x,int y,int pt,int fg,int bg){
for(int row=0;row<7;row++){
uint8_t bits=GLYPH[pt][row];
for(int col=0;col<5;col++){
int on=(bits>>(4-col))&1;
dpixel(x+col,y+row,on?fg:bg);
}
}
}
static void draw_border(int x,int y,int w,int h,int c){
drect(x,y,x+w-1,y,c);
drect(x,y+h-1,x+w-1,y+h-1,c);
drect(x,y,x,y+h-1,c);
drect(x+w-1,y,x+w-1,y+h-1,c);
}
/* ── Board squares ─────────────────────────────────────────────────────── */
static void draw_squares(Move last){
for(int r=0;r<8;r++) for(int c=0;c<8;c++){
int x=BX+c*CS, y=BY+r*CS;
int lm=(last.fr==r&&last.fc==c)||(last.tr==r&&last.tc==c);
int col;
if(lm) col=C_LASTMOVE;
else if((r+c)%2==0) col=C_LIGHT_SQ;
else col=C_DARK_SQ;
fill(x,y,CS,CS,col);
}
}
/* ── Piece glyphs ──────────────────────────────────────────────────────── */
static void draw_pieces(int board[8][8], Move last){
for(int r=0;r<8;r++) for(int c=0;c<8;c++){
int p=board[r][c]; if(!p) continue;
int x=BX+c*CS, y=BY+r*CS;
int lm=(last.fr==r&&last.fc==c)||(last.tr==r&&last.tc==c);
int sq_bg;
if(lm) sq_bg=C_LASTMOVE;
else if((r+c)%2==0) sq_bg=C_LIGHT_SQ;
else sq_bg=C_DARK_SQ;
int white=p>0, pt=abs(p);
int fg=white?C_WHITE_P:C_BLACK_P;
/* Shadow for white pieces on light squares */
if(white&&(r+c)%2==0)
draw_glyph(x+(CS-5)/2+1,y+(CS-7)/2+1,pt,C_OUTLINE,sq_bg);
draw_glyph(x+(CS-5)/2,y+(CS-7)/2,pt,fg,sq_bg);
}
}
/* ── Cursor ────────────────────────────────────────────────────────────── */
static void draw_cursor(int r,int c,int col){
int x=BX+c*CS, y=BY+r*CS;
draw_border(x,y,CS,CS,col);
draw_border(x+1,y+1,CS-2,CS-2,col);
}
/* ── Move hints ────────────────────────────────────────────────────────── */
static void draw_hints(MoveList *ml, int board[8][8]){
for(int i=0;i<ml->n;i++){
int tr=ml->m[i].tr, tc=ml->m[i].tc;
int x=BX+tc*CS, y=BY+tr*CS;
if(board[tr][tc]!=EMPTY){
draw_border(x+1,y+1,CS-2,CS-2,C_CAPTURE);
draw_border(x+2,y+2,CS-4,CS-4,C_CAPTURE);
} else {
int cx=x+CS/2, cy=y+CS/2;
fill(cx-2,cy-2,5,5,C_HINT);
}
}
}
/* ── Check highlight ───────────────────────────────────────────────────── */
static void draw_check(const Position *pos, int white){
if(!in_check(pos,white)) return;
int kr,kc; find_king(pos,white,&kr,&kc);
int x=BX+kc*CS, y=BY+kr*CS;
draw_border(x,y,CS,CS,C_CHECK);
draw_border(x+1,y+1,CS-2,CS-2,C_CHECK);
}
/* ── Coordinates ───────────────────────────────────────────────────────── */
static void draw_coords(){
char buf[2]={0,0};
for(int i=0;i<8;i++){
buf[0]='8'-i;
dtext(BX-10,BY+i*CS+8,C_DIM,buf);
buf[0]='a'+i;
dtext(BX+i*CS+8,BY+8*CS+2,C_DIM,buf);
}
}
/* ── Right panel ───────────────────────────────────────────────────────── */
static void draw_panel(int diff, int white_turn, const char *status,
int wtime, int btime, int move_num,
int w_score, int b_score, int ai_thinking){
int px=PANEL_X, pw=SW-px;
fill(px,0,pw,SH,C_PANEL);
/* Title */
dtext(px+2,2,C_TITLE,"CHESS");
/* Difficulty tabs */
static const char *dlbl[3]={"EZ","MD","HD"};
static const int dcol[3]={C_EASY,C_MED,C_HARD};
for(int i=0;i<3;i++){
int active=(diff==i);
int bx=px+2+i*22, by=14;
fill(bx,by,20,11,active?dcol[i]:C_PANEL);
draw_border(bx,by,20,11,dcol[i]);
dtext(bx+4,by+2,active?C_BG:dcol[i],dlbl[i]);
}
dtext(px+2,12,C_DIM,"F1 F2 F3");
/* Turn */
int y=30;
dtext(px+2,y,C_DIM,"TURN:"); y+=10;
dtext(px+2,y,white_turn?C_WHITE_P:C_DIM,white_turn?"WHITE":"BLACK"); y+=12;
/* Status */
int sc=C_TEXT;
if(status[0]=='C'&&status[1]=='h') sc=C_RED;
else if(status[0]=='Y'&&status[1]=='o') sc=C_GREEN;
else if(status[0]=='A'&&status[1]=='I') sc=C_GOLD;
dtext(px+2,y,sc,status); y+=12;
if(ai_thinking){ dtext(px+2,y,C_GREEN,"AI..."); y+=10; }
/* Timers */
char buf[12];
dtext(px+2,y,C_DIM,"CLOCKS"); y+=10;
int wc=white_turn?C_GOLD:C_TEXT, bc=!white_turn?C_GOLD:C_DIM;
snprintf(buf,12,"W %02d:%02d",wtime/60,wtime%60);
dtext(px+2,y,wc,buf); y+=10;
snprintf(buf,12,"B %02d:%02d",btime/60,btime%60);
dtext(px+2,y,bc,buf); y+=12;
/* Move number & score */
snprintf(buf,12,"MV:%d",move_num);
dtext(px+2,y,C_DIM,buf); y+=10;
snprintf(buf,12,"W+%d",w_score);
dtext(px+2,y,C_WHITE_P,buf); y+=10;
snprintf(buf,12,"B+%d",b_score);
dtext(px+2,y,C_DIM,buf); y+=14;
/* Key hints */
static const char *hints[]={"F4 New","EXE Sel","DEL Clr","EXIT Quit"};
for(int i=0;i<4;i++){ dtext(px+2,y,C_DIM,hints[i]); y+=10; }
}
/* ── Game-over overlay ─────────────────────────────────────────────────── */
static void draw_gameover(const char *msg, const char *sub){
int ox=BX+16,oy=BY+72,ow=CS*8-32,oh=52;
fill(ox-2,oy-2,ow+4,oh+4,C_GOLD);
fill(ox,oy,ow,oh,C_BG);
int cx=ox+ow/2;
dtext(cx-(int)strlen(msg)*3,oy+8, C_GOLD,msg);
dtext(cx-(int)strlen(sub)*3, oy+22,C_TEXT,sub);
dtext(cx-15, oy+36,C_DIM, "F4=New game");
}
/* ═══════════════════════════════════════════════════════════════════════════
* TIMER (RTC-based second counter via gint rtc)
* ═══════════════════════════════════════════════════════════════════════════ */
static volatile int g_tick=0;
static int timer_id=-1;
static int tick_handler(void){
g_tick++;
return TIMER_CONTINUE;
}
/* ═══════════════════════════════════════════════════════════════════════════
* MAIN
* ═══════════════════════════════════════════════════════════════════════════ */
int main(void){
/* Start a 1-second repeating timer */
timer_id=timer_setup(TIMER_ANY, 1000*1000, tick_handler);
if(timer_id>=0) timer_start(timer_id);
Position pos;
pos_init(&pos);
int cursor_r=6, cursor_c=4;
int sel_r=-1, sel_c=-1;
MoveList dests; dests.n=0;
int diff=1; /* 0=easy 1=medium 2=hard */
int game_over=0;
char status[24]="Your turn";
char go_msg[24]="", go_sub[24]="";
Move last_move; last_move.fr=last_move.fc=last_move.tr=last_move.tc=-1;
int wtime=0, btime=0, last_tick=0;
int w_score=0, b_score=0;
int ai_thinking=0;
Move ai_pending; ai_pending.fr=-1;
for(;;){
/* ── Clock update ─────────────────────────────────────────────── */
int now=g_tick;
int delta=now-last_tick; last_tick=now;
if(!game_over && delta>0){
if(pos.white_turn) wtime+=delta; else btime+=delta;
}
/* ── AI turn ──────────────────────────────────────────────────── */
if(!game_over && !pos.white_turn && !ai_thinking){
ai_thinking=1;
/* redraw to show "AI..." */
dclear(C_BG);
draw_squares(last_move);
draw_coords();
draw_check(&pos,pos.white_turn);
draw_pieces(pos.board,last_move);
draw_panel(diff,pos.white_turn,status,wtime,btime,
pos.full_moves,w_score,b_score,1);
dupdate();
Move best; best.fr=-1;
minimax(&pos,AI_DEPTH[diff],-100000,100000,0,&best);
ai_thinking=0;
if(best.fr>=0){
int cap=apply_move(&pos,best);
if(cap) b_score+=PIECE_VAL[cap]/100;
last_move=best;
MoveList ml; legal_moves_all(&pos,&ml);
if(!ml.n){
game_over=1;
if(in_check(&pos,pos.white_turn)){
strcpy(go_msg,"CHECKMATE!"); strcpy(go_sub,"AI wins F4=new");
strcpy(status,"You lost");
} else {
strcpy(go_msg,"STALEMATE"); strcpy(go_sub,"Draw F4=new");
strcpy(status,"Stalemate");
}
} else {
if(in_check(&pos,pos.white_turn)) strcpy(status,"Check!");
else strcpy(status,"Your turn");
}
} else {
game_over=1;
strcpy(go_msg,"AI RESIGNED"); strcpy(go_sub,"You win! F4=new");
strcpy(status,"AI resigned");
}
}
/* ── Draw ─────────────────────────────────────────────────────── */
dclear(C_BG);
draw_squares(last_move);
draw_coords();
draw_check(&pos,pos.white_turn);
if(dests.n) draw_hints(&dests,pos.board);
if(sel_r>=0) draw_cursor(sel_r,sel_c,C_SELECTED);
draw_cursor(cursor_r,cursor_c,C_CURSOR);
draw_pieces(pos.board,last_move);
draw_panel(diff,pos.white_turn,status,wtime,btime,
pos.full_moves,w_score,b_score,ai_thinking);
if(game_over) draw_gameover(go_msg,go_sub);
dupdate();
/* ── Input (non-blocking poll) ────────────────────────────────── */
int k=getkey_opt(GETKEY_NONE,NULL);
if(!k) continue; /* no key, keep looping (timer/AI updates) */
/* EXIT */
if(k==KEY_EXIT) break;
/* F4 – new game */
if(k==KEY_F4){
pos_init(&pos);
cursor_r=6; cursor_c=4;
sel_r=-1; dests.n=0;
game_over=0; ai_thinking=0;
last_move.fr=last_move.fc=last_move.tr=last_move.tc=-1;
wtime=0; btime=0; w_score=0; b_score=0;
strcpy(status,"Your turn"); go_msg[0]=0; go_sub[0]=0;
continue;
}
/* Difficulty (only when human's turn and not game over) */
if(k==KEY_F1&&!game_over&&pos.white_turn){ diff=0; strcpy(status,"Easy mode"); continue; }
if(k==KEY_F2&&!game_over&&pos.white_turn){ diff=1; strcpy(status,"Medium mode"); continue; }
if(k==KEY_F3&&!game_over&&pos.white_turn){ diff=2; strcpy(status,"Hard mode"); continue; }
if(game_over) continue;
if(!pos.white_turn) continue; /* human only plays white */
/* DEL – deselect */
if(k==KEY_DEL){ sel_r=-1; dests.n=0; strcpy(status,"Your turn"); continue; }
/* Cursor movement */
if(k==KEY_UP && cursor_r>0){ cursor_r--; continue; }
if(k==KEY_DOWN && cursor_r<7){ cursor_r++; continue; }
if(k==KEY_LEFT && cursor_c>0){ cursor_c--; continue; }
if(k==KEY_RIGHT && cursor_c<7){ cursor_c++; continue; }
/* EXE */
if(k==KEY_EXE){
int r=cursor_r, c=cursor_c;
if(sel_r<0){
/* Select own piece */
int p=pos.board[r][c];
if(p>0){
legal_dests_for(&pos,r,c,&dests);
if(dests.n){ sel_r=r; sel_c=c; strcpy(status,"Move where?"); }
else strcpy(status,"No moves");
}
} else {
/* Check if destination */
int found=-1;
for(int i=0;i<dests.n;i++)
if(dests.m[i].tr==r&&dests.m[i].tc==c){ found=i; break; }
if(found>=0){
/* Commit move */
int cap=apply_move(&pos,dests.m[found]);
if(cap) w_score+=PIECE_VAL[cap]/100;
last_move=dests.m[found];
sel_r=-1; dests.n=0;
/* Check game state immediately */
MoveList ml; legal_moves_all(&pos,&ml);
if(!ml.n){
game_over=1;
if(in_check(&pos,pos.white_turn)){
strcpy(go_msg,"CHECKMATE!"); strcpy(go_sub,"You win! F4=new");
strcpy(status,"Checkmate!");
} else {
strcpy(go_msg,"STALEMATE"); strcpy(go_sub,"Draw F4=new");
strcpy(status,"Stalemate");
}
} else {
strcpy(status,"AI thinking...");
}
} else if(pos.board[r][c]>0){
/* Reselect different piece */
legal_dests_for(&pos,r,c,&dests);
if(dests.n){ sel_r=r; sel_c=c; strcpy(status,"Move where?"); }
else { sel_r=-1; dests.n=0; strcpy(status,"No moves"); }
} else {
sel_r=-1; dests.n=0; strcpy(status,"Your turn");
}
}
}
}
if(timer_id>=0) timer_stop(timer_id);
return 1;
}
Here is CMakeLists.txt:
cmake_minimum_required(VERSION 3.15)
project(chess)
# ── fxSDK toolchain must be active ───────────────────────────────────────────
# Run: fxsdk build-cg
# or: cmake -B build -DCMAKE_TOOLCHAIN_FILE=/path/to/fxSDK/toolchain.cmake
# cmake --build build
include(GenerateG3A) # provided by fxSDK; also handles .g4m for CG100
set(SOURCES
src/main.c
)
# ── Add-in target ─────────────────────────────────────────────────────────────
fxconv_declare_assets(${SOURCES} WITH_BUILTIN_FONT)
add_executable(chess ${SOURCES})
target_compile_options(chess PRIVATE
-Wall -Wextra -O2
-ffunction-sections -fdata-sections
)
target_link_options(chess PRIVATE
-Wl,--gc-sections
)
# Link gint (Gint runtime + CASIO OS bindings)
find_package(Gint 2.9 REQUIRED)
target_link_libraries(chess Gint::Gint)
# ── Generate the .g4m add-in file ─────────────────────────────────────────────
# Icon files: icon-cg.png must be 92×64 pixels (provided in assets/)
generate_g3a(chess OUTPUT "chess.g4m"
NAME "Chess AI"
ICON "${CMAKE_SOURCE_DIR}/assets/icon.png"
)
Fichier joint
Citer : Posté le 08/03/2026 07:05 | #
Hi, sorry Planète Casio is not an online free sweatshop for processing and fixing your ChatGPT or other AI output. If you post about your setup issues with fxSDK, we can probably help you fix it however, so you can try making your add-in yourself. Keep in mind though that calculators don't have an awful lot of memory safety like other platforms do, and a bad add-in could brick your calculator.
Citer : Posté le 08/03/2026 10:14 | #
There's also a bunch of mistakes in the code and some of the stuff is legendary in how incorrect it is. QVGA 384x216, sure mate. Clearly not enough gint code in the training set of it to understand the APIs properly. What a shitshow this is...