Whoops, this file didn't get comments

This commit is contained in:
Pyrex 2024-05-25 16:13:29 -07:00
parent 7e84d09250
commit 049fa3405a

View File

@ -32,7 +32,7 @@ void puzzle_undo_propagate_constraints(
); );
// Return true if cell is bound to something other than '.'. // Return true if cell is bound to something other than '.'.
bool puzzle_is_complete(puzzle_t* puzzle, uint8_t cell); bool puzzle_cell_is_complete(puzzle_t* puzzle, uint8_t cell);
// Bind cell to some value, including '.' // Bind cell to some value, including '.'
void puzzle_set_cell(puzzle_t* puzzle, uint8_t cell, tile_t tile); void puzzle_set_cell(puzzle_t* puzzle, uint8_t cell, tile_t tile);
@ -75,11 +75,12 @@ void puzzle_solve(puzzle_t* puzzle) {
bool puzzle_solve1(puzzle_t* puzzle) { bool puzzle_solve1(puzzle_t* puzzle) {
// find best cell to start from // find best cell to start from
// (which is the cell with the fewest options)
uint8_t best_cell_noptions = 255; uint8_t best_cell_noptions = 255;
uint8_t best_cell = 255; uint8_t best_cell = 255;
for (uint8_t cell = 0; cell < N_CELLS; cell++) { for (uint8_t cell = 0; cell < N_CELLS; cell++) {
if (puzzle_is_complete(puzzle, cell)) { if (puzzle_cell_is_complete(puzzle, cell)) {
continue; continue;
} }
puzzle_options_t *options = &puzzle->options[cell]; puzzle_options_t *options = &puzzle->options[cell];
@ -91,10 +92,13 @@ bool puzzle_solve1(puzzle_t* puzzle) {
} }
if (best_cell == 255) { if (best_cell == 255) {
return true; // solved! // no valid starting cell: continue!
return true;
} }
{ {
// try every option that's still available (those from 1-9) that appear
// in the options set that we have
uint8_t cell = best_cell; uint8_t cell = best_cell;
puzzle_options_t *options = &puzzle->options[cell]; puzzle_options_t *options = &puzzle->options[cell];
for (char digit = '1'; digit <= (char) '9'; digit++) { for (char digit = '1'; digit <= (char) '9'; digit++) {
@ -107,6 +111,9 @@ bool puzzle_solve1(puzzle_t* puzzle) {
puzzle_propagate_constraints(puzzle, cell, tile, &result); puzzle_propagate_constraints(puzzle, cell, tile, &result);
if (result.viable) { if (result.viable) {
// puzzle_propagate_constraints may have created a situation
// where there is no need to even try the next branch, as it is
// known to be unsolvable
puzzle_set_cell(puzzle, cell, tile); puzzle_set_cell(puzzle, cell, tile);
if (puzzle_solve1(puzzle)) { if (puzzle_solve1(puzzle)) {
return true; return true;
@ -116,6 +123,7 @@ bool puzzle_solve1(puzzle_t* puzzle) {
puzzle_undo_propagate_constraints(puzzle, tile, &result); puzzle_undo_propagate_constraints(puzzle, tile, &result);
} }
// we didn't explicitly clear this earlier, so clear this here
puzzle_set_cell(puzzle, cell, tile_new('.')); puzzle_set_cell(puzzle, cell, tile_new('.'));
} }
@ -127,13 +135,18 @@ void puzzle_check_solution(puzzle_t* puzzle) {
tile_t original = puzzle->input_board[cell]; tile_t original = puzzle->input_board[cell];
tile_t solved = puzzle->solved_board[cell]; tile_t solved = puzzle->solved_board[cell];
// every cell must be populated
if (solved.value == '.') { if (solved.value == '.') {
crash("invalid solution (empty cell)"); crash("invalid solution (empty cell)");
} }
// new cells must have the same value as the old cell in their position
if (original.value != '.' && original.value != solved.value) { if (original.value != '.' && original.value != solved.value) {
crash("invalid solution (changed original cell)"); crash("invalid solution (changed original cell)");
} }
// there must be no cases where the interference graph sees
// two neighbors with the same tile value
cellset_t *interference_row = &interference.rows[cell]; cellset_t *interference_row = &interference.rows[cell];
for (uint8_t other_i = 0; other_i < interference_row->count; other_i++) { for (uint8_t other_i = 0; other_i < interference_row->count; other_i++) {
uint8_t other = interference_row->cells[other_i]; uint8_t other = interference_row->cells[other_i];
@ -153,10 +166,13 @@ void puzzle_propagate_constraints(
cellset_init(&result->cells); cellset_init(&result->cells);
result->viable = true; result->viable = true;
// find every row that cell interferes with
// for every incomplete cell in that row, remove this tile value
// from the options
cellset_t *interference_row = &interference.rows[cell]; cellset_t *interference_row = &interference.rows[cell];
for (uint8_t other_i = 0; other_i < interference_row->count; other_i++) { for (uint8_t other_i = 0; other_i < interference_row->count; other_i++) {
uint8_t other = interference_row->cells[other_i]; uint8_t other = interference_row->cells[other_i];
if (puzzle_is_complete(puzzle, other)) { if (puzzle_cell_is_complete(puzzle, other)) {
continue; continue;
} }
@ -164,6 +180,7 @@ void puzzle_propagate_constraints(
if (puzzle_options_remove(options, tile)) { if (puzzle_options_remove(options, tile)) {
cellset_add(&result->cells, other); cellset_add(&result->cells, other);
// if there is no possible value for a cell, then we picked wrong
if (puzzle_options_is_empty(options)) { if (puzzle_options_is_empty(options)) {
result->viable = false; result->viable = false;
break; break;
@ -177,6 +194,7 @@ void puzzle_undo_propagate_constraints(
tile_t tile, tile_t tile,
puzzle_propagate_result_t* result puzzle_propagate_result_t* result
) { ) {
// we recorded every cell that was touched, so untouch those cells
cellset_t *cells = &result->cells; cellset_t *cells = &result->cells;
for (uint8_t cell_i = 0; cell_i < cells->count; cell_i++) { for (uint8_t cell_i = 0; cell_i < cells->count; cell_i++) {
uint8_t cell = cells->cells[cell_i]; uint8_t cell = cells->cells[cell_i];
@ -184,7 +202,7 @@ void puzzle_undo_propagate_constraints(
} }
} }
bool puzzle_is_complete(puzzle_t* puzzle, uint8_t cell) { bool puzzle_cell_is_complete(puzzle_t* puzzle, uint8_t cell) {
return puzzle->solved_board[cell].value != '.'; return puzzle->solved_board[cell].value != '.';
} }