Code:
#pragma hdrstop
#include <condefs.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BOARD_SIZE 8
#define BLOCKSIZE 10
typedef enum { empty = 0, pawn, rook, knight, bishop, queen, king } Piece;
typedef enum { white, black } Colour;
typedef enum {FALSE, TRUE} Bool;
typedef struct {
Piece piece;
Colour colour;
} Square;
typedef Square Board[BOARD_SIZE][BOARD_SIZE];
char BlackPieces[7] = {' ','p','r','n','b','q','k'};
char WhitePieces[7] = {' ','P','R','N','B','Q','K'};
Board *boards; /* Array of all boards */
#define board boards[number_of_used_boards - 1] /* Current (last) board */
int number_of_allocated_boards;
int number_of_used_boards;
int read_line(char str[], int n);
void init_board (void);
void init_boards (void);
void add_boards (void);
void next_board (void);
void print_board (int n);
void print_last_board (void);
void print_all_boards (void);
int move_piece (Colour colour);
Bool move_vh (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int from_col, int from_row, int to_col, int to_row);
Bool move_dia (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int from_col, int from_row, int to_col, int to_row);
Bool move_pawn (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour);
void convert_pawn (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int col, int row);
Bool move_queen (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour);
Bool move_rook (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour);
Bool move_bishop (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour);
Bool move_knight (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour);
Bool move_king (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour);
void perform_move (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int from_col, int from_row,
int to_col, int to_row);
int translate_col (char col);
int translate_row (int row);
Bool check_std_move (const char *move, int *from_col_num,
int *to_col_num, int *from_row_num, int *to_row_num);
//---------------------------------------------------------------------------
#pragma argsused
int main(int argc, char* argv[])
{
Colour next = white;
int res;
init_boards ();
print_last_board ();
while ((res = move_piece (next)) != 1)
{
if (res == 0) {
print_last_board ();
next = (next == white) ? black : white;
}
if (res == 3)
print_all_boards ();
}
return 0;
}
/************************************************
* check_std_move checks whether the move is a *
* regular a2a4 type move. *
************************************************/
Bool check_std_move (const char *move, int *from_col_num,
int *to_col_num, int *from_row_num, int *to_row_num)
{
char from_col, to_col;
int from_row, to_row;
int items;
items = sscanf (move, "%c%d%c%d", &from_col, &from_row, &to_col, &to_row);
if (items != 4) {
fprintf (stderr, "ERROR: This is not a valid move.\n");
return FALSE;
}
*from_col_num = translate_col (from_col);
*to_col_num = translate_col (to_col);
*from_row_num = translate_row (from_row);
*to_row_num = translate_row (to_row);
return (!(*from_col_num < 0 || *to_col_num < 0 ||
*from_row_num < 0 || *to_row_num < 0 ||
(*from_col_num == *to_col_num && *from_row_num == *to_row_num)));
}
/************************************************
* translate_col turns column letter into *
* column number *
************************************************/
int
translate_col (char col)
{
if (col > 'h')
return -1;
if (col < 'a')
return -1;
return (col - 'a');
}
/************************************************
* translate_row turns row spec into *
* row number *
************************************************/
int
translate_row (int row)
{
if (row > BOARD_SIZE)
return -1;
if (row < 1)
return -1;
return (row - 1);
}
/************************************************
* perform_move performs the specified move *
* assuming it is valid *
************************************************/
void
perform_move (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int from_col, int from_row,
int to_col, int to_row)
{
boards[length][to_row][to_col] = boards[length][from_row][from_col];
boards[length][from_row][from_col].piece = empty;
return;
}
/************************************************
* move_vh handles a single vertical or *
* horizontal move attempt
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool move_vh (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int from_col, int from_row, int to_col, int to_row)
{
if (from_col == to_col) {
/* vertical move */
if (from_row < to_row) {
int i;
for (i = to_row - 1; i > from_row; i--)
if (boards[length][i][from_col].piece != empty)
return FALSE;
return TRUE;
} else {
int i;
for (i = to_row + 1; i < from_row; i++)
if (boards[length][i][from_col].piece != empty)
return FALSE;
return TRUE;
}
}
if (from_row == to_row) {
/* horizontal move */
if (from_col < to_col) {
int i;
for (i = to_col - 1; i > from_col; i--)
if (boards[length][from_row][i].piece != empty)
return FALSE;
return TRUE;
} else {
int i;
for (i = to_col + 1; i < from_col; i++)
if (boards[length][from_row][i].piece != empty)
return FALSE;
return TRUE;
}
}
return FALSE;
}
/************************************************
* move_dia handles a single diagonal *
* move attempt
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool move_dia (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int from_col, int from_row, int to_col, int to_row)
{
if (abs(from_row - to_row) == abs(from_col - to_col)) {
if (from_col < to_col) {
int diff = (from_row < to_row) ? 1 : -1;
int i, j;
for (i = to_col - 1, j = to_row - diff; i > from_col; i--, j -= diff)
if (boards[length][j][i].piece != empty)
return FALSE;
return TRUE;
} else {
int diff = (from_row < to_row) ? 1 : -1;
int i, j;
for (i = to_col + 1, j = to_row - diff; i < from_col; i++, j -= diff)
if (boards[length][j][i].piece != empty)
return FALSE;
return TRUE;
}
}
return FALSE;
}
/************************************************
* move_knight handles a single move attempt *
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool
move_knight (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour)
{
int from_col, to_col, from_row, to_row;
if (!(check_std_move (move, &from_col, &to_col, &from_row, &to_row)) ||
(boards[length][to_row][to_col].piece != empty &&
boards[length][to_row][to_col].colour == colour)) {
fprintf (stderr, "ERROR: This is not "
"a valid move for a knight.\n");
return FALSE;
}
if (abs((from_col - to_col) * (from_row - to_row)) == 2) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
return TRUE;
}
fprintf (stderr, "ERROR: This is not "
"a valid move for a knight.\n");
return FALSE;
}
/************************************************
* move_king handles a single move attempt *
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool
move_king (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour)
{
int from_col, to_col, from_row, to_row;
if (!(check_std_move (move, &from_col, &to_col, &from_row, &to_row)) ||
(boards[length][to_row][to_col].piece != empty &&
boards[length][to_row][to_col].colour == colour)) {
fprintf (stderr, "ERROR: This is not "
"a valid move for a king.\n");
return FALSE;
}
if (abs (from_col - to_col) <= 1 && abs (from_row - to_row) <= 1) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
return TRUE;
}
fprintf (stderr, "ERROR: This is not "
"a valid move for a king.\n");
return FALSE;
}
/************************************************
* move_queen handles a single move attempt *
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool
move_queen (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour)
{
int from_col, to_col, from_row, to_row;
if (!(check_std_move (move, &from_col, &to_col, &from_row, &to_row)) ||
(boards[length][to_row][to_col].piece != empty &&
boards[length][to_row][to_col].colour == colour)) {
fprintf (stderr, "ERROR: This is not "
"a valid move for a queen.\n");
return FALSE;
}
if (move_vh (boards, length, from_col, from_row, to_col, to_row)) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
return TRUE;
}
if (move_dia (boards, length, from_col, from_row, to_col, to_row)) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
return TRUE;
}
fprintf (stderr, "ERROR: This is not "
"a valid move for a queen.\n");
return FALSE;
}
/************************************************
* move_rook handles a single move attempt *
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool
move_rook (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour)
{
int from_col, to_col, from_row, to_row;
if (!(check_std_move (move, &from_col, &to_col, &from_row, &to_row)) ||
(boards[length][to_row][to_col].piece != empty &&
boards[length][to_row][to_col].colour == colour)) {
fprintf (stderr, "ERROR: This is not "
"a valid move for a rook.\n");
return FALSE;
}
if (move_vh (boards, length, from_col, from_row, to_col, to_row)) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
return TRUE;
}
fprintf (stderr, "ERROR: This is not "
"a valid move for a rook.\n");
return FALSE;
}
/************************************************
* move_bishop handles a single move attempt *
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool
move_bishop (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour)
{
int from_col, to_col, from_row, to_row;
if (!(check_std_move (move, &from_col, &to_col, &from_row, &to_row)) ||
(boards[length][to_row][to_col].piece != empty &&
boards[length][to_row][to_col].colour == colour)) {
fprintf (stderr, "ERROR: This is not "
"a valid move for a bishop.\n");
return FALSE;
}
if (move_dia (boards, length, from_col, from_row, to_col, to_row)) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
return TRUE;
}
fprintf (stderr, "ERROR: This is not "
"a valid move for a bishop.\n");
return FALSE;
}
/************************************************
* convert_pawn changes the pawn into a queen *
************************************************/
void
convert_pawn (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
int col, int row)
{
boards[length][row][col].piece = queen;
}
/************************************************
* move_pawn handles a single move attempt *
* return values:
* TRUE successful move
* FALSE unsuccessful move, try again.
*
************************************************/
Bool
move_pawn (Square boards[][BOARD_SIZE][BOARD_SIZE], int length,
const char *move, Colour colour)
{
int diff = (colour == white) ? 1 : -1;
int initial = (colour == white) ? 1 : 6;
int last = (colour == white) ? 7 : 0;
int from_col, to_col, from_row, to_row;
if (check_std_move (move, &from_col, &to_col, &from_row, &to_row))
{
switch (abs(from_col - to_col)) {
case 0: if (from_row + diff == to_row &&
boards[length][from_row + diff][from_col].piece
== empty) {
perform_move (boards, length, from_col, from_row,
to_col, to_row);
if (to_row == last)
convert_pawn (boards, length, to_col, to_row);
return TRUE;
}
if (from_row == initial &&
from_row + 2 * diff == to_row &&
boards[length][from_row + diff][from_col].piece == empty &&
boards[length][from_row + 2 * diff][from_col].piece == empty) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
return TRUE;
}
/* Move not valid */
break;
case 1: if (from_row + diff == to_row &&
boards[length][from_row + diff][to_col].piece != empty &&
boards[length][from_row + diff][to_col].colour != colour) {
perform_move (boards, length, from_col, from_row, to_col, to_row);
if (to_row == last)
convert_pawn (boards, length, to_col, to_row);
return TRUE;
}
/* Move not valid */
break;
default: /* Move not valid */
break;
}
}
fprintf (stderr, "ERROR: This is not a valid move for a pawn.\n");
return FALSE;
}
/************************************************
* move_piece handles a single move attempt *
* return values:
* 0 successful move
* 1 exit
* 2 unsuccessful move, try again.
* 3 print boards
*
************************************************/
int
move_piece (Colour colour)
{
char move[5];
char from_col;
int from_col_num;
int from_row;
int from_row_num;
int items;
Bool move_valid;
printf ((colour == white) ? "White: " : "Black: ");
read_line (move, 4);
if (strcmp(move, "exit") == 0)
return 1;
if (strcmp(move, "prin") == 0)
return 3;
items = sscanf (move, "%c%d", &from_col, &from_row);
if (items != 2) {
fprintf (stderr, "ERROR: This is not a valid move.\n");
return 2;
}
from_col_num = translate_col (from_col);
from_row_num = translate_row (from_row);
if (from_col_num < 0 ||
from_row_num < 0 ||
board[from_row_num][from_col_num].colour != colour ||
board[from_row_num][from_col_num].piece == empty) {
fprintf (stderr, "ERROR: This is not a valid move.\n");
return 2;
}
switch (board[from_row_num][from_col_num].piece) {
case pawn: move_valid = move_pawn (boards, number_of_used_boards,
move, colour);
break;
case rook: move_valid = move_rook (boards, number_of_used_boards,
move, colour);
break;
case knight: move_valid = move_knight (boards, number_of_used_boards,
move, colour);
break;
case bishop: move_valid = move_bishop (boards, number_of_used_boards,
move, colour);
break;
case queen: move_valid = move_queen (boards, number_of_used_boards,
move, colour);
break;
case king: move_valid = move_king (boards, number_of_used_boards,
move, colour);
break;
case empty:
fprintf (stderr, "We should not be getting here!\n");
return 1;
default:
fprintf (stderr, "Moving this figure is "
"not implemented yet.\n");
return 2;
}
if (move_valid)
next_board ();
return (move_valid ? 0 : 2);
}
/************************************************
* init_board initializes the board *
************************************************/
void
init_board (void)
{
int i, j;
for (i = 0; i < BOARD_SIZE; i++)
for (j = 0; j < BOARD_SIZE; j++) {
boards[0][i][j].piece = empty;
boards[0][i][j].colour = white;
}
for (j = 0; j < BOARD_SIZE; j++) {
boards[0][1][j].piece = pawn;
/* boards[0][1][j].colour = white; */
boards[0][BOARD_SIZE - 2][j].piece = pawn;
boards[0][BOARD_SIZE - 2][j].colour = black;
}
for (j = 0; j < BOARD_SIZE; j++)
boards[0][BOARD_SIZE - 1][j].colour = black;
boards[0][0][0].piece = boards[0][0][7].piece = rook;
boards[0][7][0].piece = boards[0][7][7].piece = rook;
boards[0][0][1].piece = boards[0][0][6].piece = knight;
boards[0][7][1].piece = boards[0][7][6].piece = knight;
boards[0][0][2].piece = boards[0][0][5].piece = bishop;
boards[0][7][2].piece = boards[0][7][5].piece = bishop;
boards[0][0][3].piece = queen;
boards[0][7][3].piece = queen;
boards[0][0][4].piece = king;
boards[0][7][4].piece = king;
return;
}
/************************************************
* init_boards initializes the array of board *
************************************************/
void
init_boards (void)
{
boards = (Board *)calloc(BLOCKSIZE, sizeof (Board));
if (boards == NULL) {
fprintf (stderr, "ERROR: Unable to allocate "
"initial boards!\n");
exit(1);
}
number_of_allocated_boards = BLOCKSIZE;
number_of_used_boards = 0;
init_board();
next_board();
}
/************************************************
* print_board prints the board #n *
************************************************/
void
print_board (int n)
{
int i, j;
printf ("\n**abcdefgh**\n**--------**\n");
for (i = BOARD_SIZE; i > 0 ; i--) {
printf ("%i|", i);
for (j = 0; j < BOARD_SIZE; j++) {
printf ("%c", (boards[n][i-1][j].colour == white) ?
WhitePieces[boards[n][i-1][j].piece] :
BlackPieces[boards[n][i-1][j].piece]);
}
printf ("|%i\n", i);
}
printf ("**--------**\n**abcdefgh** ");
return;
}
/************************************************
* print_last_board prints the board *
* #number_of_used_boards-1 *
************************************************/
void
print_last_board (void)
{
print_board (number_of_used_boards-1);
}
/************************************************
* print_all_boards prints all boards *
************************************************/
void
print_all_boards (void)
{
int i;
for (i = 0; i < number_of_used_boards; i++) {
print_board (i);
}
}
/************************************************
* add_boards enlarges the array *
************************************************/
void add_boards (void) {
Board *newboards;
newboards = (Board *) realloc(boards,
(number_of_allocated_boards + BLOCKSIZE)
* sizeof (Board));
if (newboards == NULL) {
fprintf (stderr, "ERROR: out of memory");
exit(1);
}
number_of_allocated_boards += BLOCKSIZE;
}
/************************************************
* next_board moves to next board *
* note: we always keep an additional copy of *
* the last board *
************************************************/
void next_board (void) {
int i, j;
if (number_of_allocated_boards - 1 <= number_of_used_boards)
add_boards();
for (i = 0; i < BOARD_SIZE; i++) {
for (j = 0; j < BOARD_SIZE; j++) {
boards[number_of_used_boards + 1][i][j] =
boards[number_of_used_boards][i][j];
}
}
number_of_used_boards++;
}
/************************************************
* read_line reads a complete line storing n *
* chars *
************************************************/
int
read_line(char str[], int n)
{
char ch;
int i = 0;
while ((ch = getchar()) != '\n')
if (i < n)
str[i++] = ch;
str[i] = '\0';
return i;
}