This is a piece of a chess - engine which accomplishes the generation of all (yet unvalidated) moves given a legal board. However, I have the strong doubt this is well written. The following action are not yet included:
- Promoting
- Castling
- En passant.
This code:
#include "chess.h"
#include "odinutilities.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/*
* Stores all moves given a pawns position,the pawns color, and a valid board position in move_info
* Returns 0 if failed, otherwise 1. If a error occured, some valid moves might still be stored.
* e.p not added yet.
*/
char store_all_moves_of_pawn(char copy_board[8][8], char from_x, char from_y,
MOVE_DATA* move_info, char color) {
const char dy = (color + 1) ? 1 : -1;
const char to_y = from_y + dy;
for (char m = -1; m < 2; m++) {
const char to_x = from_x + m;
if ((to_x < 0) | (to_x > 7)) {
continue;
}
if (m != 0) {
//check if pawn can take left and right
if (((to_y >= 0) & (to_y <= 7)) & (to_x >= 0) & (to_x <= 7)
& ((copy_board[(int) to_y][(int) to_x] * color) < 0)) {
add_move_to_data(move_info,
create_move_string(from_x, from_y, to_x, to_y,
(char) 0));
}
} else {
//can pawn move forward
if (copy_board[(int) to_y][(int) to_x] == 0) {
add_move_to_data(move_info,
create_move_string(from_x, from_y, to_x, to_y,
(char) 0));
}
}
}
return 1;
}
/*
* Stores all moves given a rocks position, the rocks color, and a valid board position in move_info
* Returns 0 if failed, otherwise 1. If a error occured, some valid moves might still be stored.
*/
char store_all_moves_of_knight(char copy_board[8][8], char from_x, char from_y,
MOVE_DATA* move_info, char color) {
char no_error = 1;
char dx;
char dy;
char* p1 = &dx;
char* p2 = &dy;
//Compressed code using pointer arithmetic:
for (char i = 0; i < 2; i++) {
for (*p1 = -2; *p1 < 3; *p1 = *p1 + 4) {
for (*p2 = -1; *p2 < 2; *p2 = *p2 + 2) {
char to_x = from_x + dx;
char to_y = from_y + dy;
if (0 <= to_x & to_x < 8 & 0 <= to_y & to_y < 8) {
no_error = add_move_if_unused_by_equal_color(copy_board,
from_x, from_y, move_info, color, to_x, to_y);
if (!no_error)
return no_error;
}
}
}
p1 = &dy;
p2 = &dx;
}
return no_error;
}
/*
* Stores all moves given a rocks position, the rocks color, and a valid board position in move_info
* Returns 0 if failed, otherwise 1. If a error occured, some valid moves might still be stored.
*/
char store_all_moves_of_rock(char copy_board[8][8], char from_x, char from_y,
MOVE_DATA* move_info, char color) {
//Vertikal
//Up
char no_error = 1;
for (char dy = 1; from_y + dy < 8; dy++) {
char temp_field = copy_board[(int) from_y + dy][(int) from_x];
if (temp_field == 0) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x, from_y + dy,
(char) 0));
if (!no_error) {
return 0;
}
} else {
if ((!color & (temp_field > 0)) || (color & !(temp_field > 0))) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x, from_y + dy,
(char) 0));
}
if (!no_error) {
return 0;
}
break;
}
}
//Down
for (char dy = -1; from_y + dy >= 0; dy--) {
char temp_field = copy_board[(int) from_y + dy][(int) from_x];
if (temp_field == 0) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x, from_y + dy,
(char) 0));
if (!no_error) {
return 0;
}
} else {
if ((!color & (temp_field > 0)) || (color & !(temp_field > 0))) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x, from_y + dy,
(char) 0));
}
if (!no_error) {
return 0;
}
break;
}
}
//Horizontal
//Right
for (char dx = 1; from_x + dx < 8; dx++) {
char temp_field = copy_board[(int) from_y][(int) from_x + dx];
if (temp_field == 0) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x + dx, from_y,
(char) 0));
if (!no_error) {
return 0;
}
} else {
if ((!color & (temp_field > 0)) || (color & !(temp_field > 0))) {
add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x + dx, from_y,
(char) 0));
}
if (!no_error) {
return 0;
}
break;
}
}
//Left
for (char dx = -1; from_x + dx >= 0; dx--) {
char temp_field = copy_board[(int) from_y][(int) from_x + dx];
if (temp_field == 0) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x + dx, from_y,
(char) 0));
if (!no_error) {
return 0;
}
} else {
if ((!color & (temp_field > 0)) || (color & !(temp_field > 0))) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, from_x + dx, from_y,
(char) 0));
}
if (!no_error) {
return 0;
}
break;
}
}
return 1;
}
/*
* Stores all moves given a bishops position, the bishops color, and a valid board position in move_info
* Returns 0 if failed, otherwise 1. If a error occured, some valid moves might still be stored.
*/
char store_all_moves_of_bishop(char copy_board[8][8], char from_x, char from_y,
MOVE_DATA* move_info, char color) {
char no_error = generate_all_moves_of_bishops_direction(copy_board, from_x,
from_y, move_info, color, -1, -1);
if (!no_error)
return no_error;
no_error = generate_all_moves_of_bishops_direction(copy_board, from_x,
from_y, move_info, color, -1, 1);
if (!no_error)
return no_error;
no_error = generate_all_moves_of_bishops_direction(copy_board, from_x,
from_y, move_info, color, 1, -1);
if (!no_error)
return no_error;
no_error = generate_all_moves_of_bishops_direction(copy_board, from_x,
from_y, move_info, color, 1, 1);
return no_error;
}
/*
* Stores all moves given a queens position, the queens color, and a valid board position in move_info
* Returns 0 if failed, otherwise 1. If a error occured, some valid moves might still be stored.
*/
char store_all_moves_of_queen(char copy_board[8][8], char from_x, char from_y,
MOVE_DATA* move_info, char color) {
char no_error = store_all_moves_of_rock(copy_board, from_x, from_y,
move_info, color);
if (!no_error)
return no_error;
no_error = store_all_moves_of_bishop(copy_board, from_x, from_y, move_info,
color);
return no_error;
}
/*
* Stores all moves given a queens position, the queens color, and a valid board position in move_info
* Returns 0 if failed, otherwise 1. If a error occured, some valid moves might still be stored.
*/
char store_all_moves_of_king(char copy_board[8][8], char from_x, char from_y,
MOVE_DATA* move_info, char color) {
char no_error;
for (int i = -1; i < 2; i++) {
for (int k = -1; k < 2; k++) {
char to_x = from_x + k;
char to_y = from_y + i;
if (0 <= to_x & to_x < 8 & 0 <= to_y & to_y < 8) {
no_error = add_move_if_unused_by_equal_color(copy_board, from_x,
from_y, move_info, color, to_x, to_y);
if (!no_error)
return no_error;
}
}
}
return 1;
}
/*
* Returns all moves given a Board-State, including a legal board position. For illegal positions the
* behaviour is undefined. However, it is allowed to pass a position, where the color to move is checked.
*/
MOVE_DATA return_all_moves(BOARD_STATE* plegal_board_state,
char ignore_check) {
MOVE_DATA move_data;
move_data.array_size = MOVE_ARRAY_SIZE_BY_INIT;
move_data.used_array_size = 0;
move_data.moves = (char**) malloc(move_data.array_size * sizeof(char*));
char copy_board[8][8];
memcpy(copy_board, (plegal_board_state->board), sizeof(copy_board));
for (int i = 0; i < BOARD_LEN; i++) {
for (int k = 0; k < BOARD_LEN; k++) {
char piece = copy_board[i][k];
char color = piece > 0 ? 1 : -1;
if (color != plegal_board_state->to_move) {
continue;
}
switch (piece * color) {
char c;
case free_piece:
continue;
case pawn:
c = store_all_moves_of_pawn(copy_board, k, i, &move_data, color);
if (!c) {
perror("OutOfMemoryException.");
exit(EXIT_FAILURE);
}
continue;
case knight:
c = store_all_moves_of_knight(copy_board, k, i, &move_data, color);
if (!c) {
perror("OutOfMemoryException.");
exit(EXIT_FAILURE);
}
continue;
case bishop:
c = store_all_moves_of_bishop(copy_board, k, i, &move_data, color);
if (!c) {
perror("OutOfMemoryException.");
exit(EXIT_FAILURE);
}
continue;
case rock:
; //this is an empty statement since a label is not allowed before a declaration
c = store_all_moves_of_rock(copy_board, k, i, &move_data, color);
if (!c) {
perror("OutOfMemoryException.");
exit(EXIT_FAILURE);
}
continue;
case queen:
c = store_all_moves_of_queen(copy_board, k, i, &move_data, color);
if (!c) {
perror("OutOfMemoryException.");
exit(EXIT_FAILURE);
}
continue;
case king:
c = store_all_moves_of_king(copy_board, k, i, &move_data, color);
if (!c) {
perror("OutOfMemoryException.");
exit(EXIT_FAILURE);
}
continue;
default:
fprintf(stderr, "Unknown piece: %c on the board\nError.", piece);
exit(EXIT_FAILURE);
}
}
}
return move_data;
}
/*Merges to_be_added into to dest.
* If successful, to_be_added moves will be freed.
* Returns 1, if successful
* Returns 0, OutOfMemoryException
*/
char merge(MOVE_DATA* dest, MOVE_DATA* to_be_merged) {
void* c;
if (dest->array_size
< dest->used_array_size + to_be_merged->used_array_size) {
c = realloc(dest->moves,
(dest->used_array_size + to_be_merged->used_array_size)
* sizeof(char*));
if (!c) {
return 0;
} else {
dest->moves = (char**) c;
}
dest->array_size = dest->used_array_size
+ to_be_merged->used_array_size;
}
c = memcpy((dest->moves) + dest->used_array_size, to_be_merged->moves,
to_be_merged->used_array_size);
if (!c) {
return 0;
}
return 1;
}
/* Adds a move string to a MOVE_DATA
* If there is no more space left, space of the MOVE_DATA will be doubled.
* Returns 1, if successful
* Returns 0, OutOfMemoryException
*/
char add_move_to_data(MOVE_DATA* move_info, char* move) {
if (move_info->array_size == move_info->used_array_size) {
char** p = realloc(move_info->moves,
2 * (move_info->array_size) * sizeof(char*));
move_info->array_size = 2 * (move_info->array_size);
if (!p) {
return 0;
} else {
move_info->moves = (char**) p;
}
}
move_info->moves[move_info->used_array_size++] = move;
return 1;
}
char generate_all_moves_of_bishops_direction(char copy_board[8][8], char from_x,
char from_y, MOVE_DATA* move_info, char color, char dhorizontal,
char dvertical) {
char n = 1;
char to_x;
char to_y;
char no_error = 1;
while (((to_x = dhorizontal * n + from_x) < 8 & (to_x >= 0))
& (((to_y = dvertical * n + from_y) < 8) & (to_y >= 0))) {
if (copy_board[(int) to_y][(int) to_x] == 0) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, to_x, to_y, (char) 0));
} else {
if (color * copy_board[(int) to_y][(int) to_x] < 0) {
no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, to_x, to_y,
(char) 0));
}
break;
}
n++;
}
return no_error;
}
//Returns 1 if successful, else 0
/*
* NOTE THIS FUNCTION IS NOT CHECKING IF THE MOVE IS LEGAL. IT IS ONLY LOOKING IF THE FIELD IS USED BY ANOTHER
* PIECE OF EQUAL COLOR AND THEN ADDS THE MOVE OR NOT. IN BOTH CASES 1 WILL BE RETURNED.
*/
char add_move_if_unused_by_equal_color(char copy_board[8][8], char from_x,
char from_y, MOVE_DATA* move_info, char color, char to_x, char to_y) {
if (copy_board[to_y][to_x] * color <= 0) {
char no_error = add_move_to_data(move_info,
create_move_string(from_x, from_y, to_x, to_y, (char) 0));
return no_error;
}
return 1;
}
This is the header-file:
#ifndef BOARD_H
#define BOARD_H
#define BOARD_LEN 8
#define MOVE_ARRAY_SIZE_BY_INIT 20
#include <stdlib.h>
typedef struct {
char board[8][8];
char to_move;
char pieces_moved[6];
} BOARD_STATE;
typedef struct {
char** moves;
size_t array_size;
size_t used_array_size;
} MOVE_DATA;
char** return_all_moves(BOARD_STATE* pstate);
MOVE_DATA return_all_legal_moves(BOARD_STATE* pstate, char ignore_check);
char board_is_legal(BOARD_STATE* pstate);
char store_all_moves_of_pawn(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color);
char store_all_moves_of_bishop(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color);
char store_all_moves_of_rock(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color);
char store_all_moves_of_queen(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color);
char store_all_moves_of_king(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color);
char add_move_to_data(MOVE_DATA* move_info, char* move);
char merge(MOVE_DATA* dest, MOVE_DATA* to_be_merged);
char generate_all_moves_of_bishops_direction(char copy_board[8][8], char from_x, char from_y,
MOVE_DATA* move_info, char color, char dhorizontal, char dvertical);
char add_move_if_unused_by_equal_color(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color,
char to_x, char to_y);
#endif
- I am searching for a general advice for a better desgin of the engine.
- I am not looking for any optimizations yet.
- I would also love your comments about readability.
Board
,Point
,TeamColor
(an enum, iffy on the name), and possibly quite a few more. \$\endgroup\$ – Alexander Jul 31 '19 at 4:48