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;
}

Attachment: pgpvf5mFSFRSo.pgp
Description: PGP signature

Reply via email to