diff --git a/chess_paths/chess_paths.c b/chess_paths/chess_paths.c index facdf6c..181545b 100644 --- a/chess_paths/chess_paths.c +++ b/chess_paths/chess_paths.c @@ -17,12 +17,6 @@ #include #include -struct position { - unsigned int column; - unsigned int row; - struct position* next; -}; - #if DEBUG char* NAMES[] = { "KING", "QUEEN", "ROOK", "BISHOP", "KNIGHT", "PAWN" }; @@ -30,15 +24,6 @@ void print_p_position(struct piece_position* p) { printf("%s at row: %u col: %u\n", NAMES[p->piece], p->row, p->column); } -void print_poss(struct position* poss, struct piece_position* p) { - printf("%s (r%u,c%u): moves ", NAMES[p->piece], p->row, p->column); - while(poss != NULL) { - printf("(r%u,c%u) ", poss->row, poss->column); - poss = poss->next; - } - puts(""); -} - void print_visited(const struct chessboard* ch, bool* v) { for (int r = rows(ch) - 1; r >= 0; r--) { for (int c = 0; c < columns(ch); c++) { @@ -49,211 +34,9 @@ void print_visited(const struct chessboard* ch, bool* v) { } #endif -void prepend(struct position** poss_p, unsigned column, unsigned row) { - struct position* prev = *poss_p; - *poss_p = malloc(sizeof(struct position)); - assert(*poss_p != NULL); - (*poss_p)->column = column; - (*poss_p)->row = row; - (*poss_p)->next = prev; -} - -struct position* pawn_positions(const struct chessboard* c, - struct piece_position* p) { - struct position* poss = NULL; - - if (p->row + 1 < rows(c)) { - prepend(&poss, p->column, p->row + 1); - } - - return poss; -} - -struct position* king_positions(const struct chessboard* c, - struct piece_position* p) { - struct position* poss = NULL; - unsigned cs = columns(c) - 1; - unsigned rs = rows(c) - 1; - unsigned row = p->row, col = p->column; - - if (row > 0 && col > 0) prepend(&poss, col - 1, row - 1); - if (row > 0) prepend(&poss, col, row - 1); - if (row > 0 && col < cs) prepend(&poss, col + 1, row - 1); - if (col > 0) prepend(&poss, col - 1, row); - if (col < cs) prepend(&poss, col + 1, row); - if (row < rs && col > 0) prepend(&poss, col - 1, row + 1); - if (row < rs) prepend(&poss, col, row + 1); - if (row < rs && col < cs) prepend(&poss, col + 1, row + 1); - - return poss; -} - -struct position* rook_positions(const struct chessboard* c, - struct piece_position* p, struct position* other) { - struct position* poss = other; - unsigned c_cols = columns(c); - unsigned c_rows = rows(c); - - for (int col = 0; col < c_cols; col++) { - if (col == p->column) continue; - prepend(&poss, col, p->row); - } - - for (int row = 0; row < c_rows; row++) { - if (row == p->row) continue; - prepend(&poss, p->column, row); - } - - return poss; -} - -struct position* knight_positions(const struct chessboard* c, - struct piece_position* p) { - struct position* poss = NULL; - unsigned cs = columns(c) - 1; - unsigned rs = rows(c) - 1; - unsigned row = p->row, col = p->column; - - if (row >= 1 && col >= 2) prepend(&poss, col - 2, row - 1); - if (row >= 2 && col >= 1) prepend(&poss, col - 1, row - 2); - if (row >= 2 && col <= cs - 1) prepend(&poss, col + 1, row - 2); - if (row >= 1 && col <= cs - 2) prepend(&poss, col + 2, row - 1); - if (row <= rs - 1 && col <= cs - 2) prepend(&poss, col + 2, row + 1); - if (row <= rs - 2 && col <= cs - 1) prepend(&poss, col + 1, row + 2); - if (row <= rs - 2 && col >= 1) prepend(&poss, col - 1, row + 2); - if (row <= rs - 1 && col >= 2) prepend(&poss, col - 2, row + 1); - - return poss; -} - -struct position* bishop_positions(const struct chessboard* board, - struct piece_position* p) { - struct position* poss = NULL; - unsigned cs = columns(board); - unsigned rs = rows(board); - int r, c; - - for (r = p->row - 1, c = p->column - 1; r >= 0 && c >= 0; r--, c--) { - prepend(&poss, c, r); - } - - for (r = p->row + 1, c = p->column + 1; r < rs && c < cs; r++, c++) { - prepend(&poss, c, r); - } - - for (r = p->row - 1, c = p->column + 1; r >= 0 && c < cs; r--, c++) { - prepend(&poss, c, r); - } - - for (r = p->row + 1, c = p->column - 1; r < rs && c >= 0; r++, c--) { - prepend(&poss, c, r); - } - - return poss; -} - -struct position* queen_positions(const struct chessboard* c, - struct piece_position* p) { - - struct position* canotaggio = bishop_positions(c, p); - return rook_positions(c, p, canotaggio); -} - -struct position* get_positions(const struct chessboard* c, - struct piece_position* p) { - struct position* poss; - switch (p->piece) { - case PAWN: poss = pawn_positions(c, p); break; - case KING: poss = king_positions(c, p); break; - case ROOK: poss = rook_positions(c, p, NULL); break; - case KNIGHT: poss = knight_positions(c, p); break; - case BISHOP: poss = bishop_positions(c, p); break; - case QUEEN: poss = queen_positions(c, p); break; - } -#if DEBUG - print_poss(poss, p); -#endif - return poss; -} - - - -unsigned int increasing_path_len(const struct chessboard* c, - struct piece_position* p) { - - unsigned int hops = 0; - bool has_next = true; - -#if DEBUG - puts("increasing"); - printf("board r=%u c=%u\n", rows(c), columns(c)); -#endif - - while (has_next) { - struct position* poss = get_positions(c, p); - unsigned int base_val = value_at(c, p->column, p->row), next_v; - has_next = false; - -#if DEBUG - print_p_position(p); -#endif - - while(poss != NULL) { - next_v = value_at(c, poss->column, poss->row); - if (next_v > base_val) { - has_next = true; - p->row = poss->row; - p->column = poss->column; - base_val = next_v; - } - struct position* del = poss; - poss = poss->next; - free(del); - } - - hops++; - } - - return hops - 1; -} - -unsigned int decreasing_path_len(const struct chessboard* c, - struct piece_position* p) { - - unsigned int hops = 0; - bool has_next = true; - -#if DEBUG - puts("decreasing"); - printf("board r=%u c=%u\n", rows(c), columns(c)); -#endif - - while (has_next) { - struct position* poss = get_positions(c, p); - unsigned int base_val = value_at(c, p->column, p->row), next_v; - has_next = false; - -#if DEBUG - print_p_position(p); -#endif - - while(poss != NULL) { - if ((next_v = value_at(c, poss->column, poss->row)) < base_val) { - has_next = true; - p->row = poss->row; - p->column = poss->column; - base_val = next_v; - } - struct position* del = poss; - poss = poss->next; - free(del); - } - - hops++; - } - - return hops - 1; -} +/** + * Code for visited row/column dictionary. Used in simple_path_len + */ struct row_list { unsigned row; @@ -337,6 +120,228 @@ void table_destroy(const struct chessboard* c, visit_table* visited) { free(visited); } +/** + * Code for search_status struct. Used to keep track of the piece to choose in + * all *_path_len functions and in piece functions + */ + +struct search_status { + unsigned column; + unsigned row; + bool found; + + bool (*better)(struct search_status* s, unsigned col, unsigned row); + + const struct chessboard* chessboard; + visit_table* table; +}; + +void search_status_init(struct search_status* s, struct piece_position* p, + bool (*better)(struct search_status*, unsigned, unsigned), + const struct chessboard* c, visit_table* table) { + s->column = p->column; + s->row = p->row; + s->found = false; + s->better = better; + s->chessboard = c; + s->table = table; +} + +/** + * Consider compares the value at the given position with the current maximum, + * if "better" (according to the predicate stored in search_status) then it sets + * the search_status maximum to the given posiition + */ + +void consider(struct search_status* s, unsigned column, unsigned row) { + if (s->better(s, column, row)) { + s->found = true; + s->column = column; + s->row = row; + } +} + +/** + * Piece postitions. They "consider" every position which is a legal move for + * the piece + */ + +void pawn_positions(struct search_status* s, struct piece_position* p) { + if (p->row + 1 < rows(s->chessboard)) { + consider(s, p->column, p->row + 1); + } +} + +void king_positions(struct search_status* s, struct piece_position* p) { + unsigned cs = columns(s->chessboard) - 1; + unsigned rs = rows(s->chessboard) - 1; + unsigned row = p->row, col = p->column; + + if (row > 0 && col > 0) consider(s, col - 1, row - 1); + if (row > 0) consider(s, col, row - 1); + if (row > 0 && col < cs) consider(s, col + 1, row - 1); + if (col > 0) consider(s, col - 1, row); + if (col < cs) consider(s, col + 1, row); + if (row < rs && col > 0) consider(s, col - 1, row + 1); + if (row < rs) consider(s, col, row + 1); + if (row < rs && col < cs) consider(s, col + 1, row + 1); +} + +void rook_positions(struct search_status* s, struct piece_position* p) { + unsigned c_cols = columns(s->chessboard); + unsigned c_rows = rows(s->chessboard); + + for (int col = 0; col < c_cols; col++) { + if (col == p->column) continue; + consider(s, col, p->row); + } + + for (int row = 0; row < c_rows; row++) { + if (row == p->row) continue; + consider(s, p->column, row); + } +} + +void knight_positions(struct search_status* s, struct piece_position* p) { + unsigned cs = columns(s->chessboard) - 1; + unsigned rs = rows(s->chessboard) - 1; + unsigned row = p->row, col = p->column; + + if (row >= 1 && col >= 2) consider(s, col - 2, row - 1); + if (row >= 2 && col >= 1) consider(s, col - 1, row - 2); + if (row >= 2 && col <= cs - 1) consider(s, col + 1, row - 2); + if (row >= 1 && col <= cs - 2) consider(s, col + 2, row - 1); + if (row <= rs - 1 && col <= cs - 2) consider(s, col + 2, row + 1); + if (row <= rs - 2 && col <= cs - 1) consider(s, col + 1, row + 2); + if (row <= rs - 2 && col >= 1) consider(s, col - 1, row + 2); + if (row <= rs - 1 && col >= 2) consider(s, col - 2, row + 1); +} + +void bishop_positions(struct search_status* s, struct piece_position* p) { + unsigned cs = columns(s->chessboard); + unsigned rs = rows(s->chessboard); + int r, c; + + for (r = p->row - 1, c = p->column - 1; r >= 0 && c >= 0; r--, c--) { + consider(s, c, r); + } + + for (r = p->row + 1, c = p->column + 1; r < rs && c < cs; r++, c++) { + consider(s, c, r); + } + + for (r = p->row - 1, c = p->column + 1; r >= 0 && c < cs; r--, c++) { + consider(s, c, r); + } + + for (r = p->row + 1, c = p->column - 1; r < rs && c >= 0; r++, c--) { + consider(s, c, r); + } +} + +void queen_positions(struct search_status* canotaggio, + struct piece_position* p) { + + bishop_positions(canotaggio, p); + rook_positions(canotaggio, p); +} + +void consider_positions(struct search_status* s, struct piece_position* p) { + switch (p->piece) { + case PAWN: pawn_positions(s, p); break; + case KING: king_positions(s, p); break; + case ROOK: rook_positions(s, p); break; + case KNIGHT: knight_positions(s, p); break; + case BISHOP: bishop_positions(s, p); break; + case QUEEN: queen_positions(s, p); break; + } +#if DEBUG + print_poss(poss, p); +#endif +} + +unsigned int path_len(const struct chessboard* c, + struct piece_position* p, + bool (*better)(struct search_status*, unsigned, unsigned), + visit_table* table) { + + unsigned int hops = 0; + bool has_next = true; + +#if DEBUG + printf("board r=%u c=%u\n", rows(c), columns(c)); +#endif + + struct search_status status; + search_status_init(&status, p, better, c, table); + + while (has_next) { + consider_positions(&status, p); + has_next = status.found; + p->column = status.column; + p->row = status.row; + +#if DEBUG + print_p_position(p); +#endif + + hops++; + } + + return hops - 1; +} + + +bool better_inc(struct search_status* s, unsigned column, unsigned row) { + return value_at(s->chessboard, s->column, s->row) > + value_at(s->chessboard, column, row); +} + +bool better_dec(struct search_status* s, unsigned column, unsigned row) { + return value_at(s->chessboard, s->column, s->row) < + value_at(s->chessboard, column, row); +} + +bool better_simple(struct search_status* s, unsigned column, unsigned row) { + return !table_visited(s->chessboard, s->table, column, row) && + (!s->found || (value_at(s->chessboard, s->column, s->row) > + value_at(s->chessboard, column, row))); +} + +unsigned int increasing_path_len(const struct chessboard* c, + struct piece_position* p) { + +} + +unsigned int decreasing_path_len(const struct chessboard* c, + struct piece_position* p) { + + unsigned int hops = 0; + bool has_next = true; + +#if DEBUG + puts("decreasing"); + printf("board r=%u c=%u\n", rows(c), columns(c)); +#endif + + struct search_status status; + search_status_init(&status, p, better_inc, c, NULL); + + while (has_next) { + consider_positions(&status, p); + has_next = status.found; + p->column = status.column; + p->row = status.row; + +#if DEBUG + print_p_position(p); +#endif + + hops++; + } + + return hops - 1; +} unsigned int simple_path_len(const struct chessboard* c, struct piece_position* p) {