Piece of chess engine, which accomplishes move generationValidate Move Pattern ChessStarting a Clojure Chess EngineEnumerating Chess Piece MovesChessMetric - Topcoder ChallengeCastling move in ChessUnicode Chess PvP with Move ValidationChess engine in C++Python Amazon CheckmateMove-generation for chess in rustObject Oriented Chess Design In Kotlin

Do other countries guarantee freedoms that the United States does not have?

How do I calculate the difference in lens reach between a superzoom compact and a DSLR zoom lens?

What does Apple mean by "This may decrease battery life"?

Non-OR journals which regularly publish OR research

What are the uses and limitations of Persuasion, Insight, and Deception against other PCs?

Could one become a successful researcher by writing some really good papers while being outside academia?

Infeasibility in mathematical optimization models

Can I call myself an assistant professor without a PhD?

How should an administrative assistant reply to student addressing them as "Professor" or "Doctor"?

Does a code snippet compile? Or does it get compiled?

Look mom! I made my own (Base 10) numeral system!

Why isn’t SHA-3 in wider use?

Ex-contractor published company source code and secrets online

Are any jet engines used in combat aircraft water cooled?

How quickly could a country build a tall concrete wall around a city?

A stranger from Norway wants to have money delivered to me

Does two puncture wounds mean venomous snake?

Is TA-ing worth the opportunity cost?

Strangeness with gears

How to say "Third time lucky" in Latin

How do I explain to a team that the project they will work on for six months will certainly be cancelled?

Are there any financial disadvantages to living significantly "below your means"?

Does this Foo machine halt?

Performance of a branch and bound algorithm VS branch-cut-heuristics



Piece of chess engine, which accomplishes move generation


Validate Move Pattern ChessStarting a Clojure Chess EngineEnumerating Chess Piece MovesChessMetric - Topcoder ChallengeCastling move in ChessUnicode Chess PvP with Move ValidationChess engine in C++Python Amazon CheckmateMove-generation for chess in rustObject Oriented Chess Design In Kotlin






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








10












$begingroup$


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:



  1. Promoting

  2. Castling

  3. 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++) (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 (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 (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 (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))

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 boardnError.", 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


  1. I am searching for a general advice for a better desgin of the
    engine.

  2. I am not looking for any optimizations yet.

  3. I would also love your comments about readability.









share|improve this question











$endgroup$









  • 1




    $begingroup$
    You have a lot of primitive obsession. Make a lot more data types, and replace all these raw types being passed around everywhere. I see a dire need for at least Board, Point, TeamColor (an enum, iffy on the name), and possibly quite a few more.
    $endgroup$
    – Alexander
    Jul 31 at 4:48






  • 1




    $begingroup$
    "which accomplishes the generation of all (yet unvalidated) moves" That's a lot of moves. Did you mean all moves possible in one turn instead?
    $endgroup$
    – Mast
    Jul 31 at 7:39






  • 1




    $begingroup$
    It's not enough for an answer, but I think you copied and pasted your comment from the rook function on to the knight one and forgot to change 'rook' to 'knight'.
    $endgroup$
    – John Gowers
    Jul 31 at 14:59










  • $begingroup$
    @Mast Yes, I thought this was kinda obvious. I will change it :)
    $endgroup$
    – TVSuchty
    Aug 1 at 12:46










  • $begingroup$
    @JohnGowers Exactly, thanky you!
    $endgroup$
    – TVSuchty
    Aug 1 at 12:47

















10












$begingroup$


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:



  1. Promoting

  2. Castling

  3. 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++) (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 (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 (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 (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))

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 boardnError.", 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


  1. I am searching for a general advice for a better desgin of the
    engine.

  2. I am not looking for any optimizations yet.

  3. I would also love your comments about readability.









share|improve this question











$endgroup$









  • 1




    $begingroup$
    You have a lot of primitive obsession. Make a lot more data types, and replace all these raw types being passed around everywhere. I see a dire need for at least Board, Point, TeamColor (an enum, iffy on the name), and possibly quite a few more.
    $endgroup$
    – Alexander
    Jul 31 at 4:48






  • 1




    $begingroup$
    "which accomplishes the generation of all (yet unvalidated) moves" That's a lot of moves. Did you mean all moves possible in one turn instead?
    $endgroup$
    – Mast
    Jul 31 at 7:39






  • 1




    $begingroup$
    It's not enough for an answer, but I think you copied and pasted your comment from the rook function on to the knight one and forgot to change 'rook' to 'knight'.
    $endgroup$
    – John Gowers
    Jul 31 at 14:59










  • $begingroup$
    @Mast Yes, I thought this was kinda obvious. I will change it :)
    $endgroup$
    – TVSuchty
    Aug 1 at 12:46










  • $begingroup$
    @JohnGowers Exactly, thanky you!
    $endgroup$
    – TVSuchty
    Aug 1 at 12:47













10












10








10


4



$begingroup$


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:



  1. Promoting

  2. Castling

  3. 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++) (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 (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 (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 (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))

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 boardnError.", 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


  1. I am searching for a general advice for a better desgin of the
    engine.

  2. I am not looking for any optimizations yet.

  3. I would also love your comments about readability.









share|improve this question











$endgroup$




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:



  1. Promoting

  2. Castling

  3. 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++) (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 (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 (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 (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))

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 boardnError.", 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


  1. I am searching for a general advice for a better desgin of the
    engine.

  2. I am not looking for any optimizations yet.

  3. I would also love your comments about readability.






c chess






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 30 at 16:24









200_success

135k21 gold badges173 silver badges443 bronze badges




135k21 gold badges173 silver badges443 bronze badges










asked Jul 30 at 13:13









TVSuchtyTVSuchty

19111 bronze badges




19111 bronze badges










  • 1




    $begingroup$
    You have a lot of primitive obsession. Make a lot more data types, and replace all these raw types being passed around everywhere. I see a dire need for at least Board, Point, TeamColor (an enum, iffy on the name), and possibly quite a few more.
    $endgroup$
    – Alexander
    Jul 31 at 4:48






  • 1




    $begingroup$
    "which accomplishes the generation of all (yet unvalidated) moves" That's a lot of moves. Did you mean all moves possible in one turn instead?
    $endgroup$
    – Mast
    Jul 31 at 7:39






  • 1




    $begingroup$
    It's not enough for an answer, but I think you copied and pasted your comment from the rook function on to the knight one and forgot to change 'rook' to 'knight'.
    $endgroup$
    – John Gowers
    Jul 31 at 14:59










  • $begingroup$
    @Mast Yes, I thought this was kinda obvious. I will change it :)
    $endgroup$
    – TVSuchty
    Aug 1 at 12:46










  • $begingroup$
    @JohnGowers Exactly, thanky you!
    $endgroup$
    – TVSuchty
    Aug 1 at 12:47












  • 1




    $begingroup$
    You have a lot of primitive obsession. Make a lot more data types, and replace all these raw types being passed around everywhere. I see a dire need for at least Board, Point, TeamColor (an enum, iffy on the name), and possibly quite a few more.
    $endgroup$
    – Alexander
    Jul 31 at 4:48






  • 1




    $begingroup$
    "which accomplishes the generation of all (yet unvalidated) moves" That's a lot of moves. Did you mean all moves possible in one turn instead?
    $endgroup$
    – Mast
    Jul 31 at 7:39






  • 1




    $begingroup$
    It's not enough for an answer, but I think you copied and pasted your comment from the rook function on to the knight one and forgot to change 'rook' to 'knight'.
    $endgroup$
    – John Gowers
    Jul 31 at 14:59










  • $begingroup$
    @Mast Yes, I thought this was kinda obvious. I will change it :)
    $endgroup$
    – TVSuchty
    Aug 1 at 12:46










  • $begingroup$
    @JohnGowers Exactly, thanky you!
    $endgroup$
    – TVSuchty
    Aug 1 at 12:47







1




1




$begingroup$
You have a lot of primitive obsession. Make a lot more data types, and replace all these raw types being passed around everywhere. I see a dire need for at least Board, Point, TeamColor (an enum, iffy on the name), and possibly quite a few more.
$endgroup$
– Alexander
Jul 31 at 4:48




$begingroup$
You have a lot of primitive obsession. Make a lot more data types, and replace all these raw types being passed around everywhere. I see a dire need for at least Board, Point, TeamColor (an enum, iffy on the name), and possibly quite a few more.
$endgroup$
– Alexander
Jul 31 at 4:48




1




1




$begingroup$
"which accomplishes the generation of all (yet unvalidated) moves" That's a lot of moves. Did you mean all moves possible in one turn instead?
$endgroup$
– Mast
Jul 31 at 7:39




$begingroup$
"which accomplishes the generation of all (yet unvalidated) moves" That's a lot of moves. Did you mean all moves possible in one turn instead?
$endgroup$
– Mast
Jul 31 at 7:39




1




1




$begingroup$
It's not enough for an answer, but I think you copied and pasted your comment from the rook function on to the knight one and forgot to change 'rook' to 'knight'.
$endgroup$
– John Gowers
Jul 31 at 14:59




$begingroup$
It's not enough for an answer, but I think you copied and pasted your comment from the rook function on to the knight one and forgot to change 'rook' to 'knight'.
$endgroup$
– John Gowers
Jul 31 at 14:59












$begingroup$
@Mast Yes, I thought this was kinda obvious. I will change it :)
$endgroup$
– TVSuchty
Aug 1 at 12:46




