h
This commit is contained in:
parent
7b55d6e67a
commit
ed962f5b09
605
board.c
605
board.c
@ -4,21 +4,19 @@
|
||||
* Created by Gabriel Tofvesson
|
||||
*/
|
||||
|
||||
#include "board.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#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));
|
||||
}
|
||||
|
204
board.h
204
board.h
@ -6,18 +6,18 @@
|
||||
|
||||
#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
|
||||
*/
|
||||
#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);
|
||||
|
433
main.c
433
main.c
@ -1,3 +1,4 @@
|
||||
#include "board.h"
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
@ -6,16 +7,13 @@
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user