This commit is contained in:
spv 2024-03-07 13:19:48 +01:00
parent 7b55d6e67a
commit ed962f5b09
3 changed files with 405 additions and 837 deletions

605
board.c
View File

@ -4,21 +4,19 @@
* Created by Gabriel Tofvesson * Created by Gabriel Tofvesson
*/ */
#include "board.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "board.h"
/** /**
* Raises an error by printing it to stderr and stopping execution * Raises an error by printing it to stderr and stopping execution
*/ */
#define ERROR(reason) \ #define ERROR(reason) \
{ \ { \
fprintf(stderr, "ERROR: %s\n", reason); \ fprintf(stderr, "ERROR: %s\n", reason); \
abort(); \ abort(); \
} }
/** /**
* Raises an error if the given condition is not met * Raises an error if the given condition is not met
@ -27,306 +25,208 @@
#ifdef OPTIMIZE #ifdef OPTIMIZE
#define ASSERT(cond, reason) #define ASSERT(cond, reason)
#else #else
#define ASSERT(cond, reason) \ #define ASSERT(cond, reason) \
{ \ { \
if (! cond) ERROR ((reason)); \ if (!cond) \
} ERROR((reason)); \
}
#endif #endif
/** /**
* Check if a given xy-pair is in bounds of a Sudoku board * Check if a given xy-pair is in bounds of a Sudoku board
*/ */
static inline bool static inline bool is_in_bounds(board_pos x, board_pos y) {
is_in_bounds (board_pos x, board_pos y)
{
#ifdef OPTIMIZE #ifdef OPTIMIZE
return true; return true;
#else #else
return x >= 0 && return x >= 0 && x < 9 && y >= 0 && y < 9;
x < 9 &&
y >= 0 &&
y < 9 ;
#endif #endif
} }
/** /**
* Check if a given element value is within acceptable bounds * Check if a given element value is within acceptable bounds
*/ */
static inline bool static inline bool is_valid_value(element_value value) {
is_valid_value (element_value value)
{
#ifdef OPTIMIZE #ifdef OPTIMIZE
return true; return true;
#else #else
return value >= 0 && return value >= 0 && value < 9;
value < 9 ;
#endif #endif
} }
void meta_init(struct metadata *meta) {
void memset(meta, 0, sizeof(struct metadata));
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 y = 0; y < 9; ++y)
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x) {
{ unsigned pos = ELEM_POS(x, y);
unsigned pos = ELEM_POS (x, y);
unsigned link_count = -1; unsigned link_count = -1;
/* Link column adjacents */ /* Link column adjacents */
for (board_pos lx = 0; lx < 9; ++lx) for (board_pos lx = 0; lx < 9; ++lx)
if (lx != x) 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 */ /* Link column adjacents */
for (board_pos ly = 0; ly < 9; ++ly) for (board_pos ly = 0; ly < 9; ++ly)
if (ly != y) 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 */ /* Link quadrant adjacents */
board_pos qx = TO_QUAD (x); board_pos qx = TO_QUAD(x);
board_pos qy = TO_QUAD (y); board_pos qy = TO_QUAD(y);
for (board_pos lqy = 0; lqy < 3; ++lqy) for (board_pos lqy = 0; lqy < 3; ++lqy)
for (board_pos lqx = 0; lqx < 3; ++lqx) for (board_pos lqx = 0; lqx < 3; ++lqx)
if ((lqx + qx) != x && (lqy + qy) != y) 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; struct board_element defval;
defval.has_value = false; defval.has_value = false;
defval.potential = 0x1FF; defval.potential = 0x1FF;
defval.complexity = 9; defval.complexity = 9;
for (board_pos y = 0; y < 9; ++y) for (board_pos y = 0; y < 9; ++y)
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x) {
{ struct board_element *elem = BOARD_ELEM(board, x, y);
struct board_element *elem = BOARD_ELEM (board, x, y);
/* Set default state */ /* 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; board->complexity = 9;
for (unsigned i = 0; i < 9; ++i) for (unsigned i = 0; i < 9; ++i) {
{ meta_init(&board->meta_quad[i]);
meta_init (&board->meta_quad[i]); meta_init(&board->meta_row[i]);
meta_init (&board->meta_row[i]); meta_init(&board->meta_col[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; 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; meta->marked |= 1 << value;
} }
void meta_clear_values(struct metadata *meta) { meta->marked = 0; }
void static inline void meta_mark(struct metadata *meta, element_value value,
meta_clear_values (struct metadata *meta) unsigned index) {
{ meta_set_value(meta, value);
meta->marked = 0;
}
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; unsigned char count = meta->unique[value].count;
if (count == 0) if (count == 0) {
{
meta->unique[value].count = 1; meta->unique[value].count = 1;
meta->unique[value].index = index; meta->unique[value].index = index;
} } else {
else
{
meta->unique[value].count = 2; meta->unique[value].count = 2;
} }
} }
void board_meta_quad_refresh(struct board *board, board_pos qx, board_pos qy) {
void struct metadata *meta = BOARD_QUAD(board, qx * 3, qy * 3);
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_x = qx * 3;
board_pos quad_base_y = qy * 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_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 = 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) 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 meta_clear_values(meta);
board_meta_row_refresh (struct board *board, board_pos y)
{
struct metadata *meta = BOARD_ROW (board, y);
meta_clear_values (meta);
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x) {
{ struct board_element *elem = BOARD_ELEM(board, x, y);
struct board_element *elem = BOARD_ELEM (board, x, y);
if (elem->has_value) 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 meta_clear_values(meta);
board_meta_col_refresh (struct board *board, board_pos x)
{
struct metadata *meta = BOARD_COL (board, x);
meta_clear_values (meta);
for (board_pos y = 0; y < 9; ++y) for (board_pos y = 0; y < 9; ++y) {
{ struct board_element *elem = BOARD_ELEM(board, x, y);
struct board_element *elem = BOARD_ELEM (board, x, y);
if (elem->has_value) 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,
bool element_value value) {
board_meta_can_set ( if (is_in_bounds(x, y) && is_valid_value(value)) {
const struct board *board, return !(meta_has_value(BOARD_ROW(board, y), value) ||
board_pos x, meta_has_value(BOARD_COL(board, x), value) ||
board_pos y, meta_has_value(BOARD_QUAD(board, x, y), value));
element_value value } else
) ERROR("Invalid parameters to function board_meta_can_set()");
{
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 struct board_element *elem = BOARD_ELEM(board, x, y);
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);
elem->has_value = true; elem->has_value = true;
elem->value = value; elem->value = value;
} } else
else ERROR("Invalid parameters to function board_set()"); 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 struct board_element *elem = BOARD_ELEM(board, x, y);
board_mark ( if (!board_is_marked(board, x, y, value)) {
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))
{
elem->potential |= 1 << value; elem->potential |= 1 << value;
++(elem->complexity); ++(elem->complexity);
} }
} } else
else ERROR("Invalid parameters to function board_mark()"); 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 return elem_unmark(BOARD_ELEM(board, x, y), value);
board_unmark ( } else
struct board *board, ERROR("Invalid parameters to function board_unmark()");
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()");
} }
bool elem_unmark(struct board_element *elem, element_value value) {
bool if (elem_is_marked(elem, value)) {
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 */ /* Shift bit to correct place and then invert first 9 bits */
elem->potential ^= (1 << value); elem->potential ^= (1 << value);
--(elem->complexity); --(elem->complexity);
@ -335,326 +235,219 @@ elem_unmark (
return elem->potential != 0; return elem->potential != 0;
} }
bool board_has_value(const struct board *board, board_pos x, board_pos y) {
bool if (is_in_bounds(x, y)) {
board_has_value ( return BOARD_ELEM(board, x, y)->has_value;
const struct board *board, } else
board_pos x, ERROR("Invalid parameters to function board_has_value()");
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,
element_value board_pos y) {
board_get_value ( if (is_in_bounds(x, y)) {
const struct board *board, return BOARD_ELEM(board, x, y)->value;
board_pos x, } else
board_pos y ERROR("Invalid parameters to function board_get_value()");
)
{
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,
bool element_value value) {
board_is_marked ( if (is_in_bounds(x, y) && is_valid_value(value)) {
const struct board *board, return elem_is_marked(BOARD_ELEM(board, x, y), value);
board_pos x, } else
board_pos y, ERROR("Invalid parameters to function board_is_marked()");
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); 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 y = 0; y < 9; ++y)
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x)
if ( if (!board_has_value(board, x, y) &&
!board_has_value (board, x, y) && BOARD_ELEM(board, x, y)->potential == 0)
BOARD_ELEM (board, x, y)->potential == 0
)
return false; return false;
return true; return true;
} }
void board_update_marks(struct board *board, board_pos x, board_pos y) {
void if (is_in_bounds(x, y)) {
board_update_marks ( struct board_element *elem = BOARD_ELEM(board, x, y);
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 */ /* Mark all values as impossible */
elem->potential = 0; elem->potential = 0;
elem->complexity = 0; elem->complexity = 0;
/* Check x-axis */ /* Check x-axis */
elem->potential |= BOARD_QUAD (board, x, y)->marked; elem->potential |= BOARD_QUAD(board, x, y)->marked;
elem->potential |= BOARD_ROW (board, y)->marked; elem->potential |= BOARD_ROW(board, y)->marked;
elem->potential |= BOARD_COL (board, x)->marked; elem->potential |= BOARD_COL(board, x)->marked;
/* Invert matches */ /* Invert matches */
elem->potential ^= 0x1FF; elem->potential ^= 0x1FF;
/* Count marked bits */ /* Count marked bits */
unsigned short potential = elem->potential; unsigned short potential = elem->potential;
while (potential != 0) while (potential != 0) {
{
if ((potential & 1) == 1) if ((potential & 1) == 1)
++(elem->complexity); ++(elem->complexity);
potential >>= 1; potential >>= 1;
} }
} } else
else ERROR("Invalid parameters to function board_update_marks()"); ERROR("Invalid parameters to function board_update_marks()");
} }
bool board_can_quad_set_value(struct board *board, board_pos x, board_pos y,
bool element_value value) {
board_can_quad_set_value ( if (is_in_bounds(x, y) && is_valid_value(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 */ /* Compute quadrant bases */
board_pos quad_x = TO_QUAD (x); board_pos quad_x = TO_QUAD(x);
board_pos quad_y = TO_QUAD (y); board_pos quad_y = TO_QUAD(y);
/* Compute sub-quadrant positions */ /* Compute sub-quadrant positions */
board_pos simp_x = x % 3; board_pos simp_x = x % 3;
board_pos simp_y = y % 3; board_pos simp_y = y % 3;
bool next = false; bool next = false;
/* Check along x-axis */ /* 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; next = false;
if (base_x != quad_x) if (base_x != quad_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)
if (check_y != simp_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_x = base_x + check_x;
board_pos target_y = quad_y + check_y; 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 */ /* Check if a quadrant can contain the given value */
if ( if ((has_value &&
( BOARD_ELEM(board, target_x, target_y)->value == value) ||
has_value && (!has_value &&
BOARD_ELEM (board, target_x, target_y)->value == value board_is_marked(board, target_x, target_y, value))) {
) ||
(
! has_value &&
board_is_marked (board, target_x, target_y, value)
)
)
{
next = true; next = true;
break; break;
} }
} }
if (! next) if (!next)
return false; return false;
} }
} }
/* Check along y-axis */ /* 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; next = false;
if (base_y != quad_y) if (base_y != quad_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)
if (check_x != simp_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_x = quad_x + check_x;
board_pos target_y = base_y + check_y; 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 */ /* Check if a quadrant can contain the given value */
if ( if ((has_value &&
( BOARD_ELEM(board, target_x, target_y)->value == value) ||
has_value && (!has_value &&
BOARD_ELEM (board, target_x, target_y)->value == value board_is_marked(board, target_x, target_y, value))) {
) ||
(
! has_value &&
board_is_marked (board, target_x, target_y, value)
)
)
{
next = true; next = true;
break; break;
} }
} }
if (! next) if (!next)
return false; return false;
} }
} }
return true; return true;
} } else
else ERROR("Invalid parameters to function board_can_quad_set_value()"); ERROR("Invalid parameters to function board_can_quad_set_value()");
} }
static inline bool field_is_potential(unsigned short field,
static inline bool element_value value) {
field_is_potential (unsigned short field, element_value value)
{
return ((field >> (value * 2)) & 3) < 2; return ((field >> (value * 2)) & 3) < 2;
} }
static inline void field_invalidate(unsigned short *field,
static inline void element_value value) {
field_invalidate (unsigned short *field, element_value value)
{
*field |= 2 << (value * 2); *field |= 2 << (value * 2);
} }
static inline void field_increment(unsigned short *field, element_value value) {
static inline void if (field_is_potential(*field, value))
field_increment (unsigned short *field, element_value value)
{
if (field_is_potential (*field, value))
*field += (1 << (value * 2)); *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 y = 0; y < 9; ++y)
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x)
if (! board_has_value (board, x, y)) if (!board_has_value(board, x, y))
board_update_marks (board, x, y); board_update_marks(board, x, y);
} }
bool board_place(struct board *board, board_pos x, board_pos y,
bool element_value value) {
board_place ( if (is_in_bounds(x, y) && is_valid_value(value)) {
struct board *board, if (board_meta_can_set(board, x, y, value)) {
board_pos x, unsigned pos = ELEM_POS(x, y);
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 */ /* Unmark all adjacent elements */
for (unsigned i = 0; i < 20; ++i) for (unsigned i = 0; i < 20; ++i)
if ( if (!board->links[pos][i]->has_value &&
! board->links[pos][i]->has_value && !elem_unmark(board->links[pos][i], value)) {
! elem_unmark (board->links[pos][i], value)
)
{
/* Unmarking potential caused element to have no potential */ /* Unmarking potential caused element to have no potential */
return false; return false;
} }
/* Set value */ /* Set value */
board_set (board, x, y, value); board_set(board, x, y, value);
/* Update metadata */ /* Update metadata */
meta_set_value (BOARD_QUAD (board, x, y), value); meta_set_value(BOARD_QUAD(board, x, y), value);
meta_set_value (BOARD_ROW (board, y), value); meta_set_value(BOARD_ROW(board, y), value);
meta_set_value (BOARD_COL (board, x), value); meta_set_value(BOARD_COL(board, x), value);
return true; return true;
} } else
else return false; return false;
} } else
else ERROR("Invalid parameters to function board_place()"); ERROR("Invalid parameters to function board_place()");
} }
struct board *board_place_speculative(const struct board *board,
struct board * struct board *board_duplicate,
board_place_speculative ( board_pos x, board_pos y,
const struct board *board, element_value value) {
struct board *board_duplicate, if (is_in_bounds(x, y) && is_valid_value(value)) {
board_pos x,
board_pos y,
element_value value
)
{
if (is_in_bounds (x, y) && is_valid_value (value))
{
/* Ensure value can be placed*/ /* 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 */ /* 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; return NULL;
board_refresh_complexity (board_duplicate); board_refresh_complexity(board_duplicate);
return board_duplicate; return board_duplicate;
} } else
else return NULL; return NULL;
} } else
else ERROR("Invalid parameters to function board_place_speculative()"); 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; board->complexity = 10;
for (board_pos y = 0; y < 9; ++y) for (board_pos y = 0; y < 9; ++y)
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x)
if (! board_has_value (board, x, y)) if (!board_has_value(board, x, y)) {
{ struct board_element *elem = BOARD_ELEM(board, x, y);
struct board_element *elem = BOARD_ELEM (board, x, y); if (elem->complexity < board->complexity) {
if (elem->complexity < board->complexity)
{
/* If complexity is somehow 0, we have an invalid board state */ /* If complexity is somehow 0, we have an invalid board state */
if (elem->complexity == 0) if (elem->complexity == 0)
return false; return false;
@ -674,14 +467,8 @@ board_refresh_complexity (struct board *board)
return true; 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 */ /* Copy everything except the links */
memcpy ( memcpy(board_to, board_from,
board_to, sizeof(struct board) - sizeof(((struct board *)0)->links));
board_from,
sizeof(struct board) - sizeof (((struct board *)0)->links)
);
} }

204
board.h
View File

@ -6,18 +6,18 @@
#include <stdbool.h> #include <stdbool.h>
#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 * 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 * 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 * 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)]) #define BOARD_COL(board_ptr, x) (&(board_ptr)->meta_col[(x)])
/** /**
* Convert any valid board position to a quadrant base position (lowest index) * Convert any valid board position to a quadrant base position (lowest index)
*/ */
@ -48,21 +47,21 @@ typedef unsigned char element_value;
* of 3 * of 3
*/ */
struct board_element { 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 */ element_value value : 4; /* Value of element */
unsigned short potential : 9; /* Bitfield of possible values*/ unsigned short potential : 9; /* Bitfield of possible values*/
unsigned char complexity : 4; /* Complexity tracker */ unsigned char complexity : 4; /* Complexity tracker */
}; };
/** /**
* Board region metadata * Board region metadata
*/ */
struct metadata { struct metadata {
unsigned short marked : 9; /* Which values have been marked */ unsigned short marked : 9; /* Which values have been marked */
struct { /* Unique potentials */ struct { /* Unique potentials */
unsigned char count : 2; /* Whether or not a potential is unique */ unsigned char count : 2; /* Whether or not a potential is unique */
unsigned char index : 3; /* Metadata index. Context-specific */ unsigned char index : 3; /* Metadata index. Context-specific */
} unique[9]; } unique[9];
}; };
@ -74,220 +73,141 @@ struct metadata {
*/ */
struct board { struct board {
/* Immediate data*/ /* Immediate data*/
struct board_element elements[81]; /* Game board */ struct board_element elements[81]; /* Game board */
unsigned char complexity : 4; /* Complexity of simplest element */ unsigned char complexity : 4; /* Complexity of simplest element */
/* Metadata */ /* Metadata */
struct metadata meta_quad [9]; /* Quadrant metadata */ struct metadata meta_quad[9]; /* Quadrant metadata */
struct metadata meta_row [9]; /* Row metadata */ struct metadata meta_row[9]; /* Row metadata */
struct metadata meta_col [9]; /* Column metadata */ struct metadata meta_col[9]; /* Column metadata */
struct board_element
struct board_element *links [81][20];/* All "connected", "adjacent" elements */ *links[81][20]; /* All "connected", "adjacent" elements */
}; };
/** /**
* Initialize metadata to a blank state * Initialize metadata to a blank state
*/ */
void void meta_init(struct metadata *meta);
meta_init (struct metadata *meta);
/* /*
* Just generate board element adjacency links * Just generate board element adjacency links
*/ */
void void board_make_links(struct board *board);
board_make_links (struct board *board);
/** /**
* Initialize a board to a blank state with maximum complexity * Initialize a board to a blank state with maximum complexity
*/ */
void void board_init(struct board *board);
board_init (struct board *board);
/** /**
* Check if a metadata structure has marked a given value * Check if a metadata structure has marked a given value
*/ */
bool bool meta_has_value(const struct metadata *meta, element_value value);
meta_has_value (const struct metadata *meta, element_value value);
/** /**
* Set value as marked for the given metadata structure * Set value as marked for the given metadata structure
*/ */
void void meta_set_value(struct metadata *meta, element_value value);
meta_set_value (struct metadata *meta, element_value value);
/** /**
* Clear all marked values for the given metadata structure * Clear all marked values for the given metadata structure
*/ */
void void meta_clear_values(struct metadata *meta);
meta_clear_values (struct metadata *meta);
/** /**
* Refresh metadata for a given quadrant * Refresh metadata for a given quadrant
*/ */
void void board_meta_quad_refresh(struct board *board, board_pos qx, board_pos qy);
board_meta_quad_refresh (struct board *board, board_pos qx, board_pos qy);
/** /**
* Refresh metadata for a given row * Refresh metadata for a given row
*/ */
void void board_meta_row_refresh(struct board *board, board_pos y);
board_meta_row_refresh (struct board *board, board_pos y);
/** /**
* Refresh metadata for a given column * Refresh metadata for a given column
*/ */
void void board_meta_col_refresh(struct board *board, board_pos x);
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 * Check if a value can be set at a given position on the board based on
* analysing the metadata structures of `board` * analysing the metadata structures of `board`
*/ */
bool bool board_meta_can_set(const struct board *board, board_pos x, board_pos y,
board_meta_can_set ( element_value value);
const struct board *board,
board_pos x,
board_pos y,
element_value value
);
/** /**
* Set the value of an element on the board * Set the value of an element on the board
* *
* NOTE: This marks an element as having a decided value * NOTE: This marks an element as having a decided value
*/ */
void void board_set(struct board *board, board_pos x, board_pos y,
board_set ( element_value value);
struct board *board,
board_pos x,
board_pos y,
element_value value
);
/** /**
* Mark a potential value of an element on the board * Mark a potential value of an element on the board
* *
* NOTE: Marking an element with a decided value is undefined * NOTE: Marking an element with a decided value is undefined
*/ */
void void board_mark(struct board *board, board_pos x, board_pos y,
board_mark ( element_value value);
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 * Removes a marking of a potential value of an element on the board
* *
* NOTE: Unmarking an element with a decied value is undefined * NOTE: Unmarking an element with a decied value is undefined
*/ */
bool bool board_unmark(struct board *board, board_pos x, board_pos y,
board_unmark ( element_value value);
struct board *board,
board_pos x,
board_pos y,
element_value value
);
/** /**
* Removes a marking of a potential value of an element * Removes a marking of a potential value of an element
*/ */
bool bool elem_unmark(struct board_element *elem, element_value value);
elem_unmark (
struct board_element *elem,
element_value value
);
/** /**
* Get whether or not an element has a decided value * Get whether or not an element has a decided value
*/ */
bool bool board_has_value(const struct board *board, board_pos x, board_pos y);
board_has_value (
const struct board *board,
board_pos x,
board_pos y
);
/** /**
* Get definite value of a board element * Get definite value of a board element
* *
* NOTE: Getting the definite value of an element without a value is undefined * NOTE: Getting the definite value of an element without a value is undefined
*/ */
element_value element_value board_get_value(const struct board *board, board_pos x,
board_get_value ( board_pos y);
const struct board *board,
board_pos x,
board_pos y
);
/** /**
* Get whether or not a board element is marked with a particular value * 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 * NOTE: Getting the mark state of an element with a value is undefined
*/ */
bool bool board_is_marked(const struct board *board, board_pos x, board_pos y,
board_is_marked ( element_value value);
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 * Get whether or not a given element is marked with a particular value
*/ */
bool bool elem_is_marked(const struct board_element *elem, element_value value);
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 * Checks if there are any pairs of board elements that share a value and
* also share either a row or a column * also share either a row or a column
*/ */
bool bool board_is_valid(struct board *board);
board_is_valid (struct board *board);
/** /**
* Check row and column of given position and mark potential values that could * 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 * be set at that position and still leave the board in a valid state
*/ */
void void board_update_marks(struct board *board, board_pos x, board_pos y);
board_update_marks (
struct board *board,
board_pos x,
board_pos y
);
/** /**
* Refreshes marks of all board elements without a value * Refreshes marks of all board elements without a value
*/ */
void void board_update_all_marks(struct board *board);
board_update_all_marks (struct board *board);
/** /**
* Attempt to set value at the given position * 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 * the addition of this value and returns true
* If value cannot be placed, just return false * If value cannot be placed, just return false
*/ */
bool bool board_place(struct board *board, board_pos x, board_pos y,
board_place ( element_value value);
struct board *board,
board_pos x,
board_pos y,
element_value value
);
/** /**
* Place a speculative value. This allocates a duplicate board with the element * 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 * NOTE: If element cannot be placed, this returns NULL
*/ */
struct board * struct board *board_place_speculative(const struct board *board,
board_place_speculative ( struct board *board_duplicate,
const struct board *board, board_pos x, board_pos y,
struct board *board_duplicate, element_value value);
board_pos x,
board_pos y,
element_value value
);
/** /**
* Recomputes board complexity by searching all elements on board for the * Recomputes board complexity by searching all elements on board for the
* lowest complexity * lowest complexity
*/ */
bool bool board_refresh_complexity(struct board *board);
board_refresh_complexity (struct board *board);
/** /**
* Copy a board layout to another board * Copy a board layout to another board
*/ */
void void board_copy(const struct board *board_from, struct board *board_to);
board_copy (const struct board *board_from, struct board *board_to);

433
main.c
View File

@ -1,3 +1,4 @@
#include "board.h"
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdio.h> #include <stdio.h>
@ -6,16 +7,13 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <time.h> #include <time.h>
#include <unistd.h> #include <unistd.h>
#include "board.h"
/** /**
* ANSI control codes * ANSI control codes
*/ */
#define COLOUR_RED "\e[31m" #define COLOUR_RED "\e[31m"
#define COLOUR_RESET "\e[0m" #define COLOUR_RESET "\e[0m"
#define CLEAR "\033[2J" #define CLEAR "\033[2J"
/** /**
* How many boards to allocate by default for board spec * How many boards to allocate by default for board spec
@ -29,26 +27,20 @@
*/ */
#define DEPTH_INCREMENT 3 #define DEPTH_INCREMENT 3
struct args { struct args {
bool valid; bool valid;
unsigned verbosity : 2; unsigned verbosity : 2;
char *file_name; char *file_name;
}; };
struct boards_table { struct boards_table {
struct board **board_specs; struct board **board_specs;
unsigned long long max_depth; unsigned long long max_depth;
}; };
void tables_ensure_depth(struct boards_table *board_spec,
void unsigned long long depth) {
tables_ensure_depth (struct boards_table *board_spec, unsigned long long depth) if (board_spec->max_depth <= depth) {
{
if (board_spec->max_depth <= depth)
{
/* Compute new max depth */ /* Compute new max depth */
unsigned long long new_max; unsigned long long new_max;
if (board_spec->max_depth == 0) 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; new_max = board_spec->max_depth + DEPTH_INCREMENT;
/* Disregard NULL return value. What's it gonna do, segfault? :P */ /* Disregard NULL return value. What's it gonna do, segfault? :P */
board_spec->board_specs = realloc ( board_spec->board_specs =
board_spec->board_specs, realloc(board_spec->board_specs, sizeof(struct board *) * new_max);
sizeof (struct board *) * new_max
);
/* Allocate boards */ /* Allocate boards */
for (unsigned long long l = board_spec->max_depth; l < new_max; ++l) for (unsigned long long l = board_spec->max_depth; l < new_max; ++l) {
{ board_spec->board_specs[l] = malloc(sizeof(struct board));
board_spec->board_specs[l] = malloc (sizeof (struct board)); board_make_links(board_spec->board_specs[l]);
board_make_links (board_spec->board_specs[l]);
} }
/* Update max depth */ /* Update max depth */
@ -74,56 +63,39 @@ tables_ensure_depth (struct boards_table *board_spec, unsigned long long depth)
} }
} }
bool bool simplify(struct boards_table *board_spec, unsigned long long depth,
simplify ( unsigned long long *counter, unsigned verbosity);
struct boards_table *board_spec,
unsigned long long depth,
unsigned long long *counter,
unsigned verbosity
);
struct board_file {
struct board_file
{
int fd; int fd;
void *data; void *data;
}; };
/** /**
* Determines if the given char is a valid character for defining * Determines if the given char is a valid character for defining
* a board element * a board element
*/ */
static inline bool static inline bool is_valid_def(char def) {
is_valid_def (char def) return def == ' ' || (def >= '0' && def <= '9');
{
return def == ' ' ||
(
def >= '0' &&
def <= '9'
);
} }
/** /**
* Load a board-definition file and return file descriptor * Load a board-definition file and return file descriptor
*/ */
static struct board_file static struct board_file load_board_file(const char *path) {
load_board_file (const char *path)
{
struct board_file file; struct board_file file;
file.fd = -1; file.fd = -1;
file.data = NULL; file.data = NULL;
/* Open file */ /* Open file */
int fd = open (path, 0); int fd = open(path, 0);
if (fd < 0) if (fd < 0)
return file; return file;
/* Map 89 bytes of file to memory */ /* Map 89 bytes of file to memory */
void *region = mmap (NULL, 89, PROT_READ, MAP_SHARED, fd, 0); void *region = mmap(NULL, 89, PROT_READ, MAP_SHARED, fd, 0);
if (region == (void*)-1) if (region == (void *)-1) {
{ close(fd);
close (fd);
return file; return file;
} }
@ -134,10 +106,9 @@ load_board_file (const char *path)
*/ */
char *data = region; char *data = region;
for (unsigned i = 1; i <= 89; ++i) for (unsigned i = 1; i <= 89; ++i)
if (!((i % 10) == 0) && !is_valid_def (data[i - 1])) if (!((i % 10) == 0) && !is_valid_def(data[i - 1])) {
{ munmap(region, 89);
munmap (region, 89); close(fd);
close (fd);
return file; return file;
} }
@ -151,265 +122,200 @@ load_board_file (const char *path)
/** /**
* Free all resources linked to an opened board definition file * Free all resources linked to an opened board definition file
*/ */
static void static void close_board_file(struct board_file file) {
close_board_file (struct board_file file) close(file.fd);
{ munmap(file.data, 89);
close (file.fd);
munmap (file.data, 89);
} }
static void static void copy_to_board(struct board_file file, struct board *board) {
copy_to_board (struct board_file file, struct board *board)
{
// Clear board // Clear board
board_init (board); board_init(board);
char *data = file.data; char *data = file.data;
for (unsigned i = 1; i <= 89; ++i) for (unsigned i = 1; i <= 89; ++i)
if ((i % 10) != 0) if ((i % 10) != 0) {
{
board_pos x = i % 10; board_pos x = i % 10;
board_pos y = i / 10; board_pos y = i / 10;
if (data[i - 1] != ' ') 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) {
static void printf("\033[%u;%uH", x + 1, y + 1);
ansi_set_cursor (unsigned y, unsigned x)
{
printf ("\033[%u;%uH", x + 1, y + 1);
} }
static void ansi_clear_screen() { puts(CLEAR); }
static void void ansi_cursor_show(bool show) {
ansi_clear_screen ()
{
puts (CLEAR);
}
void
ansi_cursor_show (bool show)
{
if (show) if (show)
fputs("\e[?25h", stdout); fputs("\e[?25h", stdout);
else else
fputs("\e[?25l", stdout); fputs("\e[?25l", stdout);
} }
static void static void print_board_verbose(const struct board *board, unsigned whence_x,
print_board_verbose ( unsigned whence_y) {
const struct board *board, for (board_pos y = 0; y < 9; ++y) {
unsigned whence_x, for (board_pos x = 0; x < 9; ++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 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); element_value check = vx + (vy * 3);
ansi_set_cursor (whence_x + (x * 4) + vx, whence_y + (y * 4) + vy); ansi_set_cursor(whence_x + (x * 4) + vx, whence_y + (y * 4) + vy);
if (board_has_value (board, x, y)) if (board_has_value(board, x, y))
printf ("%u", board_get_value (board, x, y) + 1); printf("%u", board_get_value(board, x, y) + 1);
else if (board_is_marked (board, x, y, check)) else if (board_is_marked(board, x, y, check))
printf (COLOUR_RED "%u" COLOUR_RESET, check + 1); printf(COLOUR_RED "%u" COLOUR_RESET, check + 1);
else else
fputs (" ", stdout); fputs(" ", stdout);
if (vx == 2 && x != 8) if (vx == 2 && x != 8)
fputs ("|", stdout); fputs("|", stdout);
} }
} }
ansi_set_cursor (0, (y * 4) + 3); ansi_set_cursor(0, (y * 4) + 3);
if (y != 8) if (y != 8) {
{
for (unsigned i = 0; i < (4 * 9) - 1; ++i) for (unsigned i = 0; i < (4 * 9) - 1; ++i)
if ((i + 1) % 4 == 0) if ((i + 1) % 4 == 0)
fputs ("+", stdout); fputs("+", stdout);
else else
fputs ("-", stdout); fputs("-", stdout);
} }
} }
fflush (stdout); fflush(stdout);
} }
static void print_board(const struct board *board, const struct board *compare,
static void unsigned whence_x, unsigned whence_y) {
print_board (const struct board *board, const struct board *compare, unsigned whence_x, unsigned whence_y) for (board_pos y = 0; y < 9; ++y) {
{
for (board_pos y = 0; y < 9; ++y)
{
/* Print row */ /* Print row */
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x) {
{ ansi_set_cursor(whence_x + (x * 2), whence_y + (y * 2));
ansi_set_cursor (whence_x + (x * 2), whence_y + (y * 2));
/* Print board element */ /* Print board element */
if (board_has_value (board, x, y)) if (board_has_value(board, x, y)) {
{ if (compare != NULL && !board_has_value(compare, x, y))
if (compare != NULL && ! board_has_value (compare, x, y)) printf(COLOUR_RED "%u" COLOUR_RESET,
printf (COLOUR_RED "%u" COLOUR_RESET, board_get_value (board, x, y) + 1); board_get_value(board, x, y) + 1);
else else
printf ("%u", board_get_value (board, x, y) + 1); printf("%u", board_get_value(board, x, y) + 1);
} } else
else fputs(" ", stdout);
fputs (" ", stdout);
/* Print column element delimiter */ /* Print column element delimiter */
if (x < 8) if (x < 8)
fputs("|", stdout); fputs("|", stdout);
} }
/* Print row element delimiter */ /* Print row element delimiter */
if (y < 8) if (y < 8) {
{ for (board_pos x = 0; x < 17; ++x) {
for (board_pos x = 0; x < 17; ++x) ansi_set_cursor(whence_x + x, whence_y + (y * 2 + 1));
{
ansi_set_cursor (whence_x + x, whence_y + (y * 2 + 1));
if ((x & 1) == 0) if ((x & 1) == 0)
fputs ("-", stdout); fputs("-", stdout);
else else
fputs ("+", stdout); fputs("+", stdout);
} }
} }
} }
} }
/** /**
* Compute first potential value of a given element * Compute first potential value of a given element
*/ */
element_value element_value first_potential_value(struct board_element *element,
first_potential_value (struct board_element *element, struct board *board, bool *error) struct board *board, bool *error) {
{
unsigned short potential = element->potential; unsigned short potential = element->potential;
if (potential == 0) if (potential == 0) {
{
*error = true; *error = true;
return 0; return 0;
} }
*error = false; *error = false;
element_value value = 0; element_value value = 0;
while (potential != 0) while (potential != 0) {
{
if ((potential & 1) == 1) if ((potential & 1) == 1)
return value; return value;
++value; ++value;
potential >>= 1; potential >>= 1;
} }
/* Unreachable */ /* Unreachable */
abort(); abort();
} }
/** /**
* Reduce away all elements on board with complexity=1 until none remain * Reduce away all elements on board with complexity=1 until none remain
*/ */
#ifdef NOVERB #ifdef NOVERB
bool bool simplify(struct boards_table *board_specs, unsigned long long depth)
simplify (
struct boards_table *board_specs,
unsigned long long depth
)
#else #else
bool bool simplify(struct boards_table *board_specs, unsigned long long depth,
simplify ( unsigned long long *counter, unsigned verbosity)
struct boards_table *board_specs,
unsigned long long depth,
unsigned long long *counter,
unsigned verbosity
)
#endif #endif
{ {
/* Get current table */ /* Get current table */
struct board *board = board_specs->board_specs[depth]; struct board *board = board_specs->board_specs[depth];
#ifndef NOVERB #ifndef NOVERB
if (verbosity > 0) if (verbosity > 0) {
{ if (((*counter) & (0xFFFF >> (4 * (4 - verbosity)))) == 0) {
if (((*counter) & (0xFFFF >> (4 * (4 - verbosity)))) == 0) print_board_verbose(board, 0, 0);
{ ansi_set_cursor(0, 35);
print_board_verbose (board, 0, 0); printf("Iteration: %llu", *counter);
ansi_set_cursor (0, 35);
printf ("Iteration: %llu", *counter);
} }
*counter += 1; *counter += 1;
} }
#endif #endif
bool error; bool error;
unsigned count = 0; unsigned count = 0;
/* Reduce using low-complexity computation */ /* Reduce using low-complexity computation */
while (board->complexity == 1) while (board->complexity == 1) {
{
for (board_pos y = 0; y < 9; ++y) for (board_pos y = 0; y < 9; ++y)
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x)
if (! board_has_value (board, x, y)) if (!board_has_value(board, x, y)) {
{ struct board_element *elem = BOARD_ELEM(board, x, y);
struct board_element *elem = BOARD_ELEM (board, x, y); if (elem->complexity == 1) {
if (elem->complexity == 1) element_value value = first_potential_value(elem, board, &error);
{ if (error)
element_value value = first_potential_value (elem, board, &error); return false;
if (error) return false;
++count; ++count;
if (! board_place (board, x, y, value)) if (!board_place(board, x, y, value))
return false; return false;
} }
} }
board_refresh_complexity (board); board_refresh_complexity(board);
} }
/* Attempt to reduce with speculative placement */ /* 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 y = 0; y < 9; ++y)
for (board_pos x = 0; x < 9; ++x) for (board_pos x = 0; x < 9; ++x) {
{ struct board_element *elem = BOARD_ELEM(board, x, y);
struct board_element *elem = BOARD_ELEM (board, x, y);
/* Find a simplest element on the board */ /* Find a simplest element on the board */
if ( if (!elem->has_value && elem->complexity == board->complexity)
! elem->has_value && for (element_value value = 0; value < 9; ++value) {
elem->complexity == board->complexity
)
for (element_value value = 0; value < 9; ++value)
{
/* Try speculative placement of each potential value and recurse */ /* Try speculative placement of each potential value and recurse */
tables_ensure_depth (board_specs, depth + 1); tables_ensure_depth(board_specs, depth + 1);
if (elem_is_marked (elem, value)) if (elem_is_marked(elem, value)) {
{ struct board *board_spec = board_place_speculative(
struct board *board_spec = board, board_specs->board_specs[depth + 1], x, y, value);
board_place_speculative (
board,
board_specs->board_specs[depth + 1],
x,
y,
value
);
/* If speculative placement failed, try another value */ /* If speculative placement failed, try another value */
if (board_spec == NULL) if (board_spec == NULL) {
{ if (!elem_unmark(elem, value))
if (! elem_unmark (elem, value))
return false; return false;
continue; continue;
} }
@ -418,26 +324,16 @@ simplify (
if ( if (
#ifdef NOVERB #ifdef NOVERB
simplify ( simplify(board_specs, depth + 1) &&
board_specs,
depth + 1
) &&
#else #else
simplify ( simplify(board_specs, depth + 1, counter, verbosity) &&
board_specs,
depth + 1,
counter,
verbosity
) &&
#endif #endif
board_spec->complexity == 0) board_spec->complexity == 0) {
{ board_copy(board_spec, board);
board_copy (board_spec, board);
x = 9; x = 9;
y = 9; y = 9;
value = 9; value = 9;
} } else if (!elem_unmark(elem, value))
else if (! elem_unmark (elem, value))
return false; return false;
} }
} }
@ -446,65 +342,52 @@ simplify (
return true; return true;
} }
struct args argparse(int argc, char **argv) {
struct args
argparse (int argc, char **argv)
{
struct args result; struct args result;
result.file_name = NULL; result.file_name = NULL;
result.valid = true; result.valid = true;
result.verbosity = 0; result.verbosity = 0;
if (argc < 2) if (argc < 2) {
{
result.valid = false; result.valid = false;
return result; return result;
} }
for (int i = 1; i < argc; ++i) for (int i = 1; i < argc; ++i)
if (strncmp (argv[i], "-", 1) == 0) if (strncmp(argv[i], "-", 1) == 0) {
{ if (result.verbosity != 0) {
if (result.verbosity != 0)
{
result.valid = false; result.valid = false;
return result; return result;
} }
if (strcmp (argv[i], "-v") == 0) if (strcmp(argv[i], "-v") == 0)
result.verbosity = 1; result.verbosity = 1;
else if (strcmp (argv[i], "-vv") == 0) else if (strcmp(argv[i], "-vv") == 0)
result.verbosity = 2; result.verbosity = 2;
else else {
{
result.valid = false; result.valid = false;
return result; return result;
} }
} } else if (result.file_name == NULL)
else if (result.file_name == NULL)
result.file_name = argv[i]; result.file_name = argv[i];
else else {
{
result.valid = false; result.valid = false;
return result; return result;
} }
return result; return result;
} }
int main(int argc, char **argv, char **env) {
struct args args = argparse(argc, argv);
int if (!args.valid) {
main (int argc, char **argv, char **env) fputs("Badly formatted arguments! Usage:\n\t./sudoku [-v[v]] {file name}\n",
{ stderr);
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; 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) if (file.fd == -1 || file.data == NULL)
return -1; return -1;
ansi_cursor_show (false); ansi_cursor_show(false);
/* Allocate boards */ /* Allocate boards */
struct board original; struct board original;
@ -512,62 +395,54 @@ main (int argc, char **argv, char **env)
struct boards_table boards; struct boards_table boards;
boards.max_depth = 0; boards.max_depth = 0;
boards.board_specs = NULL; boards.board_specs = NULL;
tables_ensure_depth (&boards, 0); tables_ensure_depth(&boards, 0);
struct board *root_board = boards.board_specs[0]; struct board *root_board = boards.board_specs[0];
copy_to_board (file, &original); copy_to_board(file, &original);
board_copy (&original, boards.board_specs[0]); 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 (); ansi_cursor_show(true);
if (! board_is_valid (root_board))
{
fputs ("Supplied board is not valid!\n", stderr);
ansi_cursor_show (true);
return 1; return 1;
} }
if (args.verbosity == 0) if (args.verbosity == 0)
puts ("Simplifying..."); puts("Simplifying...");
board_refresh_complexity(root_board);
board_refresh_complexity (root_board);
/* Profiler start time */ /* Profiler start time */
clock_t start_clk = clock (); clock_t start_clk = clock();
unsigned long long counter = 0; unsigned long long counter = 0;
simplify (&boards, 0, &counter, args.verbosity); simplify(&boards, 0, &counter, args.verbosity);
/* Profiler end time */ /* Profiler end time */
clock_t end_clk = clock (); clock_t end_clk = clock();
ansi_clear_screen (); ansi_clear_screen();
if (root_board->complexity == 0) if (root_board->complexity == 0) {
{ print_board(&original, NULL, 0, 0);
print_board (&original, NULL, 0, 0); print_board(root_board, &original, 21, 0);
print_board (root_board, &original, 21, 0); ansi_set_cursor(0, 18);
ansi_set_cursor (0, 18); } else {
print_board_verbose(root_board, 0, 0);
ansi_set_cursor(0, 36);
} }
else printf("Simplification took %Lf seconds\n",
{ ((long double)(end_clk - start_clk)) / CLOCKS_PER_SEC);
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);
ansi_cursor_show(true);
ansi_cursor_show (true);
return 0; return 0;
} }