$begingroup$
@Mast Yes, I thought this was kinda obvious. I will change it :)
$endgroup$
– TVSuchty
Aug 1 at 12:46












$begingroup$
@JohnGowers Exactly, thanky you!
$endgroup$
– TVSuchty
Aug 1 at 12:47




$begingroup$
@JohnGowers Exactly, thanky you!
$endgroup$
– TVSuchty
Aug 1 at 12:47










2 Answers
2






active

oldest

votes


















10












$begingroup$


return type



char should only be user for characters, as it's name says. unsigned char for characters or for aliasing other types. For everything else, use anything else.



If you want (u)int8_t, use <stdint.h>, and if you don't have that header, feel free to write your own typedef (enclosed in an #if).



But for error codes, the best is to use good old int. Everybody uses int for error codes, so you won't mess with their brains when they wonder why you did use char :)




Function return values and names (source: Linux Kernel Coding Style)



Functions can return values of many different kinds, and one of the most common is a value indicating whether the function succeeded or failed. Such a value can be represented as an error-code integer (-Exxx = failure, 0 = success) or a succeeded boolean (0 = failure, non-zero = success).



Mixing up these two sorts of representations is a fertile source of difficult-to-find bugs. If the C language included a strong distinction between integers and booleans then the compiler would find these mistakes for us... but it doesn’t. To help prevent such bugs, always follow this convention:



If the name of a function is an action or an
imperative command, the function should
return an error-code integer. If the name is a
predicate, the function should return a
"succeeded" boolean.


For example, add work is a command, and the add_work() function returns 0 for success or -EBUSY for failure. In the same way, PCI device present is a predicate, and the pci_dev_present() function returns true if it succeeds in finding a matching device or false if it doesn’t.




no_error



The variable no_error is misleading: it can hold an error code. Probably the origin of the name was the inverted error return codes. With non-zero error codes better names are: error or status.




copy_board



The name of the parameter copy_board is misleading, given that it's not a copy, but a pointer to the original board.




function names short



For making function names shorter, you can omit prepositions in them (when they are obvious). For example, store_all_moves_of_pawn() -> store_moves_pawn()




#pragma once



Although it has its own problems (only if your build configuration is completely broken, actually), it is less error-prone than typical #ifndef&#define include guards.



It's not standard, but most compilers accept it.



Just write this line at the beginning of the header:



#pragma once


#pragma once vs include guards




Names and Order of Includes (source: Google C++ Style Guide)



Use standard order for readability and to avoid hidden dependencies: Related header, C library, C++ library, other libraries' .h, your project's .h.



All of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). For example, google-awesome-project/src/base/logging.h should be included as:



#include "base/logging.h" 


In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows:



dir2/foo2.h.



A blank line



C system files.



C++ system files.



A blank line



Other libraries' .h files.



Your project's .h files.



Note that any adjacent blank lines should be collapsed.



With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. Thus, this rule ensures that build breaks show up first for the people working on these files, not for innocent people in other packages.



