Compare commits

...

3 Commits
wasm ... master

4 changed files with 159 additions and 68 deletions

View File

@ -45,7 +45,8 @@ the aforementioned specifications.
## Optimization ## Optimization
An optimization directive has been included in `board.c` to allow for the near An optimization directive has been included in `board.c` to allow for the near
complete removal of boundary checks and error conditions. To enable this complete removal of boundary checks and error conditions. To enable this
optimization, simply add `-DOPTIMIZE` to your compiler flags. optimization, simply add `-DOPTIMIZE` to your compiler flags. For insane speeds,
don't forget the `-O3` gcc flag.
## Live status output ## Live status output
If you would like to get a live status output of speculative value placement, If you would like to get a live status output of speculative value placement,
@ -56,14 +57,6 @@ are really only useful on much slower devices.
## TODO ## TODO
* Optimizations
* Packed structures
* Better structure layouts
* Optimize speculative value placement error-condition checks
* Cleaner code * Cleaner code
* Move printing to separate file * Move printing to separate file

127
board.c
View File

@ -72,6 +72,37 @@ meta_init (struct metadata *meta)
} }
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);
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);
/* Link column adjacents */
for (board_pos ly = 0; ly < 9; ++ly)
if (ly != y)
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);
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);
}
}
void void
board_init (struct board *board) board_init (struct board *board)
{ {
@ -80,8 +111,17 @@ board_init (struct board *board)
defval.potential = 0x1FF; defval.potential = 0x1FF;
defval.complexity = 9; defval.complexity = 9;
for (size_t t = 0; t < (sizeof (board->elements) / sizeof (struct board_element)); ++t) for (board_pos y = 0; y < 9; ++y)
memcpy (&board->elements[t], &defval, sizeof (struct board_element)); 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));
}
board_make_links (board);
board->complexity = 9; board->complexity = 9;
@ -224,6 +264,7 @@ board_set (
); );
struct board_element *elem = BOARD_ELEM (board, x, y); struct board_element *elem = BOARD_ELEM (board, x, y);
elem->has_value = true; elem->has_value = true;
elem->value = value; elem->value = value;
} }
@ -257,7 +298,7 @@ board_mark (
} }
void bool
board_unmark ( board_unmark (
struct board *board, struct board *board,
board_pos x, board_pos x,
@ -272,19 +313,29 @@ board_unmark (
"Attempt to mark element with value" "Attempt to mark element with value"
); );
struct board_element *elem = BOARD_ELEM (board, x, y); return elem_unmark (BOARD_ELEM (board, x, y), value);
if (board_is_marked (board, x, y, value))
{
/* Shift bit to correct place and then invert first 9 bits */
elem->potential ^= (1 << value);
--(elem->complexity);
}
} }
else ERROR("Invalid parameters to function board_unmark()"); else ERROR("Invalid parameters to function board_unmark()");
} }
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);
}
return elem->potential != 0;
}
bool bool
board_has_value ( board_has_value (
const struct board *board, const struct board *board,
@ -325,12 +376,22 @@ board_is_marked (
{ {
if (is_in_bounds (x, y) && is_valid_value (value)) if (is_in_bounds (x, y) && is_valid_value (value))
{ {
return BOARD_ELEM (board, x, y)->potential & (1 << value); return elem_is_marked(BOARD_ELEM (board, x, y), value);
} }
else ERROR("Invalid parameters to function board_is_marked()"); else ERROR("Invalid parameters to function board_is_marked()");
} }
bool
elem_is_marked (
const struct board_element *elem,
element_value value
)
{
return elem->potential & (1 << value);
}
bool bool
board_is_valid (struct board *board) board_is_valid (struct board *board)
{ {
@ -524,32 +585,17 @@ board_place (
{ {
if (board_meta_can_set (board, x, y, value)) if (board_meta_can_set (board, x, y, value))
{ {
/* Unmark x-axis */ unsigned pos = ELEM_POS (x, y);
for (board_pos unmark_x = 0; unmark_x < 9; ++unmark_x)
if (unmark_x != x && ! board_has_value (board, unmark_x, y))
board_unmark (board, unmark_x, y, value);
/* Unmark y-axis */ /* Unmark all adjacent elements */
for (board_pos unmark_y = 0; unmark_y < 9; ++unmark_y) for (unsigned i = 0; i < 20; ++i)
if (unmark_y != y && ! board_has_value (board, x, unmark_y)) if (
board_unmark (board, x, unmark_y, value); ! board->links[pos][i]->has_value &&
! elem_unmark (board->links[pos][i], value)
/* Update quad */ )
board_pos quad_x = TO_QUAD (x);
board_pos quad_y = TO_QUAD (y);
for (board_pos unmark_y = 0; unmark_y < 3; ++unmark_y)
for (board_pos unmark_x = 0; unmark_x < 3; ++unmark_x)
{ {
board_pos target_x = quad_x + unmark_x; /* Unmarking potential caused element to have no potential */
board_pos target_y = quad_y + unmark_y; return false;
/* Unmark value for all unset elements in quad */
if (
(target_x != x || target_y != y) &&
!board_has_value (board, target_x, target_y)
)
board_unmark (board, target_x, target_y, value);
} }
/* Set value */ /* Set value */
@ -585,7 +631,7 @@ board_place_speculative (
/* 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) || ! board_is_valid (board_duplicate)) if (! board_place (board_duplicate, x, y, value))
return NULL; return NULL;
board_refresh_complexity (board_duplicate); board_refresh_complexity (board_duplicate);
@ -632,5 +678,10 @@ board_refresh_complexity (struct board *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)
{ {
memcpy (board_to, board_from, sizeof(struct board)); /* Copy everything except the links */
memcpy (
board_to,
board_from,
sizeof(struct board) - sizeof (((struct board *)0)->links)
);
} }

49
board.h
View File

@ -6,10 +6,13 @@
#include <stdbool.h> #include <stdbool.h>
#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[((y) * 9) + (x)]) #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
@ -32,6 +35,8 @@
*/ */
#define TO_QUAD(pos) (((pos) / 3) * 3) #define TO_QUAD(pos) (((pos) / 3) * 3)
struct board_element;
typedef unsigned short int board_pos; typedef unsigned short int board_pos;
typedef unsigned char element_value; typedef unsigned char element_value;
@ -45,13 +50,9 @@ typedef unsigned char element_value;
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 */
union { element_value value : 4; /* Value of element */
element_value value : 4; /* Value of element */ unsigned short potential : 9; /* Bitfield of possible values*/
struct { unsigned char complexity : 4; /* Complexity tracker */
unsigned short potential : 9; /* Bitfield of possible values */
unsigned char complexity : 4; /* Complexity tracker */
};
};
}; };
/** /**
@ -80,6 +81,9 @@ struct board {
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 *links [81][20];/* All "connected", "adjacent" elements */
}; };
@ -90,6 +94,13 @@ void
meta_init (struct metadata *meta); meta_init (struct metadata *meta);
/*
* Just generate board element adjacency links
*/
void
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
*/ */
@ -184,7 +195,7 @@ board_mark (
* *
* NOTE: Unmarking an element with a decied value is undefined * NOTE: Unmarking an element with a decied value is undefined
*/ */
void bool
board_unmark ( board_unmark (
struct board *board, struct board *board,
board_pos x, board_pos x,
@ -193,6 +204,16 @@ board_unmark (
); );
/**
* Removes a marking of a potential value of an element
*/
bool
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
*/ */
@ -231,6 +252,16 @@ board_is_marked (
); );
/**
* 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
);
/** /**
* 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

40
main.c
View File

@ -64,7 +64,10 @@ tables_ensure_depth (struct boards_table *board_spec, unsigned long long depth)
/* 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]);
}
/* Update max depth */ /* Update max depth */
board_spec->max_depth = new_max; board_spec->max_depth = new_max;
@ -316,6 +319,13 @@ first_potential_value (struct board_element *element, struct board *board, bool
/** /**
* 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
bool
simplify (
struct boards_table *board_specs,
unsigned long long depth
)
#else
bool bool
simplify ( simplify (
struct boards_table *board_specs, struct boards_table *board_specs,
@ -323,10 +333,12 @@ simplify (
unsigned long long *counter, unsigned long long *counter,
unsigned verbosity unsigned verbosity
) )
#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
if (verbosity > 0) if (verbosity > 0)
{ {
if (((*counter) & (0xFFFF >> (4 * (4 - verbosity)))) == 0) if (((*counter) & (0xFFFF >> (4 * (4 - verbosity)))) == 0)
@ -337,6 +349,7 @@ simplify (
} }
*counter += 1; *counter += 1;
} }
#endif
bool error; bool error;
@ -358,15 +371,8 @@ simplify (
++count; ++count;
//fprintf (stderr, "Placing (%u, %u)=%u (potential=%u)\n", x, y, value, elem->potential);
if (! board_place (board, x, y, value)) if (! board_place (board, x, y, value))
{ return false;
bool rerr = meta_has_value (BOARD_ROW (board, y), value);
bool cerr = meta_has_value (BOARD_COL (board, x), value);
bool qerr = meta_has_value (BOARD_QUAD (board, TO_QUAD (x), TO_QUAD (y)), value);
fprintf (stderr, "Error (%u, %u, %u)\n", rerr, cerr, qerr);
}
} }
} }
@ -382,14 +388,14 @@ simplify (
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 (
! board_has_value (board, x, y) && ! elem->has_value &&
elem->complexity == board->complexity elem->complexity == board->complexity
) )
for (element_value value = 0; value < 9; ++value) 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->potential & (1 << value)) != 0) if (elem_is_marked (elem, value))
{ {
struct board *board_spec = struct board *board_spec =
board_place_speculative ( board_place_speculative (
@ -403,18 +409,27 @@ simplify (
/* If speculative placement failed, try another value */ /* If speculative placement failed, try another value */
if (board_spec == NULL) if (board_spec == NULL)
{ {
board_unmark (board, x, y, value); if (! elem_unmark (elem, value))
return false;
continue; continue;
} }
/* Found solution */ /* Found solution */
if ( if (
#ifdef NOVERB
simplify (
board_specs,
depth + 1
) &&
#else
simplify ( simplify (
board_specs, board_specs,
depth + 1, depth + 1,
counter, counter,
verbosity verbosity
) && ) &&
#endif
board_spec->complexity == 0) board_spec->complexity == 0)
{ {
board_copy (board_spec, board); board_copy (board_spec, board);
@ -422,7 +437,8 @@ simplify (
y = 9; y = 9;
value = 9; value = 9;
} }
else board_unmark (board, x, y, value); else if (! elem_unmark (elem, value))
return false;
} }
} }
} }