389 lines
10 KiB
C
389 lines
10 KiB
C
// 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 <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
|
|
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* 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;
|
|
}
|
|
|
|
struct row_list {
|
|
unsigned row;
|
|
unsigned column;
|
|
struct row_list* next;
|
|
};
|
|
|
|
typedef struct row_list* visit_table;
|
|
|
|
#if DEBUG
|
|
unsigned long alloc = 0;
|
|
#endif
|
|
|
|
unsigned long table_total_size(const struct chessboard*);
|
|
unsigned long table_hash(const struct chessboard*, unsigned, unsigned);
|
|
|
|
inline unsigned long table_total_size(const struct chessboard* c) {
|
|
return 100;
|
|
}
|
|
|
|
inline unsigned long table_hash(const struct chessboard* c, unsigned col,
|
|
unsigned row) {
|
|
return (value_at(c, col, row) ^ (('C'|'a') << 24 | ('r'|'z') << 16 |
|
|
('a'|'n') << 8 | ('i'|'g'|'a')))
|
|
% table_total_size(c);
|
|
}
|
|
|
|
visit_table* table_new(const struct chessboard* c) {
|
|
unsigned long table_size = table_total_size(c);
|
|
|
|
#if DEBUG
|
|
alloc += sizeof(struct row_list*) * table_size;
|
|
#endif
|
|
|
|
return calloc(table_size, sizeof(struct row_list*));
|
|
}
|
|
|
|
void table_visit(const struct chessboard* c, visit_table* visited,
|
|
unsigned column, unsigned row) {
|
|
|
|
unsigned long hash = table_hash(c, column, row);
|
|
struct row_list* prev = hash[visited];
|
|
|
|
#if DEBUG
|
|
alloc += sizeof(struct row_list);
|
|
#endif
|
|
|
|
hash[visited] = malloc(sizeof(struct row_list));
|
|
assert(hash[visited] != NULL);
|
|
hash[visited]->row = row;
|
|
hash[visited]->column = column;
|
|
hash[visited]->next = prev;
|
|
}
|
|
|
|
bool table_visited(const struct chessboard* c, visit_table* visited,
|
|
unsigned column, unsigned row) {
|
|
|
|
unsigned long hash = table_hash(c, column, row);
|
|
for (struct row_list* i = hash[visited]; i != NULL; i = i->next) {
|
|
if (i->row == row && i->column == column) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void table_destroy(const struct chessboard* c, visit_table* visited) {
|
|
|
|
unsigned long table_size = table_total_size(c);
|
|
for (unsigned e = 0; e < table_size; e++) {
|
|
for (struct row_list* i = e[visited], *j; i != NULL;) {
|
|
j = i->next;
|
|
free(i);
|
|
i = j;
|
|
}
|
|
}
|
|
|
|
#if DEBUG
|
|
printf("alloc = %lu\n", alloc);
|
|
alloc = 0;
|
|
#endif
|
|
|
|
free(visited);
|
|
}
|
|
|
|
unsigned int simple_path_len(const struct chessboard* c,
|
|
struct piece_position* p) {
|
|
|
|
visit_table* v = table_new(c);
|
|
table_visit(c, v, 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 (!table_visited(c, v, 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);
|
|
}
|
|
|
|
table_visit(c, v, p->column, p->row);
|
|
#if DEBUG
|
|
print_visited(c, v);
|
|
#endif
|
|
hops++;
|
|
}
|
|
|
|
table_destroy(c, v);
|
|
return hops - 1;
|
|
}
|
|
|