dir/foo.cc and dir2/foo2.h are usually in the same directory (e.g. base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too.



Within each section the includes should be ordered alphabetically.



  • In your case this would mean this order of includes:

#include "chess.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "odinutilities.h"



unnecessary casts



Most (if not all) the casts you use are unnecessary. Casts usually lead to bugs, remove them all if there's not a good reason for them to be.




ptrdiff_t



The proper type for pointer arithmetics is ptrdiff_t, not char nor int.



Variables such as to_y should be declared of this type.



You will need #include <stddef.h>






share|improve this answer











$endgroup$














  • $begingroup$
    Hey! Thanks for your answer! I thought a processor will need less time adding chars instead of integers? Is this true? If I typedef it, would not I use char anyway just by an alias?
    $endgroup$
    – TVSuchty
    Jul 30 at 14:00











  • $begingroup$
    @TVSuchty No, it isn't true (unless you have an 8-bit processor ;-)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:04






  • 1




    $begingroup$
    @TVSuchty In C the int and unsigned int type will usually be the word size of the processor so all the native operations for the processor will run faster with int. char and short might be used in arrays where memory is tight.
    $endgroup$
    – pacmaninbw
    Jul 30 at 14:08






  • 1




    $begingroup$
    @pacmaninbw That's why I put the link. But if the compiler accepts it (most of them, since a decade ago), it's very valid. And when you forget to change the FILE_MACRO_H name after copy&paste (it happened to me more than once), it's a pain in the ass until you find it. #pragma doesn't have that problem. The link provides all this info and discussion, and anyone is of course free to use whatever, and I just pointed to the info just in case he didn't know :)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:37







  • 3




    $begingroup$
    This is totally bike shedding, but I disagree on the suggestion to change store_all_moves_of_pawn() to store_moves_pawn(). Perhaps store_pawn_moves() is fine, but my personal fave is store_all_pawn_moves. I would recommend a more expressive approach. Keystrokes are free, and monitors are giant, there's really no need to be pinched on character count.
    $endgroup$
    – Alexander
    Jul 31 at 4:51


















4












$begingroup$

First, interesting code!



I agree with most of what @CacahueteFrito wrote in his review except for the #pragma once item. The method you are using is more portable. I sometimes use #pragma once when the editor defaults to it on windows (Visual Studio), but not for C++.



I will primarily address style.



Code Consistency

The code is consistently indented, which is great, but the use of braces ( and ) in if statements is inconsistent. There are many places where braces are used around a single statement, but there are many places where braces aren't used around a single statement. It is more readable and maintainable when the code is consistent. Braces around a single statement are a good practice because quite often a new line of code needs to be inserted during maintenance.



Always Test the Return Value of Memory Allocation Functions

In most of the cases where memory is allocated the code is testing the return value, however, in the function MOVE_DATA return_all_moves(BOARD_STATE* plegal_board_state, char ignore_check) there is a call to malloc(size_t size) that is not tested. The function malloc() may also return NULL if there is not enough memory.



It might be better if the code was



char **tmp = malloc(move_data.array_size * sizeof(*p));
if (tmp)
move_data.moves = tmp;

else
// needs to be defined



because only the type of tmp needs to change if the type of move_data.moves is changed. This would be true for all the memory allocation performed in the program.



Casting Malloc

In modern C the functions malloc(), calloc() and realloc() return void *. It is not necessary to cast the memory returned by these statement to the proper type.



Readability

The code would be easier to read if there were some blank lines between blocks of code, such as after variable declarations at the top of the function, after a if then else block, after each of the cases in the switch statement.



Function Complexity

The function char store_all_moves_of_rock(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color) is very complex and could be broken up into at least 4 sub functions, up, down, left and right. This function is probably misnamed, I believe is should be all_moves_of_rook rather than rock.






share|improve this answer









$endgroup$














  • $begingroup$
    Hey, thank you for your critique! Glad you liked it. I will go for it!
    $endgroup$
    – TVSuchty
    Jul 30 at 15:38











  • $begingroup$
    Lol, I never noticed the difference between rock and rook. Thanks for educating me in English :P
    $endgroup$
    – TVSuchty
    Jul 30 at 16:22










  • $begingroup$
    Just a note that on many 64 bit systems (at least Linux and Mac I think, not sure of Windows), with sane environment settings, any reasonable use of malloc will never return NULL. Program(s) will start being killed if system runs out of memory and swap. A reasonable program will not run out of its own 64 bit virtual address space. It's still good to check it of course, but it's not worth putting much effort into handling it gracefully (just abort() or something).
    $endgroup$
    – hyde
    Jul 30 at 23:10











  • $begingroup$
    @hyde and if it is an embedded processor that doesn't have all that much memory?
    $endgroup$
    – pacmaninbw
    Jul 31 at 0:46






  • 1




    $begingroup$
    @pacmaninbw In that case you should really consider if you want to use a real operating system (such as embedded Linux), and research how you can configure and control malloc behavior (such as make it return NULL reliably, if your application is such that you can actually do something useful about it).
    $endgroup$
    – hyde
    Jul 31 at 6:17













Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f225191%2fpiece-of-chess-engine-which-accomplishes-move-generation%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









10












$begingroup$


return type



char should only be user for characters, as it's name says. unsigned char for characters or for aliasing other types. For everything else, use anything else.



If you want (u)int8_t, use <stdint.h>, and if you don't have that header, feel free to write your own typedef (enclosed in an #if).



But for error codes, the best is to use good old int. Everybody uses int for error codes, so you won't mess with their brains when they wonder why you did use char :)




Function return values and names (source: Linux Kernel Coding Style)



Functions can return values of many different kinds, and one of the most common is a value indicating whether the function succeeded or failed. Such a value can be represented as an error-code integer (-Exxx = failure, 0 = success) or a succeeded boolean (0 = failure, non-zero = success).



Mixing up these two sorts of representations is a fertile source of difficult-to-find bugs. If the C language included a strong distinction between integers and booleans then the compiler would find these mistakes for us... but it doesn’t. To help prevent such bugs, always follow this convention:



If the name of a function is an action or an
imperative command, the function should
return an error-code integer. If the name is a
predicate, the function should return a
"succeeded" boolean.


For example, add work is a command, and the add_work() function returns 0 for success or -EBUSY for failure. In the same way, PCI device present is a predicate, and the pci_dev_present() function returns true if it succeeds in finding a matching device or false if it doesn’t.




no_error



The variable no_error is misleading: it can hold an error code. Probably the origin of the name was the inverted error return codes. With non-zero error codes better names are: error or status.




copy_board



The name of the parameter copy_board is misleading, given that it's not a copy, but a pointer to the original board.




function names short



For making function names shorter, you can omit prepositions in them (when they are obvious). For example, store_all_moves_of_pawn() -> store_moves_pawn()




#pragma once



Although it has its own problems (only if your build configuration is completely broken, actually), it is less error-prone than typical #ifndef&#define include guards.



It's not standard, but most compilers accept it.



Just write this line at the beginning of the header:



#pragma once


#pragma once vs include guards




Names and Order of Includes (source: Google C++ Style Guide)



Use standard order for readability and to avoid hidden dependencies: Related header, C library, C++ library, other libraries' .h, your project's .h.



All of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). For example, google-awesome-project/src/base/logging.h should be included as:



#include "base/logging.h" 


In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows:



dir2/foo2.h.



A blank line



C system files.



C++ system files.



A blank line



Other libraries' .h files.



Your project's .h files.



Note that any adjacent blank lines should be collapsed.



With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. Thus, this rule ensures that build breaks show up first for the people working on these files, not for innocent people in other packages.



