sorry for double post, missed the attachment.
v4hn
/* simple chess implementation by v4hn @ 2009 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef enum {
BLACK = 0x00,
WHITE = 0x20
} chess_color;
typedef unsigned short chess_move;
typedef signed char chess_pos;
typedef char* chess_board;
#define IS_FREE(x) (x == 0x20)
#define IS_PIECE(x) (x&(0x40))
#define IS(color, x) (!IS_FREE(x) && ((x&0x20) == color))
#define OPPONENT(color) ((chess_color) (color^0x20))
#define POS(x,y) ((chess_pos)(x-65)+((8-y)*8))
#define MOVE(f,t) ((chess_move)(((short) (f) << 8) | (t)))
#define FROM(m) ((chess_pos)(m >> 8))
#define TO(m) ((chess_pos)(m & 0xFF))
void print_board();
int valid_pawn_move(chess_move m);
int valid_rook_move(chess_move move);
int valid_bishop_move(chess_move move);
int valid_knight_move(chess_move move);
int valid_king_move(chess_move move);
int valid_castling_move(chess_color color, chess_move move);
int is_reachable(chess_color color, chess_pos pos);
int self_check_after(chess_color color, chess_move move);
int is_valid(chess_color color, chess_move move);
chess_move read_move(chess_color color);
int do_move(chess_move move);
int move(chess_color color);
/* current board */
char* board;
/* was the last move a wide pawn jump? (en passant possible)*/
chess_pos pawn_jump;
/* is castling still allowed? */
char castling_possible[2];
inline int sgn(int x){
return (x < 0) ? -1 : 1;
}
void print_board(){
unsigned int row= 0, col= 0;
printf("\n"
" || A | B | C | D | E | F | G | H ||\n"
"=======================================\n");
for(row= 0; row < 8; row++){
printf("%d ||", 8-row);
for(col= 0; col < 8; col++){
printf(" %c |", board[row*8+col]);
}
printf("| %d\n"
"---------------------------------------\n",
8-row);
}
printf("=======================================\n"
" || A | B | C | D | E | F | G | H ||\n\n");
}
int valid_pawn_move(chess_move m){
return ( IS(WHITE, board[FROM(m)]) ?
((FROM(m)/8 - TO(m)/8 == 1) &&
(FROM(m)%8 - TO(m)%8 == 0) &&
IS_FREE(board[TO(m)])) ||
((FROM(m)/8 - TO(m)/8 == 1) &&
(abs(FROM(m)%8 - TO(m)%8) == 1) &&
(IS(BLACK, board[TO(m)]) || (pawn_jump == TO(m)+8))) ||
((FROM(m)/8 - TO(m)/8 == 2) &&
FROM(m)%8 - TO(m)%8 == 0 &&
IS_FREE(board[FROM(m)-8]) &&
IS_FREE(board[TO(m)]))
:
((TO(m)/8 - FROM(m)/8 == 1) &&
(TO(m)%8 - FROM(m)%8 == 0) &&
IS_FREE(board[TO(m)])) ||
((TO(m)/8 - FROM(m)/8 == 1) &&
(abs(TO(m)%8 - FROM(m)%8) == 1) &&
(IS(WHITE, TO(m)) || pawn_jump == TO(m)-8)) ||
((TO(m)/8 - FROM(m)/8 == 2) &&
TO(m)%8 - FROM(m)%8 == 0 &&
IS_FREE(board[FROM(m)+8]) &&
IS_FREE(board[TO(m)]))
);
}
int valid_rook_move(chess_move move){
chess_pos i;
if((FROM(move)%8 != TO(move)%8) &&
(FROM(move)/8 != TO(move)/8))
return 0;
i= FROM(move);
while(i != TO(move) && IS_FREE(board[ i+= sgn(TO(move)-FROM(move)) *
((FROM(move)%8 == TO(move)%8)?8:1) ]) );
return (i == TO(move));
}
int valid_bishop_move(chess_move move){
chess_pos i, last_round;
if( (!((TO(move)-FROM(move))%9) &&
!((TO(move)-FROM(move))%7)))
return 0;
i= last_round= FROM(move);
while(i != TO(move) && IS_FREE(board[ i+= sgn(TO(move)-FROM(move)) *
((TO(move)-FROM(move))%9 ? 7 : 9) ])){
if(abs(last_round/8 - i/8) != 1)
return 0;
last_round= i;
}
return (i == TO(move));
}
int valid_knight_move(chess_move move){
return (abs(FROM(move)%8 - TO(move)%8) == 2 && abs(FROM(move)/8 - TO(move)/8)
== 1) ||
(abs(FROM(move)%8 - TO(move)%8) == 1 && abs(FROM(move)/8 - TO(move)/8)
== 2);
}
int valid_king_move(chess_move move){
return (abs(FROM(move)%8 - TO(move)%8) <= 1) && (abs(FROM(move)/8 -
TO(move)/8) <= 1);
}
int valid_castling_move(chess_color color, chess_move move){
chess_pos i;
switch(TO(move)&~0x20){
case 0:
if(castling_possible[color == WHITE]%2 == 0)
return 0;
for(i= 5+8*(color == WHITE ? 7 : 0); i%8 != 7; i++)
if(!IS_FREE(board[i]))
return 0;
for(i= 5+8*(color == WHITE ? 7 : 0); i%8 != 7; i++)
if(is_reachable(OPPONENT(color), i))
return 0;
break;
case 1:
if(castling_possible[color == WHITE] < 2)
return 0;
for(i= 1+8*(color == WHITE ? 7 : 0); i%8 != 4; i++)
if(!IS_FREE(board[i]))
return 0;
for(i= 2+8*(color == WHITE ? 7 : 0); i%8 != 5; i++)
if(is_reachable(OPPONENT(color), i))
return 0;
break;
default:
return 0;
}
return 1;
}
int is_reachable(chess_color color, chess_pos pos){
chess_pos i;
for(i= 0; i < 65; i++){
if(is_valid(color, MOVE(i, pos)))
break;
}
return (i != 65);
}
int self_check_after(chess_color color, chess_move move){
chess_pos king_pos;
char *real_board, hyp_board[65];
int tmp;
real_board= board;
strcpy(hyp_board, board);
board= hyp_board;
do_move(move);
for(king_pos= 0; king_pos < 65; king_pos++)
if( IS(color, board[king_pos]) && ((board[king_pos]|0x20) == 'k') )
break;
tmp= is_reachable(OPPONENT(color), king_pos);
board= real_board;
return tmp;
}
int is_valid(chess_color color, chess_move move){
if(FROM(move) == -1)
return 1;
if(FROM(move) == -2)
return ((TO(move)&0x20) == color) && valid_castling_move(color, move);
if( (FROM(move) == TO(move)) || !IS(color, board[FROM(move)]) || IS(color,
board[TO(move)]) )
return 0;
switch(board[FROM(move)]|0x20){
case 'p':
return valid_pawn_move(move);
case 'r':
return valid_rook_move(move);
case 'n':
return valid_knight_move(move);
case 'b':
return valid_bishop_move(move);
case 'q':
return valid_rook_move(move) || valid_bishop_move(move);
case 'k':
return valid_king_move(move);
default:
return 0;
}
}
chess_move read_move(chess_color color){
char x1, x2;
unsigned int y1, y2;
char buf[64];
for(;;){
printf("%s move(%s): ", (color == BLACK) ? "blacks" : "whites", (color ==
BLACK) ? "uc" : "lc");
fgets(buf, sizeof(buf), stdin);
if(sscanf(buf, "%c%u-%c%u", &x1, &y1, &x2, &y2) == 4 &&
(x1&= ~0x20, ('A' <= x1 && x1 <= 'H') && (1 <= y1 && y1 <= 8)) &&
(x2&= ~0x20, ('A' <= x2 && x2 <= 'H') && (1 <= y2 && y2 <= 8)))
return MOVE(POS(x1,y1), POS(x2, y2));
else if(!strcmp(buf, "resign\n"))
return 0xFF00;
else if(!strcmp(buf, "0-0\n"))
return 0xFE00 | color;
else if(!strcmp(buf, "0-0-0\n"))
return 0xFE01 | color;
}
}
int do_move(chess_move move){
switch(FROM(move)){
case -2:
switch(TO(move)&~0x20){
case 0:
board[4+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= ' ';
board[5+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= 'R' | (TO(move)&0x20);
board[6+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= 'K' | (TO(move)&0x20);
board[7+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= ' ';
break;
case 1:
board[0+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= ' ';
board[1+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= ' ';
board[2+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= 'K' | (TO(move)&0x20);
board[3+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= 'R' | (TO(move)&0x20);
board[4+8*((TO(move)&0x20) == WHITE ? 7 : 0)]= ' ';
break;
default:
break;
}
break;
default:
board[TO(move)]= board[FROM(move)];
board[FROM(move)]= ' ';
if(((board[TO(move)]|0x20) == 'p') && (pawn_jump == TO(move) +
sgn(FROM(move)-TO(move))*8))
board[pawn_jump]= ' ';
}
return 1;
}
int move(chess_color color){
chess_move move;
char s= '\0';
print_board();
while( !is_valid(color, move= read_move(color)) || self_check_after(color,
move) )
printf("invalid move\n");
if(FROM(move) == -2 || (board[FROM(move)]|0x20) == 'k')
castling_possible[color == WHITE]= 0;
else if(FROM(move) == 8*(color == WHITE ? 7 : 0))
castling_possible[color == WHITE]&= ~2;
else if(FROM(move) == 7+8*(color == WHITE ? 7 : 0))
castling_possible[color == WHITE]&= ~1;
else if(FROM(move) == -1){
printf("%s resigned\n", (color == BLACK) ? "black" : "white" );
return 0;
}
do_move(move);
if( (board[TO(move)]|0x20 == 'p') && (TO(move)/8 == ((board[TO(move)]&0x20)
== WHITE ? 0 : 7))){
while(s != 'Q' && s != 'N' && s != 'R' && s != 'B'){
printf("select promotion out of /q/ueen, k/n/ight, /r/ook, /b/ishop: ");
s= (getchar()&~0x20);
}
board[TO(move)]= (board[TO(move)]&0x20) | s;
}
pawn_jump= ((board[TO(move)]|0x20) == 'p' && abs(FROM(move) - TO(move)) ==
16) ? TO(move) : 0;
return 1;
}
int main(){
board= malloc(65*sizeof(char));
strcpy(board,
"RNBQKBNR" /*black*/
"PPPPPPPP"
" "
" "
" "
" "
"ppPppppp"
"rn qkbnr" /*white*/
);
pawn_jump= 0;
castling_possible[0]= castling_possible[1]= 3;
while(move(WHITE) && move(BLACK));
return 0;
}
pgpvf5mFSFRSo.pgp
Description: PGP signature
