// vim: set ts=4 sw=4 et tw=80: /* * Assignment 3 - Chess paths * Claudio Maggioni * * No external source was used as parts of code or as an inspiration for the * overall algorithm. * * The flag DEBUG, if defined, activates some debug messages printe on stdout. * This is disabled to comply with tests. */ #include "chess_paths.h" #include #include #include #include struct position { unsigned int column; unsigned int row; struct position* next; }; #if DEBUG char* NAMES[] = { "KING", "QUEEN", "ROOK", "BISHOP", "KNIGHT", "PAWN" }; 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++) { printf("%d", v[columns(ch) * c + r]); } puts(""); } } #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* malusa = bishop_positions(c, p); return rook_positions(c, p, malusa); } 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; } void visit(bool* visited, unsigned columns, unsigned column, unsigned row) { visited[column * columns + row] = true; } bool visited(bool* visited, unsigned columns, unsigned column, unsigned row) { return visited[column * columns + row]; } unsigned int simple_path_len(const struct chessboard* c, struct piece_position* p) { const unsigned int CC = columns(c); bool* v = calloc(rows(c) * CC, sizeof(unsigned)); visit(v, CC, p->column, p->row); #if DEBUG print_visited(c, v); #endif bool has_next = true; unsigned hops = 0; while(has_next) { struct position* poss = get_positions(c, p); has_next = false; unsigned int base_v = 0, next_v; #if DEBUG puts("simple"); print_p_position(p); #endif while(poss != NULL) { if (!visited(v, CC, poss->column, poss->row)) { next_v = value_at(c, poss->column, poss->row); if (!has_next || next_v > base_v) { has_next = true; p->row = poss->row; p->column = poss->column; base_v = next_v; } } struct position* del = poss; poss = poss->next; free(del); } visit(v, CC, p->column, p->row); #if DEBUG print_visited(c, v); #endif hops++; } free(v); return hops - 1; }