dir/foo.cc and dir2/foo2.h are usually in the same directory (e.g. base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too.



Within each section the includes should be ordered alphabetically.



  • In your case this would mean this order of includes:

#include "chess.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "odinutilities.h"



unnecessary casts



Most (if not all) the casts you use are unnecessary. Casts usually lead to bugs, remove them all if there's not a good reason for them to be.




ptrdiff_t



The proper type for pointer arithmetics is ptrdiff_t, not char nor int.



Variables such as to_y should be declared of this type.



You will need #include <stddef.h>






share|improve this answer











$endgroup$














  • $begingroup$
    Hey! Thanks for your answer! I thought a processor will need less time adding chars instead of integers? Is this true? If I typedef it, would not I use char anyway just by an alias?
    $endgroup$
    – TVSuchty
    Jul 30 at 14:00











  • $begingroup$
    @TVSuchty No, it isn't true (unless you have an 8-bit processor ;-)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:04






  • 1




    $begingroup$
    @TVSuchty In C the int and unsigned int type will usually be the word size of the processor so all the native operations for the processor will run faster with int. char and short might be used in arrays where memory is tight.
    $endgroup$
    – pacmaninbw
    Jul 30 at 14:08






  • 1




    $begingroup$
    @pacmaninbw That's why I put the link. But if the compiler accepts it (most of them, since a decade ago), it's very valid. And when you forget to change the FILE_MACRO_H name after copy&paste (it happened to me more than once), it's a pain in the ass until you find it. #pragma doesn't have that problem. The link provides all this info and discussion, and anyone is of course free to use whatever, and I just pointed to the info just in case he didn't know :)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:37







  • 3




    $begingroup$
    This is totally bike shedding, but I disagree on the suggestion to change store_all_moves_of_pawn() to store_moves_pawn(). Perhaps store_pawn_moves() is fine, but my personal fave is store_all_pawn_moves. I would recommend a more expressive approach. Keystrokes are free, and monitors are giant, there's really no need to be pinched on character count.
    $endgroup$
    – Alexander
    Jul 31 at 4:51















10












$begingroup$


return type



char should only be user for characters, as it's name says. unsigned char for characters or for aliasing other types. For everything else, use anything else.



If you want (u)int8_t, use <stdint.h>, and if you don't have that header, feel free to write your own typedef (enclosed in an #if).



But for error codes, the best is to use good old int. Everybody uses int for error codes, so you won't mess with their brains when they wonder why you did use char :)




Function return values and names (source: Linux Kernel Coding Style)



Functions can return values of many different kinds, and one of the most common is a value indicating whether the function succeeded or failed. Such a value can be represented as an error-code integer (-Exxx = failure, 0 = success) or a succeeded boolean (0 = failure, non-zero = success).



Mixing up these two sorts of representations is a fertile source of difficult-to-find bugs. If the C language included a strong distinction between integers and booleans then the compiler would find these mistakes for us... but it doesn’t. To help prevent such bugs, always follow this convention:



If the name of a function is an action or an
imperative command, the function should
return an error-code integer. If the name is a
predicate, the function should return a
"succeeded" boolean.


For example, add work is a command, and the add_work() function returns 0 for success or -EBUSY for failure. In the same way, PCI device present is a predicate, and the pci_dev_present() function returns true if it succeeds in finding a matching device or false if it doesn’t.




no_error



The variable no_error is misleading: it can hold an error code. Probably the origin of the name was the inverted error return codes. With non-zero error codes better names are: error or status.




copy_board



The name of the parameter copy_board is misleading, given that it's not a copy, but a pointer to the original board.




function names short



For making function names shorter, you can omit prepositions in them (when they are obvious). For example, store_all_moves_of_pawn() -> store_moves_pawn()




#pragma once



Although it has its own problems (only if your build configuration is completely broken, actually), it is less error-prone than typical #ifndef&#define include guards.



It's not standard, but most compilers accept it.



Just write this line at the beginning of the header:



#pragma once


#pragma once vs include guards




Names and Order of Includes (source: Google C++ Style Guide)



Use standard order for readability and to avoid hidden dependencies: Related header, C library, C++ library, other libraries' .h, your project's .h.



All of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). For example, google-awesome-project/src/base/logging.h should be included as:



#include "base/logging.h" 


In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows:



dir2/foo2.h.



A blank line



C system files.



C++ system files.



A blank line



Other libraries' .h files.



Your project's .h files.



Note that any adjacent blank lines should be collapsed.



With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. Thus, this rule ensures that build breaks show up first for the people working on these files, not for innocent people in other packages.



dir/foo.cc and dir2/foo2.h are usually in the same directory (e.g. base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too.



Within each section the includes should be ordered alphabetically.



  • In your case this would mean this order of includes:

#include "chess.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "odinutilities.h"



unnecessary casts



Most (if not all) the casts you use are unnecessary. Casts usually lead to bugs, remove them all if there's not a good reason for them to be.




ptrdiff_t



The proper type for pointer arithmetics is ptrdiff_t, not char nor int.



Variables such as to_y should be declared of this type.



You will need #include <stddef.h>






share|improve this answer











$endgroup$














  • $begingroup$
    Hey! Thanks for your answer! I thought a processor will need less time adding chars instead of integers? Is this true? If I typedef it, would not I use char anyway just by an alias?
    $endgroup$
    – TVSuchty
    Jul 30 at 14:00











  • $begingroup$
    @TVSuchty No, it isn't true (unless you have an 8-bit processor ;-)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:04






  • 1




    $begingroup$
    @TVSuchty In C the int and unsigned int type will usually be the word size of the processor so all the native operations for the processor will run faster with int. char and short might be used in arrays where memory is tight.
    $endgroup$
    – pacmaninbw
    Jul 30 at 14:08






  • 1




    $begingroup$
    @pacmaninbw That's why I put the link. But if the compiler accepts it (most of them, since a decade ago), it's very valid. And when you forget to change the FILE_MACRO_H name after copy&paste (it happened to me more than once), it's a pain in the ass until you find it. #pragma doesn't have that problem. The link provides all this info and discussion, and anyone is of course free to use whatever, and I just pointed to the info just in case he didn't know :)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:37







  • 3




    $begingroup$
    This is totally bike shedding, but I disagree on the suggestion to change store_all_moves_of_pawn() to store_moves_pawn(). Perhaps store_pawn_moves() is fine, but my personal fave is store_all_pawn_moves. I would recommend a more expressive approach. Keystrokes are free, and monitors are giant, there's really no need to be pinched on character count.
    $endgroup$
    – Alexander
    Jul 31 at 4:51













10












10








10





$begingroup$


return type



char should only be user for characters, as it's name says. unsigned char for characters or for aliasing other types. For everything else, use anything else.



If you want (u)int8_t, use <stdint.h>, and if you don't have that header, feel free to write your own typedef (enclosed in an #if).



But for error codes, the best is to use good old int. Everybody uses int for error codes, so you won't mess with their brains when they wonder why you did use char :)




Function return values and names (source: Linux Kernel Coding Style)



Functions can return values of many different kinds, and one of the most common is a value indicating whether the function succeeded or failed. Such a value can be represented as an error-code integer (-Exxx = failure, 0 = success) or a succeeded boolean (0 = failure, non-zero = success).



Mixing up these two sorts of representations is a fertile source of difficult-to-find bugs. If the C language included a strong distinction between integers and booleans then the compiler would find these mistakes for us... but it doesn’t. To help prevent such bugs, always follow this convention:



If the name of a function is an action or an
imperative command, the function should
return an error-code integer. If the name is a
predicate, the function should return a
"succeeded" boolean.


For example, add work is a command, and the add_work() function returns 0 for success or -EBUSY for failure. In the same way, PCI device present is a predicate, and the pci_dev_present() function returns true if it succeeds in finding a matching device or false if it doesn’t.




no_error



The variable no_error is misleading: it can hold an error code. Probably the origin of the name was the inverted error return codes. With non-zero error codes better names are: error or status.




copy_board



The name of the parameter copy_board is misleading, given that it's not a copy, but a pointer to the original board.




function names short



For making function names shorter, you can omit prepositions in them (when they are obvious). For example, store_all_moves_of_pawn() -> store_moves_pawn()




#pragma once



Although it has its own problems (only if your build configuration is completely broken, actually), it is less error-prone than typical #ifndef&#define include guards.



It's not standard, but most compilers accept it.



Just write this line at the beginning of the header:



#pragma once


#pragma once vs include guards




Names and Order of Includes (source: Google C++ Style Guide)



Use standard order for readability and to avoid hidden dependencies: Related header, C library, C++ library, other libraries' .h, your project's .h.



All of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). For example, google-awesome-project/src/base/logging.h should be included as:



