From ed962f5b09c43c788b868618dc4afca16098e203 Mon Sep 17 00:00:00 2001 From: spv Date: Thu, 7 Mar 2024 13:19:48 +0100 Subject: [PATCH] h --- board.c | 605 ++++++++++++++++++-------------------------------------- board.h | 204 ++++++------------- main.c | 433 +++++++++++++++------------------------- 3 files changed, 405 insertions(+), 837 deletions(-) diff --git a/board.c b/board.c index fbada8b..3c86c33 100644 --- a/board.c +++ b/board.c @@ -4,21 +4,19 @@ * Created by Gabriel Tofvesson */ +#include "board.h" #include #include #include -#include "board.h" - /** * Raises an error by printing it to stderr and stopping execution */ -#define ERROR(reason) \ -{ \ - fprintf(stderr, "ERROR: %s\n", reason); \ - abort(); \ -} - +#define ERROR(reason) \ + { \ + fprintf(stderr, "ERROR: %s\n", reason); \ + abort(); \ + } /** * Raises an error if the given condition is not met @@ -27,306 +25,208 @@ #ifdef OPTIMIZE #define ASSERT(cond, reason) #else -#define ASSERT(cond, reason) \ -{ \ - if (! cond) ERROR ((reason)); \ -} +#define ASSERT(cond, reason) \ + { \ + if (!cond) \ + ERROR((reason)); \ + } #endif - /** * Check if a given xy-pair is in bounds of a Sudoku board */ -static inline bool -is_in_bounds (board_pos x, board_pos y) -{ +static inline bool is_in_bounds(board_pos x, board_pos y) { #ifdef OPTIMIZE return true; #else - return x >= 0 && - x < 9 && - y >= 0 && - y < 9 ; + return x >= 0 && x < 9 && y >= 0 && y < 9; #endif } /** * Check if a given element value is within acceptable bounds */ -static inline bool -is_valid_value (element_value value) -{ +static inline bool is_valid_value(element_value value) { #ifdef OPTIMIZE return true; #else - return value >= 0 && - value < 9 ; + return value >= 0 && value < 9; #endif } - -void -meta_init (struct metadata *meta) -{ - memset (meta, 0, sizeof (struct metadata)); +void meta_init(struct metadata *meta) { + memset(meta, 0, sizeof(struct metadata)); } - -void -board_make_links (struct board *board) -{ +void board_make_links(struct board *board) { for (board_pos y = 0; y < 9; ++y) - for (board_pos x = 0; x < 9; ++x) - { - unsigned pos = ELEM_POS (x, y); + for (board_pos x = 0; x < 9; ++x) { + unsigned pos = ELEM_POS(x, y); unsigned link_count = -1; /* Link column adjacents */ for (board_pos lx = 0; lx < 9; ++lx) if (lx != x) - board->links[pos][++link_count] = BOARD_ELEM (board, lx, y); + board->links[pos][++link_count] = BOARD_ELEM(board, lx, y); /* Link column adjacents */ for (board_pos ly = 0; ly < 9; ++ly) if (ly != y) - board->links[pos][++link_count] = BOARD_ELEM (board, x, ly); + board->links[pos][++link_count] = BOARD_ELEM(board, x, ly); /* Link quadrant adjacents */ - board_pos qx = TO_QUAD (x); - board_pos qy = TO_QUAD (y); + board_pos qx = TO_QUAD(x); + board_pos qy = TO_QUAD(y); for (board_pos lqy = 0; lqy < 3; ++lqy) for (board_pos lqx = 0; lqx < 3; ++lqx) if ((lqx + qx) != x && (lqy + qy) != y) - board->links[pos][++link_count] = BOARD_ELEM (board, lqx + qx, lqy + qy); + board->links[pos][++link_count] = + BOARD_ELEM(board, lqx + qx, lqy + qy); } } - -void -board_init (struct board *board) -{ +void board_init(struct board *board) { struct board_element defval; defval.has_value = false; defval.potential = 0x1FF; defval.complexity = 9; for (board_pos y = 0; y < 9; ++y) - for (board_pos x = 0; x < 9; ++x) - { - struct board_element *elem = BOARD_ELEM (board, x, y); + for (board_pos x = 0; x < 9; ++x) { + struct board_element *elem = BOARD_ELEM(board, x, y); /* Set default state */ - memcpy (elem, &defval, sizeof (struct board_element)); + memcpy(elem, &defval, sizeof(struct board_element)); } - - board_make_links (board); + board_make_links(board); board->complexity = 9; - - for (unsigned i = 0; i < 9; ++i) - { - meta_init (&board->meta_quad[i]); - meta_init (&board->meta_row[i]); - meta_init (&board->meta_col[i]); + + for (unsigned i = 0; i < 9; ++i) { + meta_init(&board->meta_quad[i]); + meta_init(&board->meta_row[i]); + meta_init(&board->meta_col[i]); } } - -bool -meta_has_value (const struct metadata *meta, element_value value) -{ +bool meta_has_value(const struct metadata *meta, element_value value) { return ((meta->marked >> value) & 1) == 1; } - -void -meta_set_value (struct metadata *meta, element_value value) -{ +void meta_set_value(struct metadata *meta, element_value value) { meta->marked |= 1 << value; } +void meta_clear_values(struct metadata *meta) { meta->marked = 0; } -void -meta_clear_values (struct metadata *meta) -{ - meta->marked = 0; -} - - -static inline void -meta_mark (struct metadata *meta, element_value value, unsigned index) -{ - meta_set_value (meta, value); +static inline void meta_mark(struct metadata *meta, element_value value, + unsigned index) { + meta_set_value(meta, value); unsigned char count = meta->unique[value].count; - if (count == 0) - { + if (count == 0) { meta->unique[value].count = 1; meta->unique[value].index = index; - } - else - { + } else { meta->unique[value].count = 2; } } - -void -board_meta_quad_refresh (struct board *board, board_pos qx, board_pos qy) -{ - struct metadata *meta = BOARD_QUAD (board, qx * 3, qy * 3); +void board_meta_quad_refresh(struct board *board, board_pos qx, board_pos qy) { + struct metadata *meta = BOARD_QUAD(board, qx * 3, qy * 3); board_pos quad_base_x = qx * 3; board_pos quad_base_y = qy * 3; - meta_clear_values (meta); + meta_clear_values(meta); for (board_pos off_y = 0; off_y < 3; ++off_y) - for (board_pos off_x = 0; off_x < 3; ++off_x) - { + for (board_pos off_x = 0; off_x < 3; ++off_x) { struct board_element *elem = - BOARD_ELEM (board, quad_base_x + off_x, quad_base_y + off_y); + BOARD_ELEM(board, quad_base_x + off_x, quad_base_y + off_y); if (elem->has_value) - meta_mark (meta, elem->value, (off_y * 3) + off_x); + meta_mark(meta, elem->value, (off_y * 3) + off_x); } } +void board_meta_row_refresh(struct board *board, board_pos y) { + struct metadata *meta = BOARD_ROW(board, y); -void -board_meta_row_refresh (struct board *board, board_pos y) -{ - struct metadata *meta = BOARD_ROW (board, y); - - meta_clear_values (meta); + meta_clear_values(meta); - for (board_pos x = 0; x < 9; ++x) - { - struct board_element *elem = BOARD_ELEM (board, x, y); + for (board_pos x = 0; x < 9; ++x) { + struct board_element *elem = BOARD_ELEM(board, x, y); if (elem->has_value) - meta_mark (meta, elem->value, x); + meta_mark(meta, elem->value, x); } } +void board_meta_col_refresh(struct board *board, board_pos x) { + struct metadata *meta = BOARD_COL(board, x); -void -board_meta_col_refresh (struct board *board, board_pos x) -{ - struct metadata *meta = BOARD_COL (board, x); - - meta_clear_values (meta); + meta_clear_values(meta); - for (board_pos y = 0; y < 9; ++y) - { - struct board_element *elem = BOARD_ELEM (board, x, y); + for (board_pos y = 0; y < 9; ++y) { + struct board_element *elem = BOARD_ELEM(board, x, y); if (elem->has_value) - meta_mark (meta, elem->value, y); + meta_mark(meta, elem->value, y); } } - -bool -board_meta_can_set ( - const struct board *board, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { - return ! ( - meta_has_value (BOARD_ROW (board, y), value) || - meta_has_value (BOARD_COL (board, x), value) || - meta_has_value (BOARD_QUAD (board, x, y), value) - ); - } - else ERROR("Invalid parameters to function board_meta_can_set()"); +bool board_meta_can_set(const struct board *board, board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { + return !(meta_has_value(BOARD_ROW(board, y), value) || + meta_has_value(BOARD_COL(board, x), value) || + meta_has_value(BOARD_QUAD(board, x, y), value)); + } else + ERROR("Invalid parameters to function board_meta_can_set()"); } +void board_set(struct board *board, board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { + ASSERT(board_meta_can_set(board, x, y, value), + "Attempt to set impossible value on board"); -void -board_set ( - struct board *board, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { - ASSERT ( - board_meta_can_set (board, x, y, value), - "Attempt to set impossible value on board" - ); + struct board_element *elem = BOARD_ELEM(board, x, y); - struct board_element *elem = BOARD_ELEM (board, x, y); - elem->has_value = true; elem->value = value; - } - else ERROR("Invalid parameters to function board_set()"); + } else + ERROR("Invalid parameters to function board_set()"); } +void board_mark(struct board *board, board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { + ASSERT(!board_has_value(board, x, y), "Attempt to mark element with value"); -void -board_mark ( - struct board *board, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { - ASSERT ( - ! board_has_value (board, x, y), - "Attempt to mark element with value" - ); - - struct board_element *elem = BOARD_ELEM (board, x, y); - if (! board_is_marked (board, x, y, value)) - { + struct board_element *elem = BOARD_ELEM(board, x, y); + if (!board_is_marked(board, x, y, value)) { elem->potential |= 1 << value; ++(elem->complexity); } - } - else ERROR("Invalid parameters to function board_mark()"); + } else + ERROR("Invalid parameters to function board_mark()"); } +bool board_unmark(struct board *board, board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { + ASSERT(!board_has_value(board, x, y), "Attempt to mark element with value"); -bool -board_unmark ( - struct board *board, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { - ASSERT ( - ! board_has_value (board, x, y), - "Attempt to mark element with value" - ); - - return elem_unmark (BOARD_ELEM (board, x, y), value); - } - else ERROR("Invalid parameters to function board_unmark()"); + return elem_unmark(BOARD_ELEM(board, x, y), value); + } else + ERROR("Invalid parameters to function board_unmark()"); } - -bool -elem_unmark ( - struct board_element *elem, - element_value value -) -{ - if (elem_is_marked (elem, value)) - { +bool elem_unmark(struct board_element *elem, element_value value) { + if (elem_is_marked(elem, value)) { /* Shift bit to correct place and then invert first 9 bits */ elem->potential ^= (1 << value); --(elem->complexity); @@ -335,326 +235,219 @@ elem_unmark ( return elem->potential != 0; } - -bool -board_has_value ( - const struct board *board, - board_pos x, - board_pos y -) -{ - if (is_in_bounds (x, y)) - { - return BOARD_ELEM (board, x, y)->has_value; - } - else ERROR("Invalid parameters to function board_has_value()"); +bool board_has_value(const struct board *board, board_pos x, board_pos y) { + if (is_in_bounds(x, y)) { + return BOARD_ELEM(board, x, y)->has_value; + } else + ERROR("Invalid parameters to function board_has_value()"); } - -element_value -board_get_value ( - const struct board *board, - board_pos x, - board_pos y -) -{ - if (is_in_bounds (x, y)) - { - return BOARD_ELEM (board, x, y)->value; - } - else ERROR("Invalid parameters to function board_get_value()"); +element_value board_get_value(const struct board *board, board_pos x, + board_pos y) { + if (is_in_bounds(x, y)) { + return BOARD_ELEM(board, x, y)->value; + } else + ERROR("Invalid parameters to function board_get_value()"); } - -bool -board_is_marked ( - const struct board *board, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { - return elem_is_marked(BOARD_ELEM (board, x, y), value); - } - else ERROR("Invalid parameters to function board_is_marked()"); +bool board_is_marked(const struct board *board, board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { + return elem_is_marked(BOARD_ELEM(board, x, y), value); + } else + ERROR("Invalid parameters to function board_is_marked()"); } - -bool -elem_is_marked ( - const struct board_element *elem, - element_value value -) -{ +bool elem_is_marked(const struct board_element *elem, element_value value) { return elem->potential & (1 << value); } - -bool -board_is_valid (struct board *board) -{ +bool board_is_valid(struct board *board) { for (board_pos y = 0; y < 9; ++y) for (board_pos x = 0; x < 9; ++x) - if ( - !board_has_value (board, x, y) && - BOARD_ELEM (board, x, y)->potential == 0 - ) + if (!board_has_value(board, x, y) && + BOARD_ELEM(board, x, y)->potential == 0) return false; return true; } - -void -board_update_marks ( - struct board *board, - board_pos x, - board_pos y -) -{ - if (is_in_bounds (x, y)) - { - struct board_element *elem = BOARD_ELEM (board, x, y); +void board_update_marks(struct board *board, board_pos x, board_pos y) { + if (is_in_bounds(x, y)) { + struct board_element *elem = BOARD_ELEM(board, x, y); /* Mark all values as impossible */ elem->potential = 0; elem->complexity = 0; /* Check x-axis */ - elem->potential |= BOARD_QUAD (board, x, y)->marked; - elem->potential |= BOARD_ROW (board, y)->marked; - elem->potential |= BOARD_COL (board, x)->marked; + elem->potential |= BOARD_QUAD(board, x, y)->marked; + elem->potential |= BOARD_ROW(board, y)->marked; + elem->potential |= BOARD_COL(board, x)->marked; /* Invert matches */ elem->potential ^= 0x1FF; /* Count marked bits */ unsigned short potential = elem->potential; - while (potential != 0) - { + while (potential != 0) { if ((potential & 1) == 1) ++(elem->complexity); potential >>= 1; } - } - else ERROR("Invalid parameters to function board_update_marks()"); + } else + ERROR("Invalid parameters to function board_update_marks()"); } - -bool -board_can_quad_set_value ( - struct board *board, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { +bool board_can_quad_set_value(struct board *board, board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { /* Compute quadrant bases */ - board_pos quad_x = TO_QUAD (x); - board_pos quad_y = TO_QUAD (y); + board_pos quad_x = TO_QUAD(x); + board_pos quad_y = TO_QUAD(y); /* Compute sub-quadrant positions */ board_pos simp_x = x % 3; board_pos simp_y = y % 3; - bool next = false; /* Check along x-axis */ - for (board_pos base_x = 0; base_x < 9; base_x += 3) - { + for (board_pos base_x = 0; base_x < 9; base_x += 3) { next = false; - if (base_x != quad_x) - { - for (board_pos check_y = 0; check_y < 3 && ! next; ++check_y) + if (base_x != quad_x) { + for (board_pos check_y = 0; check_y < 3 && !next; ++check_y) if (check_y != simp_y) - for (board_pos check_x = 0; check_x < 3 && ! next; ++check_x) - { + for (board_pos check_x = 0; check_x < 3 && !next; ++check_x) { board_pos target_x = base_x + check_x; board_pos target_y = quad_y + check_y; - bool has_value = board_has_value (board, target_x, target_y); + bool has_value = board_has_value(board, target_x, target_y); /* Check if a quadrant can contain the given value */ - if ( - ( - has_value && - BOARD_ELEM (board, target_x, target_y)->value == value - ) || - ( - ! has_value && - board_is_marked (board, target_x, target_y, value) - ) - ) - { + if ((has_value && + BOARD_ELEM(board, target_x, target_y)->value == value) || + (!has_value && + board_is_marked(board, target_x, target_y, value))) { next = true; break; } } - if (! next) + if (!next) return false; } } /* Check along y-axis */ - for (board_pos base_y = 0; base_y < 9; base_y += 3) - { + for (board_pos base_y = 0; base_y < 9; base_y += 3) { next = false; - if (base_y != quad_y) - { - for (board_pos check_x = 0; check_x < 3 && ! next; ++check_x) + if (base_y != quad_y) { + for (board_pos check_x = 0; check_x < 3 && !next; ++check_x) if (check_x != simp_x) - for (board_pos check_y = 0; check_y < 3 && ! next; ++check_y) - { + for (board_pos check_y = 0; check_y < 3 && !next; ++check_y) { board_pos target_x = quad_x + check_x; board_pos target_y = base_y + check_y; - bool has_value = board_has_value (board, target_x, target_y); + bool has_value = board_has_value(board, target_x, target_y); /* Check if a quadrant can contain the given value */ - if ( - ( - has_value && - BOARD_ELEM (board, target_x, target_y)->value == value - ) || - ( - ! has_value && - board_is_marked (board, target_x, target_y, value) - ) - ) - { + if ((has_value && + BOARD_ELEM(board, target_x, target_y)->value == value) || + (!has_value && + board_is_marked(board, target_x, target_y, value))) { next = true; break; } } - if (! next) + if (!next) return false; } } return true; - } - else ERROR("Invalid parameters to function board_can_quad_set_value()"); + } else + ERROR("Invalid parameters to function board_can_quad_set_value()"); } - -static inline bool -field_is_potential (unsigned short field, element_value value) -{ +static inline bool field_is_potential(unsigned short field, + element_value value) { return ((field >> (value * 2)) & 3) < 2; } - -static inline void -field_invalidate (unsigned short *field, element_value value) -{ +static inline void field_invalidate(unsigned short *field, + element_value value) { *field |= 2 << (value * 2); } - -static inline void -field_increment (unsigned short *field, element_value value) -{ - if (field_is_potential (*field, value)) +static inline void field_increment(unsigned short *field, element_value value) { + if (field_is_potential(*field, value)) *field += (1 << (value * 2)); } - -void -board_update_all_marks (struct board *board) -{ +void board_update_all_marks(struct board *board) { for (board_pos y = 0; y < 9; ++y) for (board_pos x = 0; x < 9; ++x) - if (! board_has_value (board, x, y)) - board_update_marks (board, x, y); + if (!board_has_value(board, x, y)) + board_update_marks(board, x, y); } - -bool -board_place ( - struct board *board, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { - if (board_meta_can_set (board, x, y, value)) - { - unsigned pos = ELEM_POS (x, y); +bool board_place(struct board *board, board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { + if (board_meta_can_set(board, x, y, value)) { + unsigned pos = ELEM_POS(x, y); /* Unmark all adjacent elements */ for (unsigned i = 0; i < 20; ++i) - if ( - ! board->links[pos][i]->has_value && - ! elem_unmark (board->links[pos][i], value) - ) - { + if (!board->links[pos][i]->has_value && + !elem_unmark(board->links[pos][i], value)) { /* Unmarking potential caused element to have no potential */ return false; } /* Set value */ - board_set (board, x, y, value); + board_set(board, x, y, value); /* Update metadata */ - meta_set_value (BOARD_QUAD (board, x, y), value); - meta_set_value (BOARD_ROW (board, y), value); - meta_set_value (BOARD_COL (board, x), value); + meta_set_value(BOARD_QUAD(board, x, y), value); + meta_set_value(BOARD_ROW(board, y), value); + meta_set_value(BOARD_COL(board, x), value); return true; - } - else return false; - } - else ERROR("Invalid parameters to function board_place()"); + } else + return false; + } else + ERROR("Invalid parameters to function board_place()"); } - -struct board * -board_place_speculative ( - const struct board *board, - struct board *board_duplicate, - board_pos x, - board_pos y, - element_value value -) -{ - if (is_in_bounds (x, y) && is_valid_value (value)) - { +struct board *board_place_speculative(const struct board *board, + struct board *board_duplicate, + board_pos x, board_pos y, + element_value value) { + if (is_in_bounds(x, y) && is_valid_value(value)) { /* Ensure value can be placed*/ - if (board_meta_can_set (board, x, y, value)) - { + if (board_meta_can_set(board, x, y, value)) { /* Create duplicate and place value */ - board_copy (board, board_duplicate); + board_copy(board, board_duplicate); - if (! board_place (board_duplicate, x, y, value)) + if (!board_place(board_duplicate, x, y, value)) return NULL; - board_refresh_complexity (board_duplicate); + board_refresh_complexity(board_duplicate); return board_duplicate; - } - else return NULL; - } - else ERROR("Invalid parameters to function board_place_speculative()"); + } else + return NULL; + } else + ERROR("Invalid parameters to function board_place_speculative()"); } - -bool -board_refresh_complexity (struct board *board) -{ +bool board_refresh_complexity(struct board *board) { board->complexity = 10; for (board_pos y = 0; y < 9; ++y) for (board_pos x = 0; x < 9; ++x) - if (! board_has_value (board, x, y)) - { - struct board_element *elem = BOARD_ELEM (board, x, y); - if (elem->complexity < board->complexity) - { + if (!board_has_value(board, x, y)) { + struct board_element *elem = BOARD_ELEM(board, x, y); + if (elem->complexity < board->complexity) { /* If complexity is somehow 0, we have an invalid board state */ if (elem->complexity == 0) return false; @@ -674,14 +467,8 @@ board_refresh_complexity (struct board *board) return true; } - -void -board_copy (const struct board *board_from, struct board *board_to) -{ +void board_copy(const struct board *board_from, struct board *board_to) { /* Copy everything except the links */ - memcpy ( - board_to, - board_from, - sizeof(struct board) - sizeof (((struct board *)0)->links) - ); + memcpy(board_to, board_from, + sizeof(struct board) - sizeof(((struct board *)0)->links)); } diff --git a/board.h b/board.h index f1042ac..848e179 100644 --- a/board.h +++ b/board.h @@ -6,18 +6,18 @@ #include - -#define ELEM_POS(x, y) (((y) * 9) + (x)) +#define ELEM_POS(x, y) (((y)*9) + (x)) /** * Get a `struct board_element`-entry from a specified location on the board */ -#define BOARD_ELEM(board_ptr, x, y) (&(board_ptr)->elements[ELEM_POS (x, y)]) +#define BOARD_ELEM(board_ptr, x, y) (&(board_ptr)->elements[ELEM_POS(x, y)]) /** * Get a `struct metadata`-entry from a specified location on the quadrand grid */ -#define BOARD_QUAD(board_ptr, x, y) (&(board_ptr)->meta_quad[TO_QUAD ((y)) + ((x) / 3)]) +#define BOARD_QUAD(board_ptr, x, y) \ + (&(board_ptr)->meta_quad[TO_QUAD((y)) + ((x) / 3)]) /** * Get a `struct metadata`-entry from a specified row value @@ -29,7 +29,6 @@ */ #define BOARD_COL(board_ptr, x) (&(board_ptr)->meta_col[(x)]) - /** * Convert any valid board position to a quadrant base position (lowest index) */ @@ -48,21 +47,21 @@ typedef unsigned char element_value; * of 3 */ struct board_element { - bool has_value : 1; /* Whether element has a decided value */ + bool has_value : 1; /* Whether element has a decided value */ - element_value value : 4; /* Value of element */ - unsigned short potential : 9; /* Bitfield of possible values*/ - unsigned char complexity : 4; /* Complexity tracker */ + element_value value : 4; /* Value of element */ + unsigned short potential : 9; /* Bitfield of possible values*/ + unsigned char complexity : 4; /* Complexity tracker */ }; /** * Board region metadata */ struct metadata { - unsigned short marked : 9; /* Which values have been marked */ - struct { /* Unique potentials */ - unsigned char count : 2; /* Whether or not a potential is unique */ - unsigned char index : 3; /* Metadata index. Context-specific */ + unsigned short marked : 9; /* Which values have been marked */ + struct { /* Unique potentials */ + unsigned char count : 2; /* Whether or not a potential is unique */ + unsigned char index : 3; /* Metadata index. Context-specific */ } unique[9]; }; @@ -74,220 +73,141 @@ struct metadata { */ struct board { /* Immediate data*/ - struct board_element elements[81]; /* Game board */ - unsigned char complexity : 4; /* Complexity of simplest element */ + struct board_element elements[81]; /* Game board */ + unsigned char complexity : 4; /* Complexity of simplest element */ /* Metadata */ - struct metadata meta_quad [9]; /* Quadrant metadata */ - struct metadata meta_row [9]; /* Row metadata */ - struct metadata meta_col [9]; /* Column metadata */ + struct metadata meta_quad[9]; /* Quadrant metadata */ + struct metadata meta_row[9]; /* Row metadata */ + struct metadata meta_col[9]; /* Column metadata */ - - struct board_element *links [81][20];/* All "connected", "adjacent" elements */ + struct board_element + *links[81][20]; /* All "connected", "adjacent" elements */ }; - /** * Initialize metadata to a blank state */ -void -meta_init (struct metadata *meta); - +void meta_init(struct metadata *meta); /* * Just generate board element adjacency links */ -void -board_make_links (struct board *board); - +void board_make_links(struct board *board); /** * Initialize a board to a blank state with maximum complexity */ -void -board_init (struct board *board); - +void board_init(struct board *board); /** * Check if a metadata structure has marked a given value */ -bool -meta_has_value (const struct metadata *meta, element_value value); - +bool meta_has_value(const struct metadata *meta, element_value value); /** * Set value as marked for the given metadata structure */ -void -meta_set_value (struct metadata *meta, element_value value); - +void meta_set_value(struct metadata *meta, element_value value); /** * Clear all marked values for the given metadata structure */ -void -meta_clear_values (struct metadata *meta); - +void meta_clear_values(struct metadata *meta); /** * Refresh metadata for a given quadrant */ -void -board_meta_quad_refresh (struct board *board, board_pos qx, board_pos qy); - +void board_meta_quad_refresh(struct board *board, board_pos qx, board_pos qy); /** * Refresh metadata for a given row */ -void -board_meta_row_refresh (struct board *board, board_pos y); - +void board_meta_row_refresh(struct board *board, board_pos y); /** * Refresh metadata for a given column */ -void -board_meta_col_refresh (struct board *board, board_pos x); - +void board_meta_col_refresh(struct board *board, board_pos x); /** * Check if a value can be set at a given position on the board based on * analysing the metadata structures of `board` */ -bool -board_meta_can_set ( - const struct board *board, - board_pos x, - board_pos y, - element_value value -); - +bool board_meta_can_set(const struct board *board, board_pos x, board_pos y, + element_value value); /** * Set the value of an element on the board - * + * * NOTE: This marks an element as having a decided value */ -void -board_set ( - struct board *board, - board_pos x, - board_pos y, - element_value value -); +void board_set(struct board *board, board_pos x, board_pos y, + element_value value); /** * Mark a potential value of an element on the board * * NOTE: Marking an element with a decided value is undefined */ -void -board_mark ( - struct board *board, - board_pos x, - board_pos y, - element_value value -); - +void board_mark(struct board *board, board_pos x, board_pos y, + element_value value); /** * Removes a marking of a potential value of an element on the board * * NOTE: Unmarking an element with a decied value is undefined */ -bool -board_unmark ( - struct board *board, - board_pos x, - board_pos y, - element_value value -); - +bool board_unmark(struct board *board, board_pos x, board_pos y, + element_value value); /** * Removes a marking of a potential value of an element */ -bool -elem_unmark ( - struct board_element *elem, - element_value value -); - +bool elem_unmark(struct board_element *elem, element_value value); /** * Get whether or not an element has a decided value */ -bool -board_has_value ( - const struct board *board, - board_pos x, - board_pos y -); - +bool board_has_value(const struct board *board, board_pos x, board_pos y); /** * Get definite value of a board element * * NOTE: Getting the definite value of an element without a value is undefined */ -element_value -board_get_value ( - const struct board *board, - board_pos x, - board_pos y -); - +element_value board_get_value(const struct board *board, board_pos x, + board_pos y); /** * Get whether or not a board element is marked with a particular value * * NOTE: Getting the mark state of an element with a value is undefined */ -bool -board_is_marked ( - const struct board *board, - board_pos x, - board_pos y, - element_value value -); - +bool board_is_marked(const struct board *board, board_pos x, board_pos y, + element_value value); /** * Get whether or not a given element is marked with a particular value */ -bool -elem_is_marked ( - const struct board_element *elem, - element_value value -); - +bool elem_is_marked(const struct board_element *elem, element_value value); /** * Checks if there are any pairs of board elements that share a value and * also share either a row or a column */ -bool -board_is_valid (struct board *board); - +bool board_is_valid(struct board *board); /** * Check row and column of given position and mark potential values that could * be set at that position and still leave the board in a valid state */ -void -board_update_marks ( - struct board *board, - board_pos x, - board_pos y -); - +void board_update_marks(struct board *board, board_pos x, board_pos y); /** * Refreshes marks of all board elements without a value */ -void -board_update_all_marks (struct board *board); - +void board_update_all_marks(struct board *board); /** * Attempt to set value at the given position @@ -296,14 +216,8 @@ board_update_all_marks (struct board *board); * the addition of this value and returns true * If value cannot be placed, just return false */ -bool -board_place ( - struct board *board, - board_pos x, - board_pos y, - element_value value -); - +bool board_place(struct board *board, board_pos x, board_pos y, + element_value value); /** * Place a speculative value. This allocates a duplicate board with the element @@ -312,26 +226,18 @@ board_place ( * * NOTE: If element cannot be placed, this returns NULL */ -struct board * -board_place_speculative ( - const struct board *board, - struct board *board_duplicate, - board_pos x, - board_pos y, - element_value value -); - +struct board *board_place_speculative(const struct board *board, + struct board *board_duplicate, + board_pos x, board_pos y, + element_value value); /** * Recomputes board complexity by searching all elements on board for the * lowest complexity */ -bool -board_refresh_complexity (struct board *board); - +bool board_refresh_complexity(struct board *board); /** * Copy a board layout to another board */ -void -board_copy (const struct board *board_from, struct board *board_to); +void board_copy(const struct board *board_from, struct board *board_to); diff --git a/main.c b/main.c index d2f1bab..4440409 100644 --- a/main.c +++ b/main.c @@ -1,3 +1,4 @@ +#include "board.h" #include #include #include @@ -6,16 +7,13 @@ #include #include #include -#include "board.h" - /** * ANSI control codes */ -#define COLOUR_RED "\e[31m" -#define COLOUR_RESET "\e[0m" -#define CLEAR "\033[2J" - +#define COLOUR_RED "\e[31m" +#define COLOUR_RESET "\e[0m" +#define CLEAR "\033[2J" /** * How many boards to allocate by default for board spec @@ -29,26 +27,20 @@ */ #define DEPTH_INCREMENT 3 - - struct args { bool valid; unsigned verbosity : 2; char *file_name; }; - struct boards_table { struct board **board_specs; unsigned long long max_depth; }; - -void -tables_ensure_depth (struct boards_table *board_spec, unsigned long long depth) -{ - if (board_spec->max_depth <= depth) - { +void tables_ensure_depth(struct boards_table *board_spec, + unsigned long long depth) { + if (board_spec->max_depth <= depth) { /* Compute new max depth */ unsigned long long new_max; if (board_spec->max_depth == 0) @@ -57,16 +49,13 @@ tables_ensure_depth (struct boards_table *board_spec, unsigned long long depth) new_max = board_spec->max_depth + DEPTH_INCREMENT; /* Disregard NULL return value. What's it gonna do, segfault? :P */ - board_spec->board_specs = realloc ( - board_spec->board_specs, - sizeof (struct board *) * new_max - ); + board_spec->board_specs = + realloc(board_spec->board_specs, sizeof(struct board *) * new_max); /* Allocate boards */ - for (unsigned long long l = board_spec->max_depth; l < new_max; ++l) - { - board_spec->board_specs[l] = malloc (sizeof (struct board)); - board_make_links (board_spec->board_specs[l]); + for (unsigned long long l = board_spec->max_depth; l < new_max; ++l) { + board_spec->board_specs[l] = malloc(sizeof(struct board)); + board_make_links(board_spec->board_specs[l]); } /* Update max depth */ @@ -74,56 +63,39 @@ tables_ensure_depth (struct boards_table *board_spec, unsigned long long depth) } } -bool -simplify ( - struct boards_table *board_spec, - unsigned long long depth, - unsigned long long *counter, - unsigned verbosity -); +bool simplify(struct boards_table *board_spec, unsigned long long depth, + unsigned long long *counter, unsigned verbosity); - -struct board_file -{ +struct board_file { int fd; void *data; }; - /** * Determines if the given char is a valid character for defining * a board element */ -static inline bool -is_valid_def (char def) -{ - return def == ' ' || - ( - def >= '0' && - def <= '9' - ); +static inline bool is_valid_def(char def) { + return def == ' ' || (def >= '0' && def <= '9'); } /** * Load a board-definition file and return file descriptor */ -static struct board_file -load_board_file (const char *path) -{ +static struct board_file load_board_file(const char *path) { struct board_file file; file.fd = -1; file.data = NULL; /* Open file */ - int fd = open (path, 0); + int fd = open(path, 0); if (fd < 0) return file; /* Map 89 bytes of file to memory */ - void *region = mmap (NULL, 89, PROT_READ, MAP_SHARED, fd, 0); - if (region == (void*)-1) - { - close (fd); + void *region = mmap(NULL, 89, PROT_READ, MAP_SHARED, fd, 0); + if (region == (void *)-1) { + close(fd); return file; } @@ -134,10 +106,9 @@ load_board_file (const char *path) */ char *data = region; for (unsigned i = 1; i <= 89; ++i) - if (!((i % 10) == 0) && !is_valid_def (data[i - 1])) - { - munmap (region, 89); - close (fd); + if (!((i % 10) == 0) && !is_valid_def(data[i - 1])) { + munmap(region, 89); + close(fd); return file; } @@ -151,265 +122,200 @@ load_board_file (const char *path) /** * Free all resources linked to an opened board definition file */ -static void -close_board_file (struct board_file file) -{ - close (file.fd); - munmap (file.data, 89); +static void close_board_file(struct board_file file) { + close(file.fd); + munmap(file.data, 89); } -static void -copy_to_board (struct board_file file, struct board *board) -{ +static void copy_to_board(struct board_file file, struct board *board) { // Clear board - board_init (board); + board_init(board); char *data = file.data; for (unsigned i = 1; i <= 89; ++i) - if ((i % 10) != 0) - { + if ((i % 10) != 0) { board_pos x = i % 10; board_pos y = i / 10; if (data[i - 1] != ' ') - board_place (board, x - 1, y, data[i - 1] - '0' - 1); + board_place(board, x - 1, y, data[i - 1] - '0' - 1); } } - -static void -ansi_set_cursor (unsigned y, unsigned x) -{ - printf ("\033[%u;%uH", x + 1, y + 1); +static void ansi_set_cursor(unsigned y, unsigned x) { + printf("\033[%u;%uH", x + 1, y + 1); } +static void ansi_clear_screen() { puts(CLEAR); } -static void -ansi_clear_screen () -{ - puts (CLEAR); -} - - -void -ansi_cursor_show (bool show) -{ +void ansi_cursor_show(bool show) { if (show) fputs("\e[?25h", stdout); else fputs("\e[?25l", stdout); } -static void -print_board_verbose ( - const struct board *board, - unsigned whence_x, - unsigned whence_y -) -{ - for (board_pos y = 0; y < 9; ++y) - { - for (board_pos x = 0; x < 9; ++x) - { +static void print_board_verbose(const struct board *board, unsigned whence_x, + unsigned whence_y) { + for (board_pos y = 0; y < 9; ++y) { + for (board_pos x = 0; x < 9; ++x) { for (element_value vy = 0; vy < 3; ++vy) - for (element_value vx = 0; vx < 3; ++vx) - { + for (element_value vx = 0; vx < 3; ++vx) { element_value check = vx + (vy * 3); - ansi_set_cursor (whence_x + (x * 4) + vx, whence_y + (y * 4) + vy); - - if (board_has_value (board, x, y)) - printf ("%u", board_get_value (board, x, y) + 1); - else if (board_is_marked (board, x, y, check)) - printf (COLOUR_RED "%u" COLOUR_RESET, check + 1); + ansi_set_cursor(whence_x + (x * 4) + vx, whence_y + (y * 4) + vy); + + if (board_has_value(board, x, y)) + printf("%u", board_get_value(board, x, y) + 1); + else if (board_is_marked(board, x, y, check)) + printf(COLOUR_RED "%u" COLOUR_RESET, check + 1); else - fputs (" ", stdout); + fputs(" ", stdout); if (vx == 2 && x != 8) - fputs ("|", stdout); + fputs("|", stdout); } } - - ansi_set_cursor (0, (y * 4) + 3); - if (y != 8) - { + + ansi_set_cursor(0, (y * 4) + 3); + if (y != 8) { for (unsigned i = 0; i < (4 * 9) - 1; ++i) if ((i + 1) % 4 == 0) - fputs ("+", stdout); + fputs("+", stdout); else - fputs ("-", stdout); + fputs("-", stdout); } } - fflush (stdout); + fflush(stdout); } - -static void -print_board (const struct board *board, const struct board *compare, unsigned whence_x, unsigned whence_y) -{ - for (board_pos y = 0; y < 9; ++y) - { +static void print_board(const struct board *board, const struct board *compare, + unsigned whence_x, unsigned whence_y) { + for (board_pos y = 0; y < 9; ++y) { /* Print row */ - for (board_pos x = 0; x < 9; ++x) - { - ansi_set_cursor (whence_x + (x * 2), whence_y + (y * 2)); + for (board_pos x = 0; x < 9; ++x) { + ansi_set_cursor(whence_x + (x * 2), whence_y + (y * 2)); /* Print board element */ - if (board_has_value (board, x, y)) - { - if (compare != NULL && ! board_has_value (compare, x, y)) - printf (COLOUR_RED "%u" COLOUR_RESET, board_get_value (board, x, y) + 1); + if (board_has_value(board, x, y)) { + if (compare != NULL && !board_has_value(compare, x, y)) + printf(COLOUR_RED "%u" COLOUR_RESET, + board_get_value(board, x, y) + 1); else - printf ("%u", board_get_value (board, x, y) + 1); - } - else - fputs (" ", stdout); + printf("%u", board_get_value(board, x, y) + 1); + } else + fputs(" ", stdout); /* Print column element delimiter */ if (x < 8) fputs("|", stdout); } - + /* Print row element delimiter */ - if (y < 8) - { - for (board_pos x = 0; x < 17; ++x) - { - ansi_set_cursor (whence_x + x, whence_y + (y * 2 + 1)); + if (y < 8) { + for (board_pos x = 0; x < 17; ++x) { + ansi_set_cursor(whence_x + x, whence_y + (y * 2 + 1)); if ((x & 1) == 0) - fputs ("-", stdout); + fputs("-", stdout); else - fputs ("+", stdout); + fputs("+", stdout); } } } } - /** * Compute first potential value of a given element */ -element_value -first_potential_value (struct board_element *element, struct board *board, bool *error) -{ +element_value first_potential_value(struct board_element *element, + struct board *board, bool *error) { unsigned short potential = element->potential; - if (potential == 0) - { + if (potential == 0) { *error = true; return 0; } *error = false; - + element_value value = 0; - while (potential != 0) - { + while (potential != 0) { if ((potential & 1) == 1) return value; ++value; potential >>= 1; } - + /* Unreachable */ abort(); } - /** * Reduce away all elements on board with complexity=1 until none remain */ #ifdef NOVERB -bool -simplify ( - struct boards_table *board_specs, - unsigned long long depth -) +bool simplify(struct boards_table *board_specs, unsigned long long depth) #else -bool -simplify ( - struct boards_table *board_specs, - unsigned long long depth, - unsigned long long *counter, - unsigned verbosity -) +bool simplify(struct boards_table *board_specs, unsigned long long depth, + unsigned long long *counter, unsigned verbosity) #endif { /* Get current table */ struct board *board = board_specs->board_specs[depth]; #ifndef NOVERB - if (verbosity > 0) - { - if (((*counter) & (0xFFFF >> (4 * (4 - verbosity)))) == 0) - { - print_board_verbose (board, 0, 0); - ansi_set_cursor (0, 35); - printf ("Iteration: %llu", *counter); + if (verbosity > 0) { + if (((*counter) & (0xFFFF >> (4 * (4 - verbosity)))) == 0) { + print_board_verbose(board, 0, 0); + ansi_set_cursor(0, 35); + printf("Iteration: %llu", *counter); } *counter += 1; } #endif - bool error; unsigned count = 0; /* Reduce using low-complexity computation */ - while (board->complexity == 1) - { + while (board->complexity == 1) { for (board_pos y = 0; y < 9; ++y) for (board_pos x = 0; x < 9; ++x) - if (! board_has_value (board, x, y)) - { - struct board_element *elem = BOARD_ELEM (board, x, y); - if (elem->complexity == 1) - { - element_value value = first_potential_value (elem, board, &error); - if (error) return false; + if (!board_has_value(board, x, y)) { + struct board_element *elem = BOARD_ELEM(board, x, y); + if (elem->complexity == 1) { + element_value value = first_potential_value(elem, board, &error); + if (error) + return false; ++count; - if (! board_place (board, x, y, value)) + if (!board_place(board, x, y, value)) return false; } } - board_refresh_complexity (board); + board_refresh_complexity(board); } /* Attempt to reduce with speculative placement */ - if (board->complexity > 1) - { + if (board->complexity > 1) { for (board_pos y = 0; y < 9; ++y) - for (board_pos x = 0; x < 9; ++x) - { - struct board_element *elem = BOARD_ELEM (board, x, y); + for (board_pos x = 0; x < 9; ++x) { + struct board_element *elem = BOARD_ELEM(board, x, y); /* Find a simplest element on the board */ - if ( - ! elem->has_value && - elem->complexity == board->complexity - ) - for (element_value value = 0; value < 9; ++value) - { + if (!elem->has_value && elem->complexity == board->complexity) + for (element_value value = 0; value < 9; ++value) { /* Try speculative placement of each potential value and recurse */ - tables_ensure_depth (board_specs, depth + 1); - if (elem_is_marked (elem, value)) - { - struct board *board_spec = - board_place_speculative ( - board, - board_specs->board_specs[depth + 1], - x, - y, - value - ); + tables_ensure_depth(board_specs, depth + 1); + if (elem_is_marked(elem, value)) { + struct board *board_spec = board_place_speculative( + board, board_specs->board_specs[depth + 1], x, y, value); /* If speculative placement failed, try another value */ - if (board_spec == NULL) - { - if (! elem_unmark (elem, value)) + if (board_spec == NULL) { + if (!elem_unmark(elem, value)) return false; continue; } @@ -418,26 +324,16 @@ simplify ( if ( #ifdef NOVERB - simplify ( - board_specs, - depth + 1 - ) && + simplify(board_specs, depth + 1) && #else - simplify ( - board_specs, - depth + 1, - counter, - verbosity - ) && + simplify(board_specs, depth + 1, counter, verbosity) && #endif - board_spec->complexity == 0) - { - board_copy (board_spec, board); + board_spec->complexity == 0) { + board_copy(board_spec, board); x = 9; y = 9; value = 9; - } - else if (! elem_unmark (elem, value)) + } else if (!elem_unmark(elem, value)) return false; } } @@ -446,65 +342,52 @@ simplify ( return true; } - -struct args -argparse (int argc, char **argv) -{ +struct args argparse(int argc, char **argv) { struct args result; result.file_name = NULL; result.valid = true; result.verbosity = 0; - if (argc < 2) - { + if (argc < 2) { result.valid = false; return result; } for (int i = 1; i < argc; ++i) - if (strncmp (argv[i], "-", 1) == 0) - { - if (result.verbosity != 0) - { + if (strncmp(argv[i], "-", 1) == 0) { + if (result.verbosity != 0) { result.valid = false; return result; } - if (strcmp (argv[i], "-v") == 0) + if (strcmp(argv[i], "-v") == 0) result.verbosity = 1; - else if (strcmp (argv[i], "-vv") == 0) + else if (strcmp(argv[i], "-vv") == 0) result.verbosity = 2; - else - { + else { result.valid = false; return result; } - } - else if (result.file_name == NULL) + } else if (result.file_name == NULL) result.file_name = argv[i]; - else - { + else { result.valid = false; return result; } return result; } - - -int -main (int argc, char **argv, char **env) -{ - struct args args = argparse (argc, argv); - if (! args.valid) - { - fputs ("Badly formatted arguments! Usage:\n\t./sudoku [-v[v]] {file name}\n", stderr); +int main(int argc, char **argv, char **env) { + struct args args = argparse(argc, argv); + if (!args.valid) { + fputs("Badly formatted arguments! Usage:\n\t./sudoku [-v[v]] {file name}\n", + stderr); return 1; } - - struct board_file file = load_board_file (args.file_name); + + struct board_file file = load_board_file(args.file_name); if (file.fd == -1 || file.data == NULL) return -1; - ansi_cursor_show (false); + ansi_cursor_show(false); /* Allocate boards */ struct board original; @@ -512,62 +395,54 @@ main (int argc, char **argv, char **env) struct boards_table boards; boards.max_depth = 0; boards.board_specs = NULL; - tables_ensure_depth (&boards, 0); + tables_ensure_depth(&boards, 0); struct board *root_board = boards.board_specs[0]; - copy_to_board (file, &original); - board_copy (&original, boards.board_specs[0]); + copy_to_board(file, &original); + board_copy(&original, boards.board_specs[0]); - close_board_file (file); + close_board_file(file); + ansi_clear_screen(); + if (!board_is_valid(root_board)) { + fputs("Supplied board is not valid!\n", stderr); - ansi_clear_screen (); - - if (! board_is_valid (root_board)) - { - fputs ("Supplied board is not valid!\n", stderr); + ansi_cursor_show(true); - ansi_cursor_show (true); - return 1; } - if (args.verbosity == 0) - puts ("Simplifying..."); + puts("Simplifying..."); - - board_refresh_complexity (root_board); + board_refresh_complexity(root_board); /* Profiler start time */ - clock_t start_clk = clock (); + clock_t start_clk = clock(); unsigned long long counter = 0; - - simplify (&boards, 0, &counter, args.verbosity); + + simplify(&boards, 0, &counter, args.verbosity); /* Profiler end time */ - clock_t end_clk = clock (); + clock_t end_clk = clock(); - ansi_clear_screen (); + ansi_clear_screen(); - if (root_board->complexity == 0) - { - print_board (&original, NULL, 0, 0); - print_board (root_board, &original, 21, 0); - ansi_set_cursor (0, 18); + if (root_board->complexity == 0) { + print_board(&original, NULL, 0, 0); + print_board(root_board, &original, 21, 0); + ansi_set_cursor(0, 18); + } else { + print_board_verbose(root_board, 0, 0); + ansi_set_cursor(0, 36); } - else - { - print_board_verbose (root_board, 0, 0); - ansi_set_cursor (0, 36); - } - printf ("Simplification took %Lf seconds\n", ((long double)(end_clk - start_clk))/CLOCKS_PER_SEC); + printf("Simplification took %Lf seconds\n", + ((long double)(end_clk - start_clk)) / CLOCKS_PER_SEC); - - ansi_cursor_show (true); + ansi_cursor_show(true); return 0; }