#include "base/logging.h" 


In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows:



dir2/foo2.h.



A blank line



C system files.



C++ system files.



A blank line



Other libraries' .h files.



Your project's .h files.



Note that any adjacent blank lines should be collapsed.



With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. Thus, this rule ensures that build breaks show up first for the people working on these files, not for innocent people in other packages.



dir/foo.cc and dir2/foo2.h are usually in the same directory (e.g. base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too.



Within each section the includes should be ordered alphabetically.



  • In your case this would mean this order of includes:

#include "chess.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "odinutilities.h"



unnecessary casts



Most (if not all) the casts you use are unnecessary. Casts usually lead to bugs, remove them all if there's not a good reason for them to be.




ptrdiff_t



The proper type for pointer arithmetics is ptrdiff_t, not char nor int.



Variables such as to_y should be declared of this type.



You will need #include <stddef.h>






share|improve this answer











$endgroup$




return type



char should only be user for characters, as it's name says. unsigned char for characters or for aliasing other types. For everything else, use anything else.



If you want (u)int8_t, use <stdint.h>, and if you don't have that header, feel free to write your own typedef (enclosed in an #if).



But for error codes, the best is to use good old int. Everybody uses int for error codes, so you won't mess with their brains when they wonder why you did use char :)




Function return values and names (source: Linux Kernel Coding Style)



Functions can return values of many different kinds, and one of the most common is a value indicating whether the function succeeded or failed. Such a value can be represented as an error-code integer (-Exxx = failure, 0 = success) or a succeeded boolean (0 = failure, non-zero = success).



Mixing up these two sorts of representations is a fertile source of difficult-to-find bugs. If the C language included a strong distinction between integers and booleans then the compiler would find these mistakes for us... but it doesn’t. To help prevent such bugs, always follow this convention:



If the name of a function is an action or an
imperative command, the function should
return an error-code integer. If the name is a
predicate, the function should return a
"succeeded" boolean.


For example, add work is a command, and the add_work() function returns 0 for success or -EBUSY for failure. In the same way, PCI device present is a predicate, and the pci_dev_present() function returns true if it succeeds in finding a matching device or false if it doesn’t.




no_error



The variable no_error is misleading: it can hold an error code. Probably the origin of the name was the inverted error return codes. With non-zero error codes better names are: error or status.




copy_board



The name of the parameter copy_board is misleading, given that it's not a copy, but a pointer to the original board.




function names short



For making function names shorter, you can omit prepositions in them (when they are obvious). For example, store_all_moves_of_pawn() -> store_moves_pawn()




#pragma once



Although it has its own problems (only if your build configuration is completely broken, actually), it is less error-prone than typical #ifndef&#define include guards.



It's not standard, but most compilers accept it.



Just write this line at the beginning of the header:



#pragma once


#pragma once vs include guards




Names and Order of Includes (source: Google C++ Style Guide)



Use standard order for readability and to avoid hidden dependencies: Related header, C library, C++ library, other libraries' .h, your project's .h.



All of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). For example, google-awesome-project/src/base/logging.h should be included as:



#include "base/logging.h" 


In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows:



dir2/foo2.h.



A blank line



C system files.



C++ system files.



A blank line



Other libraries' .h files.



Your project's .h files.



Note that any adjacent blank lines should be collapsed.



With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. Thus, this rule ensures that build breaks show up first for the people working on these files, not for innocent people in other packages.



dir/foo.cc and dir2/foo2.h are usually in the same directory (e.g. base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too.



Within each section the includes should be ordered alphabetically.



  • In your case this would mean this order of includes:

#include "chess.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "odinutilities.h"



unnecessary casts



Most (if not all) the casts you use are unnecessary. Casts usually lead to bugs, remove them all if there's not a good reason for them to be.




ptrdiff_t



The proper type for pointer arithmetics is ptrdiff_t, not char nor int.



Variables such as to_y should be declared of this type.



You will need #include <stddef.h>







share|improve this answer














share|improve this answer



share|improve this answer








edited Jul 31 at 6:16

























answered Jul 30 at 13:56









Cacahuete FritoCacahuete Frito

1,1682 silver badges15 bronze badges




1,1682 silver badges15 bronze badges














  • $begingroup$
    Hey! Thanks for your answer! I thought a processor will need less time adding chars instead of integers? Is this true? If I typedef it, would not I use char anyway just by an alias?
    $endgroup$
    – TVSuchty
    Jul 30 at 14:00











  • $begingroup$
    @TVSuchty No, it isn't true (unless you have an 8-bit processor ;-)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:04






  • 1




    $begingroup$
    @TVSuchty In C the int and unsigned int type will usually be the word size of the processor so all the native operations for the processor will run faster with int. char and short might be used in arrays where memory is tight.
    $endgroup$
    – pacmaninbw
    Jul 30 at 14:08






  • 1




    $begingroup$
    @pacmaninbw That's why I put the link. But if the compiler accepts it (most of them, since a decade ago), it's very valid. And when you forget to change the FILE_MACRO_H name after copy&paste (it happened to me more than once), it's a pain in the ass until you find it. #pragma doesn't have that problem. The link provides all this info and discussion, and anyone is of course free to use whatever, and I just pointed to the info just in case he didn't know :)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:37







  • 3




    $begingroup$
    This is totally bike shedding, but I disagree on the suggestion to change store_all_moves_of_pawn() to store_moves_pawn(). Perhaps store_pawn_moves() is fine, but my personal fave is store_all_pawn_moves. I would recommend a more expressive approach. Keystrokes are free, and monitors are giant, there's really no need to be pinched on character count.
    $endgroup$
    – Alexander
    Jul 31 at 4:51
















  • $begingroup$
    Hey! Thanks for your answer! I thought a processor will need less time adding chars instead of integers? Is this true? If I typedef it, would not I use char anyway just by an alias?
    $endgroup$
    – TVSuchty
    Jul 30 at 14:00











  • $begingroup$
    @TVSuchty No, it isn't true (unless you have an 8-bit processor ;-)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:04






  • 1




    $begingroup$
    @TVSuchty In C the int and unsigned int type will usually be the word size of the processor so all the native operations for the processor will run faster with int. char and short might be used in arrays where memory is tight.
    $endgroup$
    – pacmaninbw
    Jul 30 at 14:08






  • 1




    $begingroup$
    @pacmaninbw That's why I put the link. But if the compiler accepts it (most of them, since a decade ago), it's very valid. And when you forget to change the FILE_MACRO_H name after copy&paste (it happened to me more than once), it's a pain in the ass until you find it. #pragma doesn't have that problem. The link provides all this info and discussion, and anyone is of course free to use whatever, and I just pointed to the info just in case he didn't know :)
    $endgroup$
    – Cacahuete Frito
    Jul 30 at 14:37







  • 3




    $begingroup$
    This is totally bike shedding, but I disagree on the suggestion to change store_all_moves_of_pawn() to store_moves_pawn(). Perhaps store_pawn_moves() is fine, but my personal fave is store_all_pawn_moves. I would recommend a more expressive approach. Keystrokes are free, and monitors are giant, there's really no need to be pinched on character count.
    $endgroup$
    – Alexander
    Jul 31 at 4:51















$begingroup$
Hey! Thanks for your answer! I thought a processor will need less time adding chars instead of integers? Is this true? If I typedef it, would not I use char anyway just by an alias?
$endgroup$
– TVSuchty
Jul 30 at 14:00





$begingroup$
Hey! Thanks for your answer! I thought a processor will need less time adding chars instead of integers? Is this true? If I typedef it, would not I use char anyway just by an alias?
$endgroup$
– TVSuchty
Jul 30 at 14:00













$begingroup$
@TVSuchty No, it isn't true (unless you have an 8-bit processor ;-)
$endgroup$
– Cacahuete Frito
Jul 30 at 14:04




$begingroup$
@TVSuchty No, it isn't true (unless you have an 8-bit processor ;-)
$endgroup$
– Cacahuete Frito
Jul 30 at 14:04




1




1




$begingroup$
@TVSuchty In C the int and unsigned int type will usually be the word size of the processor so all the native operations for the processor will run faster with int. char and short might be used in arrays where memory is tight.
$endgroup$
– pacmaninbw
Jul 30 at 14:08




$begingroup$
@TVSuchty In C the int and unsigned int type will usually be the word size of the processor so all the native operations for the processor will run faster with int. char and short might be used in arrays where memory is tight.
$endgroup$
– pacmaninbw
Jul 30 at 14:08




1




1




$begingroup$
@pacmaninbw That's why I put the link. But if the compiler accepts it (most of them, since a decade ago), it's very valid. And when you forget to change the FILE_MACRO_H name after copy&paste (it happened to me more than once), it's a pain in the ass until you find it. #pragma doesn't have that problem. The link provides all this info and discussion, and anyone is of course free to use whatever, and I just pointed to the info just in case he didn't know :)
$endgroup$
– Cacahuete Frito
Jul 30 at 14:37





$begingroup$
@pacmaninbw That's why I put the link. But if the compiler accepts it (most of them, since a decade ago), it's very valid. And when you forget to change the FILE_MACRO_H name after copy&paste (it happened to me more than once), it's a pain in the ass until you find it. #pragma doesn't have that problem. The link provides all this info and discussion, and anyone is of course free to use whatever, and I just pointed to the info just in case he didn't know :)
$endgroup$
– Cacahuete Frito
Jul 30 at 14:37





3




3




$begingroup$
This is totally bike shedding, but I disagree on the suggestion to change store_all_moves_of_pawn() to store_moves_pawn(). Perhaps store_pawn_moves() is fine, but my personal fave is store_all_pawn_moves. I would recommend a more expressive approach. Keystrokes are free, and monitors are giant, there's really no need to be pinched on character count.
$endgroup$
– Alexander
Jul 31 at 4:51




$begingroup$
This is totally bike shedding, but I disagree on the suggestion to change store_all_moves_of_pawn() to store_moves_pawn(). Perhaps store_pawn_moves() is fine, but my personal fave is store_all_pawn_moves. I would recommend a more expressive approach. Keystrokes are free, and monitors are giant, there's really no need to be pinched on character count.
$endgroup$
– Alexander
Jul 31 at 4:51













4












$begingroup$

First, interesting code!



I agree with most of what @CacahueteFrito wrote in his review except for the #pragma once item. The method you are using is more portable. I sometimes use #pragma once when the editor defaults to it on windows (Visual Studio), but not for C++.



I will primarily address style.



Code Consistency

The code is consistently indented, which is great, but the use of braces ( and ) in if statements is inconsistent. There are many places where braces are used around a single statement, but there are many places where braces aren't used around a single statement. It is more readable and maintainable when the code is consistent. Braces around a single statement are a good practice because quite often a new line of code needs to be inserted during maintenance.



Always Test the Return Value of Memory Allocation Functions

In most of the cases where memory is allocated the code is testing the return value, however, in the function MOVE_DATA return_all_moves(BOARD_STATE* plegal_board_state, char ignore_check) there is a call to malloc(size_t size) that is not tested. The function malloc() may also return NULL if there is not enough memory.



It might be better if the code was



char **tmp = malloc(move_data.array_size * sizeof(*p));
if (tmp)
move_data.moves = tmp;

else
// needs to be defined



because only the type of tmp needs to change if the type of move_data.moves is changed. This would be true for all the memory allocation performed in the program.



Casting Malloc

In modern C the functions malloc(), calloc() and realloc() return void *. It is not necessary to cast the memory returned by these statement to the proper type.



Readability

The code would be easier to read if there were some blank lines between blocks of code, such as after variable declarations at the top of the function, after a if then else block, after each of the cases in the switch statement.



Function Complexity

The function char store_all_moves_of_rock(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color) is very complex and could be broken up into at least 4 sub functions, up, down, left and right. This function is probably misnamed, I believe is should be all_moves_of_rook rather than rock.






share|improve this answer









$endgroup$














  • $begingroup$
    Hey, thank you for your critique! Glad you liked it. I will go for it!
    $endgroup$
    – TVSuchty
    Jul 30 at 15:38











  • $begingroup$
    Lol, I never noticed the difference between rock and rook. Thanks for educating me in English :P
    $endgroup$
    – TVSuchty
    Jul 30 at 16:22










  • $begingroup$
    Just a note that on many 64 bit systems (at least Linux and Mac I think, not sure of Windows), with sane environment settings, any reasonable use of malloc will never return NULL. Program(s) will start being killed if system runs out of memory and swap. A reasonable program will not run out of its own 64 bit virtual address space. It's still good to check it of course, but it's not worth putting much effort into handling it gracefully (just abort() or something).
    $endgroup$
    – hyde
    Jul 30 at 23:10











  • $begingroup$
    @hyde and if it is an embedded processor that doesn't have all that much memory?
    $endgroup$
    – pacmaninbw
    Jul 31 at 0:46






  • 1




    $begingroup$
    @pacmaninbw In that case you should really consider if you want to use a real operating system (such as embedded Linux), and research how you can configure and control malloc behavior (such as make it return NULL reliably, if your application is such that you can actually do something useful about it).
    $endgroup$
    – hyde
    Jul 31 at 6:17















4












$begingroup$

First, interesting code!



I agree with most of what @CacahueteFrito wrote in his review except for the #pragma once item. The method you are using is more portable. I sometimes use #pragma once when the editor defaults to it on windows (Visual Studio), but not for C++.



I will primarily address style.



Code Consistency

The code is consistently indented, which is great, but the use of braces ( and ) in if statements is inconsistent. There are many places where braces are used around a single statement, but there are many places where braces aren't used around a single statement. It is more readable and maintainable when the code is consistent. Braces around a single statement are a good practice because quite often a new line of code needs to be inserted during maintenance.



Always Test the Return Value of Memory Allocation Functions

In most of the cases where memory is allocated the code is testing the return value, however, in the function MOVE_DATA return_all_moves(BOARD_STATE* plegal_board_state, char ignore_check) there is a call to malloc(size_t size) that is not tested. The function malloc() may also return NULL if there is not enough memory.



It might be better if the code was



char **tmp = malloc(move_data.array_size * sizeof(*p));
if (tmp)
move_data.moves = tmp;

else
// needs to be defined



because only the type of tmp needs to change if the type of move_data.moves is changed. This would be true for all the memory allocation performed in the program.



Casting Malloc

In modern C the functions malloc(), calloc() and realloc() return void *. It is not necessary to cast the memory returned by these statement to the proper type.



Readability

The code would be easier to read if there were some blank lines between blocks of code, such as after variable declarations at the top of the function, after a if then else block, after each of the cases in the switch statement.



Function Complexity

The function char store_all_moves_of_rock(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color) is very complex and could be broken up into at least 4 sub functions, up, down, left and right. This function is probably misnamed, I believe is should be all_moves_of_rook rather than rock.






share|improve this answer









$endgroup$














  • $begingroup$
    Hey, thank you for your critique! Glad you liked it. I will go for it!
    $endgroup$
    – TVSuchty
    Jul 30 at 15:38











  • $begingroup$
    Lol, I never noticed the difference between rock and rook. Thanks for educating me in English :P
    $endgroup$
    – TVSuchty
    Jul 30 at 16:22










  • $begingroup$
    Just a note that on many 64 bit systems (at least Linux and Mac I think, not sure of Windows), with sane environment settings, any reasonable use of malloc will never return NULL. Program(s) will start being killed if system runs out of memory and swap. A reasonable program will not run out of its own 64 bit virtual address space. It's still good to check it of course, but it's not worth putting much effort into handling it gracefully (just abort() or something).
    $endgroup$
    – hyde
    Jul 30 at 23:10











  • $begingroup$
    @hyde and if it is an embedded processor that doesn't have all that much memory?
    $endgroup$
    – pacmaninbw
    Jul 31 at 0:46






  • 1




    $begingroup$
    @pacmaninbw In that case you should really consider if you want to use a real operating system (such as embedded Linux), and research how you can configure and control malloc behavior (such as make it return NULL reliably, if your application is such that you can actually do something useful about it).
    $endgroup$
    – hyde
    Jul 31 at 6:17













4












4








4





$begingroup$

First, interesting code!



I agree with most of what @CacahueteFrito wrote in his review except for the #pragma once item. The method you are using is more portable. I sometimes use #pragma once when the editor defaults to it on windows (Visual Studio), but not for C++.



I will primarily address style.



Code Consistency

The code is consistently indented, which is great, but the use of braces ( and ) in if statements is inconsistent. There are many places where braces are used around a single statement, but there are many places where braces aren't used around a single statement. It is more readable and maintainable when the code is consistent. Braces around a single statement are a good practice because quite often a new line of code needs to be inserted during maintenance.



Always Test the Return Value of Memory Allocation Functions

In most of the cases where memory is allocated the code is testing the return value, however, in the function MOVE_DATA return_all_moves(BOARD_STATE* plegal_board_state, char ignore_check) there is a call to malloc(size_t size) that is not tested. The function malloc() may also return NULL if there is not enough memory.



It might be better if the code was



char **tmp = malloc(move_data.array_size * sizeof(*p));
if (tmp)
move_data.moves = tmp;

else
// needs to be defined



because only the type of tmp needs to change if the type of move_data.moves is changed. This would be true for all the memory allocation performed in the program.



Casting Malloc

In modern C the functions malloc(), calloc() and realloc() return void *. It is not necessary to cast the memory returned by these statement to the proper type.



Readability

The code would be easier to read if there were some blank lines between blocks of code, such as after variable declarations at the top of the function, after a if then else block, after each of the cases in the switch statement.



Function Complexity

The function char store_all_moves_of_rock(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color) is very complex and could be broken up into at least 4 sub functions, up, down, left and right. This function is probably misnamed, I believe is should be all_moves_of_rook rather than rock.






share|improve this answer









$endgroup$



First, interesting code!



I agree with most of what @CacahueteFrito wrote in his review except for the #pragma once item. The method you are using is more portable. I sometimes use #pragma once when the editor defaults to it on windows (Visual Studio), but not for C++.



I will primarily address style.



Code Consistency

The code is consistently indented, which is great, but the use of braces ( and ) in if statements is inconsistent. There are many places where braces are used around a single statement, but there are many places where braces aren't used around a single statement. It is more readable and maintainable when the code is consistent. Braces around a single statement are a good practice because quite often a new line of code needs to be inserted during maintenance.



Always Test the Return Value of Memory Allocation Functions

In most of the cases where memory is allocated the code is testing the return value, however, in the function MOVE_DATA return_all_moves(BOARD_STATE* plegal_board_state, char ignore_check) there is a call to malloc(size_t size) that is not tested. The function malloc() may also return NULL if there is not enough memory.



It might be better if the code was



char **tmp = malloc(move_data.array_size * sizeof(*p));
if (tmp)
move_data.moves = tmp;

else
// needs to be defined



because only the type of tmp needs to change if the type of move_data.moves is changed. This would be true for all the memory allocation performed in the program.



Casting Malloc

In modern C the functions malloc(), calloc() and realloc() return void *. It is not necessary to cast the memory returned by these statement to the proper type.



Readability

The code would be easier to read if there were some blank lines between blocks of code, such as after variable declarations at the top of the function, after a if then else block, after each of the cases in the switch statement.



Function Complexity

The function char store_all_moves_of_rock(char copy_board[8][8], char from_x, char from_y, MOVE_DATA* move_info, char color) is very complex and could be broken up into at least 4 sub functions, up, down, left and right. This function is probably misnamed, I believe is should be all_moves_of_rook rather than rock.







share|improve this answer












share|improve this answer



share|improve this answer










answered Jul 30 at 15:26









pacmaninbwpacmaninbw

7,1002 gold badges20 silver badges44 bronze badges




7,1002 gold badges20 silver badges44 bronze badges














  • $begingroup$
    Hey, thank you for your critique! Glad you liked it. I will go for it!
    $endgroup$
    – TVSuchty
    Jul 30 at 15:38











  • $begingroup$
    Lol, I never noticed the difference between rock and rook. Thanks for educating me in English :P
    $endgroup$
    – TVSuchty
    Jul 30 at 16:22










  • $begingroup$
    Just a note that on many 64 bit systems (at least Linux and Mac I think, not sure of Windows), with sane environment settings, any reasonable use of malloc will never return NULL. Program(s) will start being killed if system runs out of memory and swap. A reasonable program will not run out of its own 64 bit virtual address space. It's still good to check it of course, but it's not worth putting much effort into handling it gracefully (just abort() or something).
    $endgroup$
    – hyde
    Jul 30 at 23:10











  • $begingroup$
    @hyde and if it is an embedded processor that doesn't have all that much memory?
    $endgroup$
    – pacmaninbw
    Jul 31 at 0:46






  • 1




    $begingroup$
    @pacmaninbw In that case you should really consider if you want to use a real operating system (such as embedded Linux), and research how you can configure and control malloc behavior (such as make it return NULL reliably, if your application is such that you can actually do something useful about it).
    $endgroup$
    – hyde
    Jul 31 at 6:17
















  • $begingroup$
    Hey, thank you for your critique! Glad you liked it. I will go for it!
    $endgroup$
    – TVSuchty
    Jul 30 at 15:38











  • $begingroup$
    Lol, I never noticed the difference between rock and rook. Thanks for educating me in English :P
    $endgroup$
    – TVSuchty
    Jul 30 at 16:22










  • $begingroup$
    Just a note that on many 64 bit systems (at least Linux and Mac I think, not sure of Windows), with sane environment settings, any reasonable use of malloc will never return NULL. Program(s) will start being killed if system runs out of memory and swap. A reasonable program will not run out of its own 64 bit virtual address space. It's still good to check it of course, but it's not worth putting much effort into handling it gracefully (just abort() or something).
    $endgroup$
    – hyde
    Jul 30 at 23:10











  • $begingroup$
    @hyde and if it is an embedded processor that doesn't have all that much memory?
    $endgroup$
    – pacmaninbw
    Jul 31 at 0:46






  • 1




    $begingroup$
    @pacmaninbw In that case you should really consider if you want to use a real operating system (such as embedded Linux), and research how you can configure and control malloc behavior (such as make it return NULL reliably, if your application is such that you can actually do something useful about it).
    $endgroup$
    – hyde
    Jul 31 at 6:17















$begingroup$
Hey, thank you for your critique! Glad you liked it. I will go for it!
$endgroup$
– TVSuchty
Jul 30 at 15:38





$begingroup$
Hey, thank you for your critique! Glad you liked it. I will go for it!
$endgroup$
– TVSuchty
Jul 30 at 15:38













$begingroup$
Lol, I never noticed the difference between rock and rook. Thanks for educating me in English :P
$endgroup$
– TVSuchty
Jul 30 at 16:22




$begingroup$
Lol, I never noticed the difference between rock and rook. Thanks for educating me in English :P
$endgroup$
– TVSuchty
Jul 30 at 16:22












$begingroup$
Just a note that on many 64 bit systems (at least Linux and Mac I think, not sure of Windows), with sane environment settings, any reasonable use of malloc will never return NULL. Program(s) will start being killed if system runs out of memory and swap. A reasonable program will not run out of its own 64 bit virtual address space. It's still good to check it of course, but it's not worth putting much effort into handling it gracefully (just abort() or something).
$endgroup$
– hyde
Jul 30 at 23:10





$begingroup$
Just a note that on many 64 bit systems (at least Linux and Mac I think, not sure of Windows), with sane environment settings, any reasonable use of malloc will never return NULL. Program(s) will start being killed if system runs out of memory and swap. A reasonable program will not run out of its own 64 bit virtual address space. It's still good to check it of course, but it's not worth putting much effort into handling it gracefully (just abort() or something).
$endgroup$
– hyde
Jul 30 at 23:10













$begingroup$
@hyde and if it is an embedded processor that doesn't have all that much memory?
$endgroup$
– pacmaninbw
Jul 31 at 0:46




$begingroup$
@hyde and if it is an embedded processor that doesn't have all that much memory?
$endgroup$
– pacmaninbw
Jul 31 at 0:46




1




1




$begingroup$
@pacmaninbw In that case you should really consider if you want to use a real operating system (such as embedded Linux), and research how you can configure and control malloc behavior (such as make it return NULL reliably, if your application is such that you can actually do something useful about it).
$endgroup$
– hyde
Jul 31 at 6:17




$begingroup$
@pacmaninbw In that case you should really consider if you want to use a real operating system (such as embedded Linux), and research how you can configure and control malloc behavior (such as make it return NULL reliably, if your application is such that you can actually do something useful about it).
$endgroup$
– hyde
Jul 31 at 6:17

















draft saved

draft discarded
















































Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f225191%2fpiece-of-chess-engine-which-accomplishes-move-generation%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

Circuit construction for execution of conditional statements using least significant bitHow are two different registers being used as “control”?How exactly is the stated composite state of the two registers being produced using the $R_zz$ controlled rotations?Efficiently performing controlled rotations in HHLWould this quantum algorithm implementation work?How to prepare a superposed states of odd integers from $1$ to $sqrtN$?Why is this implementation of the order finding algorithm not working?Circuit construction for Hamiltonian simulationHow can I invert the least significant bit of a certain term of a superposed state?Implementing an oracleImplementing a controlled sum operation

Magento 2 “No Payment Methods” in Admin New OrderHow to integrate Paypal Express Checkout with the Magento APIMagento 1.5 - Sales > Order > edit order and shipping methods disappearAuto Invoice Check/Money Order Payment methodAdd more simple payment methods?Shipping methods not showingWhat should I do to change payment methods if changing the configuration has no effects?1.9 - No Payment Methods showing upMy Payment Methods not Showing for downloadable/virtual product when checkout?Magento2 API to access internal payment methodHow to call an existing payment methods in the registration form?