├── 9781484209967.jpg ├── LICENSE.txt ├── README.md ├── contributing.md └── sources ├── Generator ├── brute.c ├── brute.h ├── brute_comp.c ├── brute_comp.h ├── count_solved.c ├── count_solved.h ├── def.h ├── display.c ├── display.h ├── display_string.c ├── display_string.h ├── fill.c ├── fill.h ├── fill_digit.c ├── fill_digit.h ├── in_box.c ├── in_box.h ├── inconsistent_grid.c ├── inconsistent_grid.h ├── inconsistent_unit.c ├── inconsistent_unit.h ├── init.c ├── init.h ├── list_solved.c ├── list_solved.h ├── multi_html.c ├── multi_html.h ├── save_html.c ├── save_html.h └── sudoku_gen.c └── Solver ├── backtrack.c ├── backtrack.h ├── box_line.c ├── box_line.h ├── box_line_unit.c ├── box_line_unit.h ├── cleanup.c ├── cleanup.h ├── cleanup_around.c ├── cleanup_around.h ├── cleanup_unit.c ├── cleanup_unit.h ├── count_candidates.c ├── count_candidates.h ├── count_solved.c ├── count_solved.h ├── def.h ├── display.c ├── display.h ├── display_strats_in_clear.c ├── display_strats_in_clear.h ├── display_string.c ├── display_string.h ├── execute_strategies.c ├── execute_strategies.h ├── footprint.c ├── footprint.h ├── hidden_pair.c ├── hidden_pair.h ├── hidden_pair_unit.c ├── hidden_pair_unit.h ├── hidden_triple.c ├── hidden_triple.h ├── hidden_triple_unit.c ├── hidden_triple_unit.h ├── inconsistent_grid.c ├── inconsistent_grid.h ├── inconsistent_unit.c ├── inconsistent_unit.h ├── init.c ├── init.h ├── intersection.c ├── intersection.h ├── keep_going.c ├── keep_going.h ├── lines.c ├── lines.h ├── lines_2.c ├── lines_2.h ├── lines_3.c ├── lines_3.h ├── lines_4.c ├── lines_4.h ├── naked_pair.c ├── naked_pair.h ├── naked_pair_unit.c ├── naked_pair_unit.h ├── naked_quad.c ├── naked_quad.h ├── naked_quad_unit.c ├── naked_quad_unit.h ├── naked_triple.c ├── naked_triple.h ├── naked_triple_unit.c ├── naked_triple_unit.h ├── pairs_data.c ├── pairs_data.h ├── pairs_find.c ├── pairs_find.h ├── pointing_line.c ├── pointing_line.h ├── pointing_line_box.c ├── pointing_line_box.h ├── rectangle.c ├── rectangle.h ├── rectangle_cell.c ├── rectangle_cell.h ├── rectangle_pattern.c ├── rectangle_pattern.h ├── rectangle_step.c ├── rectangle_step.h ├── remove_candidate.c ├── remove_candidate.h ├── solve.c ├── solve.h ├── sudoku_solver.c ├── unique.c ├── unique.h ├── unique_loop.c ├── unique_loop.h ├── unique_unit.c ├── unique_unit.h ├── xy_chain.c ├── xy_chain.h ├── xy_chain_digit.c ├── xy_chain_digit.h ├── xy_chain_step.c ├── xy_chain_step.h ├── y_wing.c ├── y_wing.h ├── y_wing_digit.c └── y_wing_digit.h /9781484209967.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/sudoku-programming-w-c/9609281ce56d73bd3ce9df0d0500bf8090c26fe6/9781484209967.jpg -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Apress/sudoku-programming-w-c/9609281ce56d73bd3ce9df0d0500bf8090c26fe6/LICENSE.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apress Source Code 2 | 3 | This repository accompanies [*Sudoku Programming with C*](http://www.apress.com/9781484209967) by Giulio Zambon (Apress, 2015). 4 | 5 | ![Cover image](9781484209967.jpg) 6 | 7 | Download the files as a zip using the green button, or clone the repository to your machine using Git. 8 | 9 | ## Releases 10 | 11 | Release v1.0 corresponds to the code in the published book, without corrections or updates. 12 | 13 | ## Contributions 14 | 15 | See the file Contributing.md for more information on how you can contribute to this repository. 16 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to Apress Source Code 2 | 3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers. 4 | 5 | ## How to Contribute 6 | 7 | 1. Make sure you have a GitHub account. 8 | 2. Fork the repository for the relevant book. 9 | 3. Create a new branch on which to make your change, e.g. 10 | `git checkout -b my_code_contribution` 11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted. 12 | 5. Submit a pull request. 13 | 14 | Thank you for your contribution! -------------------------------------------------------------------------------- /sources/Generator/brute.c: -------------------------------------------------------------------------------- 1 | /* brute.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include "brute.h" 10 | #include "def.h" 11 | #include "inconsistent_unit.h" 12 | 13 | int brute() { 14 | int result = BRUTE_SUCCESSFUL; 15 | unsigned long start_time = clock()/CLOCKS_PER_SEC; 16 | unsigned long this_time; 17 | char initial[9][9]; 18 | for (int k = 0; k < 9; k++) { 19 | for (int j = 0; j < 9; j++) { 20 | initial[k][j] = grid[k][j]; 21 | } 22 | } 23 | int k = 0; 24 | int j = 0; 25 | do { 26 | do { 27 | if (initial[k][j] == 0) { 28 | int i = grid[k][j] + 1; 29 | if (i > 9) { 30 | grid[k][j] = 0; 31 | do { 32 | do { j--; } while (j >= 0 && initial[k][j] != 0); 33 | if (j < 0) { 34 | k--; 35 | if (k < 0) { 36 | result = BRUTE_IMPOSSIBLE; 37 | goto done; //==> 38 | } 39 | j = 8; 40 | } 41 | } while (initial[k][j] != 0); 42 | } // if (i.. 43 | else { 44 | grid[k][j] = i; 45 | int kB = k/3*3+j/3; 46 | if ( !inconsistent_unit("row", k, row[k]) 47 | && !inconsistent_unit("column", j, col[j]) 48 | && !inconsistent_unit("box", kB, box[kB]) 49 | ) { 50 | j++; 51 | } 52 | } // if (i.. else 53 | } // if (initial[k][j].. 54 | else { 55 | j++; 56 | } 57 | this_time = clock()/CLOCKS_PER_SEC; 58 | if (this_time - start_time > BRUTE_MAX_TIME) { 59 | result = BRUTE_TIMEOUT; 60 | goto done; //==> 61 | } 62 | } while (j < 9); 63 | k++; 64 | j = 0; 65 | } while (k < 9); 66 | 67 | done: 68 | return result; 69 | } 70 | -------------------------------------------------------------------------------- /sources/Generator/brute.h: -------------------------------------------------------------------------------- 1 | /* brute.h 2 | * 3 | * Solves a Sudoku by brute force 4 | * 5 | * See below for the return codes 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef BRUTE 11 | #define BRUTE 12 | 13 | #define BRUTE_SUCCESSFUL 0 14 | #define BRUTE_IMPOSSIBLE -1 15 | #define BRUTE_TIMEOUT -2 16 | 17 | #define BRUTE_MAX_TIME 10 18 | 19 | int brute(void); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /sources/Generator/brute_comp.c: -------------------------------------------------------------------------------- 1 | /* brute_comp.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include "brute.h" 10 | #include "brute_comp.h" 11 | #include "def.h" 12 | #include "inconsistent_grid.h" 13 | 14 | // This messages in clear must match the codes defined in brute_comp.h 15 | const char *brute_comp_err[] = { 16 | /* 0 */ "same as reference", 17 | /* 1 */ "different from reference", 18 | /* 2 */ "timeout", 19 | /* 3 */ "grid inconsistent", 20 | /* 4 */ "puzzle impossible", 21 | /* 5 */ "unknown result" 22 | }; 23 | 24 | int brute_comp() { 25 | int result = BRUTE_COMP_PROBLEM; 26 | int brute_result = brute(); 27 | switch (brute_result) { 28 | 29 | case BRUTE_SUCCESSFUL: 30 | result = BRUTE_COMP_OK; 31 | for (int kk = 0; kk < 9 && result == BRUTE_COMP_OK; kk++) { 32 | for (int jj = 0; jj < 9 && result == BRUTE_COMP_OK; jj++) { 33 | if (solved[kk][jj] != grid[kk][jj]) result = BRUTE_COMP_DIFFERENT; 34 | } 35 | } 36 | if (inconsistent_grid()) result = BRUTE_COMP_INCONSISTENT; 37 | break; 38 | 39 | case BRUTE_IMPOSSIBLE: 40 | result = BRUTE_COMP_IMPOSSIBLE; 41 | break; 42 | 43 | case BRUTE_TIMEOUT: 44 | result = BRUTE_COMP_TIMEOUT; 45 | break; 46 | 47 | default: 48 | result = BRUTE_COMP_PROBLEM; 49 | break; 50 | } 51 | return result; 52 | } 53 | -------------------------------------------------------------------------------- /sources/Generator/brute_comp.h: -------------------------------------------------------------------------------- 1 | /* brute_comp.h 2 | * 3 | * Solves a Sudoku by executing brute() and then compares the result with 4 | * the reference 5 | * 6 | * See below for the return codes 7 | * 8 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 9 | * 10 | */ 11 | #ifndef BRUTE_COMPARE 12 | #define BRUTE_COMPARE 13 | 14 | // If you modify the following list, change brute_comp_err accordingly 15 | #define BRUTE_COMP_OK 0 16 | #define BRUTE_COMP_DIFFERENT 1 17 | #define BRUTE_COMP_TIMEOUT 2 18 | #define BRUTE_COMP_INCONSISTENT 3 19 | #define BRUTE_COMP_IMPOSSIBLE 4 20 | #define BRUTE_COMP_PROBLEM 5 21 | 22 | extern const char *brute_comp_err[]; 23 | 24 | int brute_comp(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /sources/Generator/count_solved.c: -------------------------------------------------------------------------------- 1 | /* count_solved.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "count_solved.h" 9 | #include "def.h" 10 | 11 | int count_solved() { 12 | int result = 0; 13 | for (int k = 0; k < 9; k++) { 14 | for (int j = 0; j < 9; j++) { 15 | if (grid[k][j] != 0) result++; 16 | } 17 | } 18 | return result; 19 | } 20 | -------------------------------------------------------------------------------- /sources/Generator/count_solved.h: -------------------------------------------------------------------------------- 1 | /* count_solved.h 2 | * 3 | * Counts the number of solved cells. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef COUNT_SOLVED 9 | #define COUNT_SOLVED 10 | 11 | int count_solved(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Generator/def.h: -------------------------------------------------------------------------------- 1 | /* def.h 2 | * 3 | * Definitions and declarations 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef DEF 9 | #define DEF 10 | 11 | // General definitions 12 | #define FALSE 0 13 | #define TRUE 1 14 | 15 | // Used in some strategies for clarity 16 | #define ROW 0 17 | #define COL 1 18 | #define BOX 2 19 | extern char *unit_names[3]; 20 | 21 | // grid declarations 22 | extern char grid[9][9]; 23 | extern char row[9][9][2]; 24 | extern char col[9][9][2]; 25 | extern char box[9][9][2]; 26 | extern char solved[9][9]; 27 | 28 | // Flags 29 | extern int silent; 30 | 31 | // Patch because Windows doesn't recognise srandom() and random() 32 | #ifdef __WIN32__ 33 | #define srandom srand 34 | #define random rand 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /sources/Generator/display.c: -------------------------------------------------------------------------------- 1 | /* display.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "display.h" 10 | 11 | void display() { 12 | char *h = " ++---+---+---++---+---+---++---+---+---++"; 13 | char *hh = " ++===+===+===++===+===+===++===+===+===++"; 14 | int jBase[] = {2, 6, 10, 15, 19, 23, 28, 32, 36}; 15 | printf(" 0 1 2 3 4 5 6 7 8\n"); 16 | for (int k = 0; k < 9; k++) { 17 | if (k%3 == 0) { 18 | printf("%s\n", hh); 19 | } 20 | else { 21 | printf("%s\n", h); 22 | } 23 | // 000 000 111 111 122 222 223 333 333 24 | // 234 678 012 567 901 345 890 234 678 25 | char top[42] = "|| | | || | | || | | ||"; 26 | char mid[42] = "|| | | || | | || | | ||"; 27 | char bot[42] = "|| | | || | | || | | ||"; 28 | char *displ[42] = {top, mid, bot}; 29 | for (int j = 0; j < 9; j++) { 30 | if (grid[k][j] == 0) { 31 | mid[jBase[j]+1] = ' '; 32 | } 33 | else { 34 | mid[jBase[j]+1] = '0' + grid[k][j]; 35 | } 36 | } // for (int j.. 37 | printf(" %s\n", displ[0]); 38 | printf("%d %s\n", k, displ[1]); 39 | printf(" %s\n", displ[2]); 40 | } 41 | printf("%s\n", hh); 42 | } 43 | -------------------------------------------------------------------------------- /sources/Generator/display.h: -------------------------------------------------------------------------------- 1 | /* display.h 2 | * 3 | * Displays the sudoku grid. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef DISPLAY 9 | #define DISPLAY 10 | 11 | void display(); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Generator/display_string.c: -------------------------------------------------------------------------------- 1 | /* display_string.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "display_string.h" 10 | 11 | void display_string(char *name) { 12 | for (int k = 0; k < 9; k++) { 13 | for (int j = 0; j < 9; j++) { 14 | printf("%d", grid[k][j]); 15 | } 16 | } 17 | if (name != NULL) printf(" \"%s\"", name); 18 | printf("\n"); 19 | } 20 | -------------------------------------------------------------------------------- /sources/Generator/display_string.h: -------------------------------------------------------------------------------- 1 | /* display_string.h 2 | * 3 | * Displays the sudoku string. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef DISPLAY_STRING 9 | #define DISPLAY_STRING 10 | 11 | void display_string(char *name); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Generator/fill.c: -------------------------------------------------------------------------------- 1 | /* fill.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "display.h" 10 | #include "fill.h" 11 | #include "fill_digit.h" 12 | 13 | int fill(void) { 14 | int problem_found = FALSE; 15 | int i; 16 | int kkount = 0; 17 | for (i = 1; i <= 9 && kkount < 729; i++) { 18 | int kount = 0; 19 | do { 20 | kount++; 21 | problem_found = fill_digit((char)i); 22 | if (!silent) printf("fill %d [%d %d]: %s\n", 23 | i, kount, kkount, (problem_found) ? "failed" : "succeeded" 24 | ); 25 | } while (problem_found && kount < 9); 26 | 27 | if (problem_found) { 28 | for (int k = 0; k < 9; k++) { 29 | for (int j = 0; j < 9; j++) { 30 | if (grid[k][j] == i || grid[k][j] == i-1) grid[k][j] = 0; 31 | } 32 | } 33 | i -= 2; 34 | } // if (problem_found.. 35 | kkount++; 36 | } 37 | return problem_found || kkount >= 729; 38 | } 39 | -------------------------------------------------------------------------------- /sources/Generator/fill.h: -------------------------------------------------------------------------------- 1 | /* fill.h 2 | * 3 | * Fills in a Sudoku 4 | * 5 | * Returns zero if everything is OK 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef FILL 11 | #define FILL 12 | 13 | int fill(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Generator/fill_digit.c: -------------------------------------------------------------------------------- 1 | /* fill_digit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "fill_digit.h" 10 | 11 | int fill_digit(char i) { 12 | const int other_box[9][2][2] = { // [this box][row/column][..] 13 | {/* 0 */ {-1 }, {-1 }}, 14 | {/* 1 */ { 0, -1}, {-1 }}, 15 | {/* 2 */ { 0, 1}, {-1 }}, 16 | {/* 3 */ {-1 }, { 0, -1}}, 17 | {/* 4 */ { 3, -1}, { 1, -1}}, 18 | {/* 5 */ { 3, 4}, { 2, -1}}, 19 | {/* 6 */ {-1 }, { 0, 3}}, 20 | {/* 7 */ { 6, -1}, { 1, 4}}, 21 | {/* 8 */ { 6, 7}, { 2, 5}}, 22 | }; 23 | int solved_cells[2][9] = {{-1, -1, -1, -1, -1, -1, -1, -1, -1}}; 24 | 25 | int problem_found = FALSE; 26 | int n_cells; 27 | int cell[9][2]; 28 | for (int kB = 0; kB < 9 && !problem_found; kB++) { 29 | problem_found = TRUE; 30 | n_cells = 0; 31 | for (int k = 0; k < 9; k++) { 32 | int kR = box[kB][k][ROW]; 33 | int kC = box[kB][k][COL]; 34 | if (grid[kR][kC] == 0) { 35 | int rc[2]; 36 | rc[ROW] = kR; 37 | rc[COL] = kC; 38 | int conflict = FALSE; 39 | for (int kRC = 0; kRC < 2 && !conflict; kRC++) { 40 | int kkS = other_box[kB][kRC][0]; 41 | if (kkS >= 0) { 42 | if (rc[kRC] == solved_cells[kRC][kkS]) { 43 | conflict = TRUE; 44 | } 45 | else { 46 | kkS = other_box[kB][kRC][1]; 47 | if (kkS >= 0 && rc[kRC] == solved_cells[kRC][kkS]) { 48 | conflict = TRUE; 49 | } 50 | } 51 | } // if (kkS.. 52 | } // for (int kRC.. 53 | 54 | if (!conflict) { 55 | cell[n_cells][ROW] = kR; 56 | cell[n_cells][COL] = kC; 57 | n_cells++; 58 | } 59 | } // if (grid[kR][kC].. 60 | } // for (int k.. 61 | 62 | // Pick a cell of the box 63 | if (n_cells > 0) { 64 | problem_found = FALSE; 65 | int kE = rand() % n_cells; 66 | solved_cells[ROW][kB] = cell[kE][ROW]; 67 | solved_cells[COL][kB] = cell[kE][COL]; 68 | grid[solved_cells[ROW][kB]][solved_cells[COL][kB]] = i; 69 | } 70 | 71 | } // for (int kB.. 72 | 73 | if (problem_found) { 74 | 75 | // Restore the grid to its initial status 76 | for (int m = 0; m < 9 && solved_cells[ROW][m] >= 0; m++) { 77 | grid[solved_cells[ROW][m]][solved_cells[COL][m]] = 0; 78 | } 79 | } 80 | return problem_found; 81 | } 82 | -------------------------------------------------------------------------------- /sources/Generator/fill_digit.h: -------------------------------------------------------------------------------- 1 | /* fill_digit.h 2 | * 3 | * Fills in one digit 4 | * 5 | * Returns zero if everything is OK 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef FILL_DIGIT 11 | #define FILL_DIGIT 12 | 13 | int fill_digit(char i); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Generator/in_box.c: -------------------------------------------------------------------------------- 1 | /* in_box.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "in_box.h" 9 | 10 | int in_box(int kR, int kC, int kB) { 11 | int kkR = kB / 3 * 3; 12 | int kkC = kB % 3 * 3; 13 | return (kR >= kkR && kR < kkR + 3 && kC >= kkC && kC < kkC + 3); 14 | } // in_box 15 | -------------------------------------------------------------------------------- /sources/Generator/in_box.h: -------------------------------------------------------------------------------- 1 | /* in_box.h 2 | * 3 | * Returns TRUE if the given cell is in the given box 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef IN_BOX 9 | #define IN_BOX 10 | 11 | int in_box(int kR, int kC, int kB); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Generator/inconsistent_grid.c: -------------------------------------------------------------------------------- 1 | /* inconsistent_grid.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "inconsistent_grid.h" 10 | #include "inconsistent_unit.h" 11 | 12 | int inconsistent_grid() { 13 | int result = FALSE; 14 | for (int k = 0; k < 9 && !result; k++) { 15 | result |= inconsistent_unit("row", k, row[k]); 16 | if (!result) { 17 | result |= inconsistent_unit("column", k, col[k]); 18 | if (!result) { 19 | result |= inconsistent_unit("box", k, box[k]); 20 | } 21 | } 22 | } // for (int k.. 23 | return result; 24 | } 25 | -------------------------------------------------------------------------------- /sources/Generator/inconsistent_grid.h: -------------------------------------------------------------------------------- 1 | /* inconsistent_grid.h 2 | * 3 | * Checks that there are no repeated solutions. 4 | * Returns TRUE if it finds a problem. 5 | * 6 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 7 | * 8 | */ 9 | #ifndef INCONSISTENT_GRID 10 | #define INCONSISTENT_GRID 11 | 12 | int inconsistent_grid(); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sources/Generator/inconsistent_unit.c: -------------------------------------------------------------------------------- 1 | /* inconsistent_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "inconsistent_unit.h" 10 | 11 | int inconsistent_unit(char *what, int kG, char unit[9][2]) { 12 | int result = FALSE; 13 | int i_vect[10] = {0}; 14 | for (int k = 0; k < 9 && !result; k++) { 15 | int kR = unit[k][ROW]; 16 | int kC = unit[k][COL]; 17 | int i = grid[kR][kC]; 18 | if (i > 0) { 19 | if (i_vect[i] == FALSE) { 20 | i_vect[i] = TRUE; 21 | } 22 | else { // we have a duplicate solution 23 | result = TRUE; 24 | } 25 | } // if (i.. 26 | } // for (int k.. 27 | return result; 28 | } 29 | -------------------------------------------------------------------------------- /sources/Generator/inconsistent_unit.h: -------------------------------------------------------------------------------- 1 | /* inconsistent_unit.h 2 | * 3 | * Checks that there are no repeated solutions within a unit and that all 4 | * cells have at least a candidate. 5 | * Returns TRUE if it finds a problem. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef INCONSISTENT_UNIT 11 | #define INCONSISTENT_UNIT 12 | 13 | int inconsistent_unit(char*, int, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Generator/init.c: -------------------------------------------------------------------------------- 1 | /* init.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "init.h" 10 | 11 | void init() { 12 | 13 | // Initialize the sudoku arrays 14 | for (int k = 0; k < 9; k++) { 15 | for (int j = 0; j < 9; j++) { 16 | grid[k][j] = 0; 17 | row[k][j][0] = k; 18 | row[k][j][1] = j; 19 | col[j][k][0] = k; 20 | col[j][k][1] = j; 21 | box[k/3*3+j/3][k%3*3+j%3][0] = k; 22 | box[k/3*3+j/3][k%3*3+j%3][1] = j; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sources/Generator/init.h: -------------------------------------------------------------------------------- 1 | /* init.h 2 | * 3 | * Initializes a sudoku grid. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef INIT 9 | #define INIT 10 | 11 | void init(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Generator/list_solved.c: -------------------------------------------------------------------------------- 1 | /* list_solved.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "list_solved.h" 10 | 11 | void list_solved(FILE *fp) { 12 | if (fp == NULL) { 13 | fp = stdout; 14 | } 15 | char spacing = (fp == stdout) ? ' ' : '\t'; 16 | int digits[10] = {0}; 17 | for (int k = 0; k < 9; k++) { 18 | for (int j = 0; j < 9; j++) { 19 | if (grid[k][j] != 0) { 20 | digits[(int)grid[k][j]]++; 21 | } 22 | } // for (int j.. 23 | } // for (int k.. 24 | for (int i = 1; i <= 9; i++) { 25 | fprintf(fp, "%c%d", spacing, digits[i]); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sources/Generator/list_solved.h: -------------------------------------------------------------------------------- 1 | /* list_solved.h 2 | * 3 | * Lists the digits on the given file pointer 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef LIST_SOLVED 9 | #define LIST_SOLVED 10 | 11 | #include 12 | 13 | void list_solved(FILE*); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Generator/multi_html.c: -------------------------------------------------------------------------------- 1 | /* multi_html.c 2 | * 3 | * This module must be able to display all different types of multi-grid 4 | * puzzles (only the boxes are shown): 5 | * 6 | * +---+---+---+ 7 | * | | | | 8 | * +---+---+---+ 9 | * | | 1 | | 10 | * +---+---+---+---+---+ N_GRIDS == 2 (double Sudokus) 11 | * | | | | | | 12 | * +---+---+---+---+---+ 13 | * | | 0 | | 14 | * +---+---+---+ 15 | * | | | | 16 | * +---+---+---+ 17 | * 18 | * +---+---+---+ 19 | * | | | | 20 | * +---+---+---+ 21 | * | | 1 | | 22 | * +---+---+---+---+---+ 23 | * | | | | | | 24 | * +---+---+---+---+---+ 25 | * | | 0 | | N_GRIDS == 3 26 | * +---+---+---+---+---+ 27 | * | | | | | | 28 | * +---+---+---+---+---+ 29 | * | | 2 | | 30 | * +---+---+---+ 31 | * | | | | 32 | * +---+---+---+ 33 | * 34 | * +---+---+---+ +---+---+---+ 35 | * | | | | | | | | 36 | * +---+---+---+ +---+---+---+ 37 | * | | 1 | | | | 3 | | 38 | * +---+---+---+---+---+---+---+ 39 | * | | | | | | | | 40 | * +---+---+---+---+---+---+---+ 41 | * | | 0 | | N_GRIDS == 4 42 | * +---+---+---+---+---+ 43 | * | | | | | | 44 | * +---+---+---+---+---+ 45 | * | | 2 | | 46 | * +---+---+---+ 47 | * | | | | 48 | * +---+---+---+ 49 | * 50 | * +---+---+---+ +---+---+---+ 51 | * | | | | | | | | 52 | * +---+---+---+ +---+---+---+ 53 | * | | 1 | | | | 3 | | 54 | * +---+---+===+===+===+---+---+ 55 | * | | I | | I | | 56 | * +---+---+---+---+---+---+---+ 57 | * I | 0 | I N_GRIDS == 5 (samurai) 58 | * +---+---+---+---+---+---+---+ (the central puzzle is highlighted) 59 | * | | I | | I | | 60 | * +---+---+===+===+===+---+---+ 61 | * | | 4 | | | | 2 | | 62 | * +---+---+---+ +---+---+---+ 63 | * | | | | | | | | 64 | * +---+---+---+ +---+---+---+ 65 | * 66 | * The cell borders are defined like in save_html.c, but their position 67 | * and the size of the HTML table depend on the type of puzzle. 68 | * 69 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 70 | * 71 | */ 72 | #include 73 | #include 74 | #include 75 | #include "def.h" 76 | #include "in_box.h" 77 | #include "multi_html.h" 78 | 79 | // Define the number of rows and columns needed for the multi-grid 80 | #if N_GRIDS == 2 81 | #define SIZE 15 82 | #else 83 | #define SIZE 21 84 | #endif 85 | 86 | char multi_string[N_GRIDS][2][82]; 87 | 88 | // The following table identifies the box of each grid that overlaps with 89 | // a corner box of grid 0 when creating multi-grid Sudokus. 90 | // 91 | // N_GRIDS kPuz=1 kPuz=2 kPuz=3 kPuz=4 92 | // 2 8 93 | // 3 8 0 94 | // 4 8 0 6 95 | // 5 8 0 6 2 96 | // 97 | // Puzzle: 0 1 2 3 4 98 | int overlapping_box[] = {0, 8, 0, 6, 2}; 99 | 100 | void multi_html(int seed, int what) { 101 | char *header_1 = 102 | "\n" 104 | "\n" 105 | "\n" 106 | "" 107 | ; 108 | char *header_2 = 109 | "\n" 110 | "\n" 112 | "\n\n\n\n" 132 | ; 133 | char *footer = "
\n\n"; 134 | 135 | // Puzzle offsets (row/column) for each puzzle (puzzle 0 is in the middle): 136 | // 0 1 2 3 4 137 | int offs[5][2] = {{6,6}, {0,0}, {12,12}, {0,12}, {12,0}}; 138 | 139 | // Combined multi-string (+1 to be able to close each string with a '\0'). 140 | char multi_s[SIZE][SIZE + 1]; 141 | for (int k = 0; k < SIZE; k++) { 142 | for (int j = 0; j < SIZE; j++) { 143 | multi_s[k][j] = ' '; 144 | } 145 | multi_s[k][SIZE] = '\0'; 146 | } 147 | 148 | // Copy the puzzles to the places they belong. 149 | // The boxes that overlap are set twice, first for puzzle 0 and then for 150 | // the other one. But it doesn't matter, as the two boxes are identical. 151 | // To set them only once, it would be sufficient to do the setting only 152 | // if (multi_s[baseR + kR][baseC + kC] == ' ') 153 | for (int kPuz = 0; kPuz < N_GRIDS; kPuz++) { 154 | int baseR = offs[kPuz][ROW]; 155 | int baseC = offs[kPuz][COL]; 156 | char *s = multi_string[kPuz][what]; 157 | for (int i = 0; i < 81; i++) { 158 | int kR = i / 9; 159 | int kC = i - kR * 9; 160 | multi_s[baseR + kR][baseC + kC] = (s[i] == '0') ? '.' : s[i]; 161 | } 162 | } 163 | for (int k = 0; k < SIZE; k++) printf("%s\n", multi_s[k]); 164 | printf("\n"); 165 | 166 | // Finally, save the HTML to disk 167 | char f_name[64] = {0}; 168 | sprintf(f_name, "%d_%d%c.html", seed, N_GRIDS, (what == SOL) ? 's' : 'p'); 169 | FILE *fp = fopen(f_name, "w"); 170 | if (fp == NULL) { 171 | printf("Unable to open the file '%s' for writing\n", f_name); 172 | } 173 | else { 174 | fprintf(fp, "%s%d%s", header_1, seed, header_2); 175 | for (int kRow = 0; kRow < SIZE; kRow++) { 176 | char *s = multi_s[kRow]; 177 | fprintf(fp, ""); 178 | for (int i = 0; i < SIZE; i++) { 179 | if (s[i] == ' ') { 180 | fprintf(fp, " "); 181 | } 182 | else { 183 | fprintf(fp, "%c", 184 | kRow % 3 * 3 + i % 3, 185 | (what == SOL || (s[i] == '.') ? "White" : "LightGray"), 186 | ((s[i] == '.') ? ' ' : s[i]) 187 | ); 188 | } 189 | } 190 | fprintf(fp, "\n"); 191 | } 192 | fprintf(fp, "%s\n", footer); 193 | fclose(fp); 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /sources/Generator/multi_html.h: -------------------------------------------------------------------------------- 1 | /* multi_html.h 2 | * 3 | * Saves a multi-grid puzzle to disk as a web page. 4 | * When the suffix is the empty string, it saves the puzzle. Otherwise, 5 | * it saves the solution. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef MULTI_HTML 11 | #define MULTI_HTML 12 | 13 | #define N_GRIDS 1 14 | 15 | #define PUZ 0 16 | #define SOL 1 17 | 18 | extern char multi_string[N_GRIDS][2][82]; 19 | extern int overlapping_box[]; 20 | 21 | void multi_html(int seed, int what); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /sources/Generator/save_html.c: -------------------------------------------------------------------------------- 1 | /* save_html.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "save_html.h" 10 | 11 | #define PLAIN_SUDOKU 0 12 | #define SYMBOLIC_SUDOKU 1 13 | #define IMAGE_SUDOKU 2 14 | 15 | #define SUDOKU_TYPE PLAIN_SUDOKU 16 | 17 | void save_html(char *puzzle, int seed, char *suffix) { 18 | char *header_1 = 19 | "\n" 21 | "\n" 22 | "\n" 23 | "" 24 | ; 25 | char *header_2 = 26 | "\n" 27 | "\n" 29 | "\n\n\n\n" 47 | ; 48 | char *footer = "
\n\n"; 49 | 50 | char f_name[64] = {0}; 51 | sprintf(f_name, "%d%s.html", seed, suffix); 52 | 53 | FILE *fp = fopen(f_name, "w"); 54 | if (fp == NULL) { 55 | printf("Unable to open the file '%s' for writing\n", f_name); 56 | } 57 | else { 58 | fprintf(fp, "%s%d%s", header_1, seed, header_2); 59 | for (int i = 0; i < 81; i++) { 60 | int kR = i / 9; 61 | int kC = i - kR * 9; 62 | if (kC == 0) fprintf(fp, ""); 63 | 64 | #if SUDOKU_TYPE == PLAIN_SUDOKU 65 | fprintf(fp, "%c", 66 | kR % 3 * 3 + kC % 3, ((puzzle[i] == '0') ? ' ' : puzzle[i]) 67 | ); 68 | #elif SUDOKU_TYPE == SYMBOLIC_SUDOKU 69 | char *symbols[10] = {"", "\u260E", "\u2622", "\u262F", "\u263C", "\u263D", 70 | "\u2658", "\u269B", "\u2665", "\u266B" 71 | }; 72 | 73 | fprintf(fp, "%s", 74 | kR % 3 * 3 + kC % 3, symbols[(int)(puzzle[i] - '0')] 75 | ); 76 | #elif SUDOKU_TYPE == IMAGE_SUDOKU 77 | fprintf(fp, " ", 78 | kR % 3 * 3 + kC % 3, puzzle[i] 79 | ); 80 | #endif 81 | 82 | if ((kC + 1) % 3 == 0) fprintf(fp, "\n"); 83 | if (kC == 8) fprintf(fp, "\n"); 84 | } 85 | fprintf(fp, "%s\n", footer); 86 | fclose(fp); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /sources/Generator/save_html.h: -------------------------------------------------------------------------------- 1 | /* save_html.h 2 | * 3 | * Saves a puzzle to disk as a web page 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef SAVE_HTML 9 | #define SAVE_HTML 10 | 11 | void save_html(char *puzzle, int seed, char *suffix); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Generator/sudoku_gen.c: -------------------------------------------------------------------------------- 1 | /* sudoku_gen.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "brute_comp.h" 11 | #include "count_solved.h" 12 | #include "def.h" 13 | #include "display.h" 14 | #include "display_string.h" 15 | #include "fill.h" 16 | #include "inconsistent_grid.h" 17 | #include "inconsistent_unit.h" 18 | #include "init.h" 19 | #include "in_box.h" 20 | #include "list_solved.h" 21 | #include "multi_html.h" 22 | #include "save_html.h" 23 | 24 | #define LOG_TO_FILE___NO 25 | #define FILE_NAME "puzzles.txt" 26 | 27 | #define SAVE_HTML_PUZZLE 28 | #define SAVE_HTML_SOLUTION 29 | 30 | #define DO_PATTERN___NO 31 | 32 | // N_GRIDS is defined in multi_html.h. 33 | // When N_GRIDS is between 2 and 5, it triggers the creation of multi-grid 34 | // puzzles. With any other value, the Generator creates a classic Sudoku. 35 | #define DO_MULTI_GRID (N_GRIDS >= 2 && N_GRIDS <= 5) 36 | 37 | // Parameters 38 | #define N_SET_QUADS 5 39 | #define N_SET_PAIRS 10 40 | #define N_SET_CELLS 0 41 | #define ADDITIONAL_CELLS TRUE 42 | #define FIRST_SEED 12345 43 | #define N_SEEDS 1 44 | 45 | // Global variables 46 | char *unit_names[3] = {"row", "column", "box"}; 47 | char grid[9][9]; 48 | char row[9][9][2]; 49 | char col[9][9][2]; 50 | char box[9][9][2]; 51 | char solved[9][9]; 52 | int silent = TRUE; 53 | 54 | // Variables and functions local to this module 55 | char puzzle[9][9]; 56 | int r_1[81]; 57 | int c_1[81]; 58 | int k_cell; 59 | int remove_quads(int k_puz); 60 | int remove_pairs(int k_puz); 61 | void make_clue_list(void); 62 | int remove_clues(int k_puz); 63 | void remove_more_clues(int k_puz); 64 | int check_uniqueness(void); 65 | 66 | // The following table identifies the box of grid 0 that overlaps with other 67 | // grids when creating multi-grid Sudokus. 68 | // The first box refers to puzzle0 and second one to the other puzzle: 69 | // 70 | // N_GRIDS kPuz=1 kPuz=2 kPuz=3 kPuz=4 71 | // 2 b0-b8 72 | // 3 b0-b8 b8-b0 73 | // 4 b0-b8 b8-b0 b2-b6 74 | // 5 b0-b8 b8-b0 b2-b6 b6-b2 75 | // 76 | // Puzzle: 0 1 2 3 4 77 | int box0[] = {-1, 0, 8, 2, 6}; 78 | 79 | #ifdef DO_PATTERN 80 | const char KEEP0[82] = 81 | "..1.1.1.." 82 | ".1..1..1." 83 | "1..1.1..1" 84 | "..1...1.." 85 | "11..1..11" 86 | "..1...1.." 87 | "1..1.1..1" 88 | ".1..1..1." 89 | "..1.1.1.." 90 | ; 91 | const char KEEP1[82] = 92 | "..11111.." 93 | ".1.....1." 94 | "1..111..1" 95 | "1.1...1.1" 96 | "1.1.1.1.1" 97 | "1.1...1.1" 98 | "1..111..1" 99 | ".1.....1." 100 | "..11111.." 101 | ; 102 | const char KEEP2[82] = 103 | "..11111.." 104 | ".1.....1." 105 | "1..111..1" 106 | "1.1...1.1" 107 | "1.1.1.1.1" 108 | "1.1...1.1" 109 | "1..111..1" 110 | ".1.....1." 111 | "..11111.." 112 | ; 113 | const char KEEP3[] = 114 | "..11111.." 115 | ".1.....1." 116 | "1..111..1" 117 | "1.1...1.1" 118 | "1.1.1.1.1" 119 | "1.1...1.1" 120 | "1..111..1" 121 | ".1.....1." 122 | "..11111.." 123 | ; 124 | const char KEEP4[] = 125 | "..11111.." 126 | ".1.....1." 127 | "1..111..1" 128 | "1.1...1.1" 129 | "1.1.1.1.1" 130 | "1.1...1.1" 131 | "1..111..1" 132 | ".1.....1." 133 | "..11111.." 134 | ; 135 | const char *KEEPS[5] = { KEEP0, KEEP1, KEEP2, KEEP3, KEEP4 }; 136 | #endif 137 | 138 | //======================================================================== main 139 | int main(int argc, char *argv[]) { 140 | printf("*** sudoku_gen ***\n"); 141 | char mess[32]; 142 | int n_seeds = N_SEEDS; 143 | int k_try = 0; 144 | 145 | #if DO_MULTI_GRID 146 | // When creating multi-grid puzzles, set n_seed to the number of 147 | // puzzles that you need 148 | n_seeds = N_GRIDS; 149 | #endif 150 | 151 | // Open a file to log the results 152 | FILE *fp = NULL; 153 | #ifdef LOG_TO_FILE 154 | fp = fopen(FILE_NAME, "a"); 155 | if (fp == NULL) { 156 | printf("Unable to open the file '%s' for reading\n", FILE_NAME); 157 | return EXIT_FAILURE; //==> 158 | } 159 | #endif 160 | 161 | // Try all the seeds in the given range 162 | unsigned long start_time = clock(); 163 | 164 | for (int k_seed = 0; k_seed < n_seeds; k_seed++) { 165 | int seed = FIRST_SEED + k_seed; 166 | srand(seed); 167 | int brute_result; 168 | int n; 169 | 170 | // Keep repeating the generation until you find a unique solution 171 | char puzzle_string[82]; 172 | char solution_string[82]; 173 | do { 174 | 175 | // Generate a solved Sudoku 176 | do { init(); } while (fill()); 177 | 178 | // Save the solved Sudoku 179 | for (int k = 0; k < 9; k++) { 180 | for (int j = 0; j < 9; j++) { 181 | solved[k][j] = grid[k][j]; 182 | puzzle[k][j] = grid[k][j]; 183 | } 184 | } 185 | 186 | #if DO_MULTI_GRID 187 | if (k_seed > 0) { 188 | // You arrive here if you are creating a multi-grid puzzle and 189 | // have already created the first one (puzzle 0). 190 | int k0 = box0[k_seed]/3*3; 191 | int j0 = box0[k_seed]%3*3; 192 | int kk = overlapping_box[k_seed]/3*3; 193 | int jj = overlapping_box[k_seed]%3*3; 194 | 195 | // Build the look-up list of numbers to match puzzle 0 when creating 196 | // subsequent grids. 197 | char map[10] = {0}; 198 | for (int k = 0; k < 3; k++) { 199 | for (int j = 0; j < 3; j++) { 200 | map[(int)grid[(kk + k)][jj + j]] = 201 | multi_string[0][SOL][(k0 + k)*9 + j0 + j] - '0' 202 | ; 203 | } 204 | } 205 | 206 | // Convert the numbers in the grid and save the modified grid 207 | for (int k = 0; k < 9; k++) { 208 | for (int j = 0; j < 9; j++) { 209 | grid[k][j] = map[(int)grid[k][j]]; 210 | solved[k][j] = grid[k][j]; 211 | puzzle[k][j] = grid[k][j]; 212 | } 213 | } 214 | #ifndef DO_PATTERN 215 | // Make the box that overlaps puzzle 0 identical to the 216 | // corresponding one of puzzle 0 217 | for (int k = 0; k < 3; k++) { 218 | for (int j = 0; j < 3; j++) { 219 | grid[(kk + k)][jj + j] = 220 | multi_string[0][PUZ][(k0 + k)*9 + j0 + j] - '0' 221 | ; 222 | } 223 | } 224 | #endif 225 | } 226 | #endif 227 | 228 | #ifdef DO_PATTERN 229 | for (int i = 0; i < 81; i++) { 230 | if (KEEPS[k_seed][i] == '.') { 231 | int k = i / 9; 232 | int j = i - k * 9; 233 | grid[k][j] = 0; 234 | puzzle[k][j] = 0; 235 | } 236 | } 237 | #else 238 | //========= Remove N_SET_QUADS quadruples of clues 239 | if (N_SET_QUADS > 0) { 240 | int success = remove_quads(k_seed); 241 | if (!success) { 242 | brute_result = BRUTE_COMP_DIFFERENT; 243 | goto skip; //==> 244 | } 245 | } 246 | 247 | //========= Remove N_SET_PAIRS pairs of clues 248 | if (N_SET_PAIRS > 0) { 249 | int success = remove_pairs(k_seed); 250 | if (!success) { 251 | brute_result = BRUTE_COMP_DIFFERENT; 252 | goto skip; //==> 253 | } 254 | } 255 | 256 | //========= Remove N_SET_CELLS individual clues and then some more 257 | make_clue_list(); 258 | k_cell = 0; 259 | if (N_SET_CELLS > 0) { 260 | int success = remove_clues(k_seed); 261 | if (!success) { 262 | brute_result = BRUTE_COMP_DIFFERENT; 263 | goto skip; //==> 264 | } 265 | } 266 | if (ADDITIONAL_CELLS && k_cell < 81) remove_more_clues(k_seed); 267 | #endif 268 | 269 | //========= Check whether the solution is really unique 270 | brute_result = check_uniqueness(); 271 | 272 | //========= Done 273 | for (int k = 0; k < 9; k++) { 274 | for (int j = 0; j < 9; j++) { 275 | grid[k][j] = puzzle[k][j]; 276 | } 277 | } 278 | n = count_solved(); 279 | if (!silent && fp == NULL) { 280 | display(); 281 | sprintf(mess, "seed %d %d", seed, n); 282 | display_string(mess); 283 | printf("The puzzle contains %d clues:", n); 284 | list_solved(stdout); 285 | } 286 | 287 | skip: // <== 288 | k_try++; 289 | printf("%d: %s\n", 290 | k_try, 291 | (brute_result == BRUTE_COMP_DIFFERENT) ? "No" : "Yes" 292 | ); 293 | } while (brute_result == BRUTE_COMP_DIFFERENT); 294 | 295 | // Save puzzle and solution into strings 296 | int kar = 0; 297 | for (int k = 0; k < 9; k++) { 298 | for (int j = 0; j < 9; j++) { 299 | puzzle_string[kar] = puzzle[k][j] + '0'; 300 | solution_string[kar] = solved[k][j] + '0'; 301 | kar++; 302 | } 303 | } 304 | puzzle_string[kar] = '\0'; 305 | solution_string[kar] = '\0'; 306 | 307 | #if DO_MULTI_GRID 308 | // Save the puzzle and solution strings to be combined later into 309 | // a multi-grid Sudoku 310 | for (int i = 0; i < 82; i++) { // copy also the '\0' at the end 311 | multi_string[k_seed][PUZ][i] = puzzle_string[i]; 312 | multi_string[k_seed][SOL][i] = solution_string[i]; 313 | } 314 | #endif 315 | 316 | #ifdef SAVE_HTML_PUZZLE 317 | save_html(puzzle_string, seed, "p"); 318 | #endif 319 | 320 | #ifdef SAVE_HTML_SOLUTION 321 | save_html(solution_string, seed, "s"); 322 | #endif 323 | if (fp != NULL) { 324 | printf("#%d\n", k_seed); 325 | fprintf(fp, "%s\t%d", puzzle_string, seed); 326 | if (brute_result != BRUTE_COMP_DIFFERENT) { 327 | fprintf(fp, "\t%d", n); 328 | list_solved(fp); 329 | } 330 | fprintf(fp, "\n"); 331 | } 332 | } // for (k_seed.. 333 | 334 | #if DO_MULTI_GRID 335 | multi_html(FIRST_SEED, PUZ); 336 | multi_html(FIRST_SEED, SOL); 337 | #endif 338 | 339 | unsigned long end_time = clock(); 340 | printf("********* done in %ld microseconds\n", end_time - start_time); 341 | if (fp != NULL) fclose(fp); 342 | return EXIT_SUCCESS; 343 | } 344 | 345 | //================================================================ remove_quads 346 | #define N_QUADS 20 347 | int remove_quads(int kPuz) { 348 | 349 | // Build a random list of cells to be quadrupled 350 | int r_4[N_QUADS]; 351 | int c_4[N_QUADS]; 352 | { 353 | char quads[9][9] = {{0}}; 354 | for (int k = 0; k < N_QUADS; k++) { 355 | int kR; 356 | int kC; 357 | do { 358 | int kk = rand() % N_QUADS; 359 | kR = kk >> 2; 360 | kC = kk - (kR << 2); 361 | } while (quads[kR][kC] > 0); 362 | r_4[k] = kR; 363 | c_4[k] = kC; 364 | quads[kR][kC] = 1; 365 | } 366 | } 367 | 368 | // Change quadruples until you get a matching solution 369 | int k_quad = -1; 370 | int n_quads = 0; 371 | while (n_quads < N_SET_QUADS && k_quad < N_QUADS-1) { 372 | k_quad++; 373 | n_quads++; 374 | int quad[4][2] = {{0}}; // [index][row/col] 375 | int kR = r_4[k_quad]; 376 | int kC = c_4[k_quad]; 377 | quad[0][ROW] = kR; 378 | quad[0][COL] = kC; 379 | quad[1][ROW] = kR; 380 | quad[1][COL] = 8 - kC; 381 | if (kR == 4) { 382 | quad[2][ROW] = kC; 383 | quad[2][COL] = kR; 384 | quad[3][ROW] = 8 - kC; 385 | quad[3][COL] = kR; 386 | } 387 | else { 388 | quad[2][ROW] = 8 - kR; 389 | quad[2][COL] = kC; 390 | quad[3][ROW] = 8 - kR; 391 | quad[3][COL] = 8 - kC; 392 | } 393 | if (!silent) printf("Removed quad %d:", k_quad); 394 | for (int k = 0; k < 4; k++) { 395 | int kR = quad[k][ROW]; 396 | int kC = quad[k][COL]; 397 | 398 | // The following 'if' is only needed when creating multi-grid puzzles 399 | if (kPuz == 0 || !in_box(kR, kC, overlapping_box[kPuz])) { 400 | grid[kR][kC] = 0; 401 | } 402 | if (!silent) printf("(%d,%d)", kR, kC); 403 | } 404 | if (!silent) printf("\n"); 405 | 406 | // Save the Sudoku puzzle after the removal 407 | for (int k = 0; k < 9; k++) { 408 | for (int j = 0; j < 9; j++) { 409 | puzzle[k][j] = grid[k][j]; 410 | } 411 | } 412 | 413 | // Solve with brute() and see whether the solution matches 414 | // the reference 415 | int brute_result = brute_comp(); 416 | if (!silent) printf("Brute after removing quad %d: %s\n", 417 | k_quad, brute_comp_err[brute_result] 418 | ); 419 | 420 | // If not, backtrack 421 | if (brute_result != BRUTE_COMP_OK) { 422 | if (!silent) printf("Backtracking the last quadruple\n"); 423 | puzzle[kR][kC] = solved[kR][kC]; 424 | puzzle[kR][8-kC] = solved[kR][8-kC]; 425 | puzzle[8-kR][kC] = solved[8-kR][kC]; 426 | puzzle[8-kR][8-kC] = solved[8-kR][8-kC]; 427 | n_quads--; 428 | } 429 | 430 | // Restore the puzzle to how it was before solving it 431 | for (int k = 0; k < 9; k++) { 432 | for (int j = 0; j < 9; j++) { 433 | grid[k][j] = puzzle[k][j]; 434 | } 435 | } 436 | } // while (n_quads.. 437 | int success = n_quads == N_SET_QUADS; 438 | if (!silent) { 439 | if (success) { 440 | printf("%d clues left after removing the quadruples\n", count_solved()); 441 | display(); 442 | 443 | // Save the Sudoku puzzle after removing the quadruples 444 | for (int k = 0; k < 9; k++) { 445 | for (int j = 0; j < 9; j++) { 446 | grid[k][j] = puzzle[k][j]; 447 | } 448 | } 449 | } 450 | else { 451 | printf("No unique solution when removing quadruples. Run aborted.\n"); 452 | } 453 | } 454 | return success; 455 | } // remove_quads 456 | 457 | //================================================================ remove_pairs 458 | #define N_PAIRS 40 459 | int remove_pairs(int kPuz) { 460 | 461 | // Build a random list of cells to be paired 462 | int r_2[N_PAIRS]; 463 | int c_2[N_PAIRS]; 464 | { 465 | char pairs[9][9] = {{0}}; 466 | for (int k = 0; k < N_PAIRS; k++) { 467 | int kR; 468 | int kC; 469 | do { 470 | int kk = rand() % N_PAIRS; 471 | kR = kk / 9; 472 | kC = kk - kR * 9; 473 | } while (pairs[kR][kC] > 0); 474 | r_2[k] = kR; 475 | c_2[k] = kC; 476 | pairs[kR][kC] = 1; 477 | } 478 | } 479 | 480 | // Change pairs until you get a matching solution 481 | int k_pair = -1; 482 | int n_pairs = 0; 483 | while (n_pairs < N_SET_PAIRS && k_pair < N_PAIRS-1) { 484 | int kR; 485 | int kC; 486 | do { 487 | k_pair++; 488 | if (k_pair < N_PAIRS) { 489 | kR = r_2[k_pair]; 490 | kC = c_2[k_pair]; 491 | if (grid[kR][kC] == 0) { 492 | if (!silent) printf("Pair %d: (%d,%d) (%d,%d) overlaps" 493 | " with quadruple\n", k_pair, kR, kC, 8-kR, 8-kC 494 | ); 495 | } 496 | } 497 | } while (grid[kR][kC] == 0 && k_pair < N_PAIRS); 498 | if (k_pair < N_PAIRS) { 499 | 500 | // The following two 'if' are only needed when creating multi-grid puzzles 501 | if (kPuz == 0 || !in_box(kR, kC, overlapping_box[kPuz])) { 502 | grid[kR][kC] = 0; 503 | } 504 | if (kPuz == 0 || !in_box(8 - kR, 8 - kC, overlapping_box[kPuz])) { 505 | grid[8-kR][8-kC] = 0; 506 | } 507 | n_pairs++; 508 | if (!silent) printf("Removed pair %d: (%d,%d) (%d,%d)\n", 509 | k_pair, kR, kC, 8-kR, 8-kC 510 | ); 511 | 512 | // Save the Sudoku puzzle after the removal 513 | for (int k = 0; k < 9; k++) { 514 | for (int j = 0; j < 9; j++) { 515 | puzzle[k][j] = grid[k][j]; 516 | } 517 | } 518 | 519 | // Solve with brute() and see whether the solution matches 520 | // the reference 521 | int brute_result = brute_comp(); 522 | if (!silent) printf("Brute after removing pair %d: %s\n", 523 | k_pair, brute_comp_err[brute_result] 524 | ); 525 | 526 | // If not, backtrack 527 | if (brute_result != BRUTE_COMP_OK) { 528 | if (!silent) printf("Backtracking the last pair\n"); 529 | puzzle[kR][kC] = solved[kR][kC]; 530 | puzzle[8-kR][8-kC] = solved[8-kR][8-kC]; 531 | n_pairs--; 532 | } 533 | 534 | // Restore the puzzle to how it was before solving it 535 | for (int k = 0; k < 9; k++) { 536 | for (int j = 0; j < 9; j++) { 537 | grid[k][j] = puzzle[k][j]; 538 | } 539 | } 540 | } // if (k_pair.. 541 | } // while (n_pairs.. 542 | 543 | int success = n_pairs == N_SET_PAIRS; 544 | if (!silent) { 545 | if (success) { 546 | printf("%d clues left after removing the pairs\n", count_solved()); 547 | display(); 548 | 549 | // Save the Sudoku puzzle after removing the pairs 550 | for (int k = 0; k < 9; k++) { 551 | for (int j = 0; j < 9; j++) { 552 | grid[k][j] = puzzle[k][j]; 553 | } 554 | } 555 | } 556 | else { 557 | printf("No unique solution when removing pairs. Run aborted.\n"); 558 | } 559 | } 560 | return success; 561 | } // remove_pairs 562 | 563 | //============================================================== make_clue_list 564 | void make_clue_list() { 565 | char singles[9][9] = {{0}}; 566 | for (int k = 0; k < 81; k++) { 567 | int kR; 568 | int kC; 569 | do { 570 | int kk = rand() % 81; 571 | kR = kk / 9; 572 | kC = kk - kR * 9; 573 | } while (singles[kR][kC] > 0); 574 | r_1[k] = kR; 575 | c_1[k] = kC; 576 | singles[kR][kC] = 1; 577 | } 578 | } // make_clue_list 579 | 580 | //================================================================ remove_clues 581 | int remove_clues(int kPuz) { 582 | int success = TRUE; 583 | int n_cells = 0; 584 | while (n_cells < N_SET_CELLS && success) { 585 | int kR; 586 | int kC; 587 | do { 588 | kR = r_1[k_cell]; 589 | kC = c_1[k_cell]; 590 | if (grid[kR][kC] == 0) { 591 | if (!silent) printf("1 Cell %d: (%d,%d) overlaps with quadruple" 592 | " or pair\n", k_cell, kR, kC 593 | ); 594 | } 595 | k_cell++; 596 | } while (grid[kR][kC] == 0 && k_cell < 81); 597 | if (k_cell > 81) { 598 | if (!silent) printf("1 No more cells available after removing" 599 | " %d clues. Run aborted.\n", n_cells 600 | ); 601 | success = FALSE; 602 | } 603 | // The following 'if' is only needed when creating multi-grid puzzles 604 | else if (kPuz == 0 || !in_box(kR, kC, overlapping_box[kPuz])) { 605 | grid[kR][kC] = 0; 606 | n_cells++; 607 | if (!silent) printf("1 Clue removal %d, removed" 608 | " cell %d: (%d,%d)\n", n_cells, k_cell-1, kR, kC 609 | ); 610 | 611 | // Save the Sudoku puzzle after the removal 612 | for (int k = 0; k < 9; k++) { 613 | for (int j = 0; j < 9; j++) { 614 | puzzle[k][j] = grid[k][j]; 615 | } 616 | } 617 | 618 | // Solve with brute() and see whether the solution matches 619 | // the reference 620 | int brute_result = brute_comp(); 621 | if (!silent) printf("1 Brute after removing cell %d: %s\n", 622 | k_cell-1, brute_comp_err[brute_result] 623 | ); 624 | 625 | // If not, backtrack 626 | if (brute_result != BRUTE_COMP_OK) { 627 | if (!silent) printf("1 Backtracking the last cell\n"); 628 | puzzle[kR][kC] = solved[kR][kC]; 629 | n_cells--; 630 | } 631 | 632 | // Restore the puzzle to how it was before solving it 633 | for (int k = 0; k < 9; k++) { 634 | for (int j = 0; j < 9; j++) { 635 | grid[k][j] = puzzle[k][j]; 636 | } 637 | } 638 | } // if (k_cell.. else .. 639 | } // while (n_cells.. 640 | 641 | if (success) { 642 | 643 | // Save the Sudoku puzzle after removing the individual clues 644 | for (int k = 0; k < 9; k++) { 645 | for (int j = 0; j < 9; j++) { 646 | grid[k][j] = puzzle[k][j]; 647 | } 648 | } 649 | if (!silent) { 650 | printf("%d clues left after removing %d individual clues\n", 651 | count_solved(), n_cells 652 | ); 653 | display(); 654 | } 655 | } 656 | return success; 657 | } // remove_clues 658 | 659 | //=========================================================== remove_more_clues 660 | void remove_more_clues(int kPuz) { 661 | int brute_result; 662 | do { 663 | int kR; 664 | int kC; 665 | do { 666 | kR = r_1[k_cell]; 667 | kC = c_1[k_cell]; 668 | if (grid[kR][kC] == 0) { 669 | if (!silent) printf("2 Cell %d: (%d,%d) overlaps with quadruple" 670 | " or pair\n", k_cell, kR, kC 671 | ); 672 | } 673 | k_cell++; 674 | } while (grid[kR][kC] == 0 && k_cell < 81); 675 | 676 | // The second part of the following 'if' is only needed when creating 677 | // multi-grid puzzles 678 | if (k_cell <= 81 && 679 | (kPuz == 0 || !in_box(kR, kC, overlapping_box[kPuz])) 680 | ) { 681 | grid[kR][kC] = 0; 682 | if (!silent) printf("2 Clue removal %d, removed" 683 | " cell %d: (%d,%d)\n", 81-count_solved(), k_cell-1, kR, kC 684 | ); 685 | 686 | // Save the Sudoku puzzle after the removal 687 | for (int k = 0; k < 9; k++) { 688 | for (int j = 0; j < 9; j++) { 689 | puzzle[k][j] = grid[k][j]; 690 | } 691 | } 692 | 693 | // Solve with brute() and see whether the solution matches the reference 694 | brute_result = brute_comp(); 695 | if (!silent) printf("2 Brute after removing cell %d: %s\n", 696 | k_cell-1, brute_comp_err[brute_result] 697 | ); 698 | 699 | // Restore the puzzle to how it was before solving it 700 | for (int k = 0; k < 9; k++) { 701 | for (int j = 0; j < 9; j++) { 702 | grid[k][j] = puzzle[k][j]; 703 | } 704 | } 705 | } // if (k_cell.. 706 | } while (brute_result == BRUTE_COMP_OK && k_cell < 81); 707 | 708 | // Restore the last clue removed 709 | if (brute_result != BRUTE_COMP_OK) { 710 | int kR = r_1[k_cell-1]; 711 | int kC = c_1[k_cell-1]; 712 | puzzle[kR][kC] = solved[kR][kC]; 713 | } 714 | } // remove_more_clues 715 | 716 | //============================================================ check_uniqueness 717 | int check_uniqueness() { 718 | int brute_result = BRUTE_COMP_OK; 719 | int incr = -8; 720 | while (incr < 9 && brute_result != BRUTE_COMP_DIFFERENT) { 721 | for (int k = 0; k < 9 && brute_result != BRUTE_COMP_DIFFERENT; k++) { 722 | for (int j = 0; j < 9 && brute_result != BRUTE_COMP_DIFFERENT; j++) { 723 | if (puzzle[k][j] == 0) { 724 | for (int kk = 0; kk < 9; kk++) { 725 | for (int jj = 0; jj < 9; jj++) { 726 | grid[kk][jj] = puzzle[kk][jj]; 727 | } // for (int jj.. 728 | } // for (int kk.. 729 | grid[k][j] = solved[k][j] + incr; 730 | int kB = k/3*3+j/3; 731 | if ( grid[k][j] < 1 732 | || grid[k][j] > 9 733 | || inconsistent_unit("row", k, row[k]) 734 | || inconsistent_unit("column", j, col[j]) 735 | || inconsistent_unit("box", kB, box[kB]) 736 | ) { 737 | grid[k][j] = 0; 738 | } 739 | else { 740 | brute_result = brute_comp(); 741 | } // if (grid[k][j].. 742 | } // if (puzzle[k]j].. 743 | } // for (int j.. 744 | } // for (int k.. 745 | incr++; 746 | if (incr == 0) incr++; 747 | } // while (incr.. 748 | return brute_result; 749 | } // check_uniqueness 750 | -------------------------------------------------------------------------------- /sources/Solver/backtrack.c: -------------------------------------------------------------------------------- 1 | /* backtrack.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "backtrack.h" 9 | #include "cleanup_around.h" 10 | #include "count_solved.h" 11 | #include "def.h" 12 | #include "display_strats_in_clear.h" 13 | #include "solve.h" 14 | 15 | #define MAX_DEPTH 10 16 | 17 | int backtrack(int depth) { 18 | #ifdef LOG_IN_OUT 19 | printf("--- backtrack (%d) >>>\n", depth); 20 | #endif 21 | 22 | int result = FALSE; 23 | char grid_backup[9][9][10]; 24 | 25 | // Select the cell 26 | int k; 27 | int j; 28 | { 29 | int max_i = -1; 30 | int row_max_i; 31 | int col_max_i; 32 | for (k = 0; k < 9 && max_i < 9; k++) { 33 | for (j = 0; j < 9 && max_i < 9; j++) { 34 | if (grid[k][j][0] > max_i) { 35 | max_i = grid[k][j][0]; 36 | row_max_i = k; 37 | col_max_i = j; 38 | } 39 | } 40 | } 41 | k = row_max_i; 42 | j = col_max_i; 43 | } 44 | 45 | // Process the cell 46 | char *elem = grid[k][j]; 47 | if (!silent) { 48 | for (int kd = 0; kd < depth; kd++) printf(" "); 49 | printf("backtrack (%d): (%d,%d) has candidates", depth, k, j); 50 | for (int i = 1; i <= 9; i++) { 51 | if (elem[i]) printf(" %d", i); 52 | } 53 | printf("\n"); 54 | } // if (!silent.. 55 | for (int i = 1; i <= 9 && !result; i++) { 56 | if (elem[i]) { 57 | 58 | // Save the current state of the grid 59 | for (int k1 = 0; k1 < 9; k1++) { 60 | for (int j1 = 0; j1 < 9; j1++) { 61 | for (int i1 = 0; i1 <= 9; i1++) { 62 | grid_backup[k1][j1][i1] = grid[k1][j1][i1]; 63 | } 64 | } // for (int j1.. 65 | } // for (int k1.. 66 | 67 | // Force a solution 68 | for (int i1 = 1; i1 <= 9; i1++) { 69 | elem[i1] = FALSE; 70 | } 71 | elem[i] = TRUE; 72 | elem[0] = 1; 73 | int orig_silent = silent; 74 | silent = TRUE; 75 | cleanup_around(k, j); 76 | 77 | // Attempt to solve the puzzle 78 | solve(); 79 | silent = orig_silent; 80 | 81 | // Check the result 82 | if (problem_found) { 83 | problem_found = FALSE; 84 | if (!silent) { 85 | for (int kd = 0; kd < depth; kd++) printf(" "); 86 | printf("backtrack (%d): %d unsuccessful\n", depth, i); 87 | } 88 | } // if (problem_found.. 89 | else { 90 | if (!silent) { 91 | for (int kd = 0; kd < depth; kd++) printf(" "); 92 | printf("backtrack (%d): %d successful (%d solved)\n", 93 | depth, i, count_solved() 94 | ); 95 | for (int kd = 0; kd < depth; kd++) printf(" "); 96 | printf("backtrack (%d) strategies:", depth); 97 | if (n_strats_used > 0) display_strats_in_clear(); 98 | else printf("none"); 99 | printf("\n"); 100 | } 101 | if (count_solved() == 81) { 102 | strats_used[n_strats_used] = 40 + depth; 103 | n_strats_used++; 104 | result = TRUE; 105 | } 106 | else if (depth < MAX_DEPTH) { 107 | result = backtrack(depth + 1); 108 | } 109 | } // if (problem_found.. else.. 110 | 111 | // If unsuccessful, restore the grid to its original content 112 | if (!result) { 113 | for (int k1 = 0; k1 < 9; k1++) { 114 | for (int j1 = 0; j1 < 9; j1++) { 115 | for (int i1 = 0; i1 <= 9; i1++) { 116 | grid[k1][j1][i1] = grid_backup[k1][j1][i1]; 117 | } 118 | } // for (int j1.. 119 | } // for (int k1.. 120 | } // if (!result 121 | } // if (elem[i].. 122 | } // for (int i.. 123 | 124 | #ifdef LOG_IN_OUT 125 | printf("<<< backtrack (%d) ---\n", depth); 126 | #endif 127 | return result; 128 | } 129 | -------------------------------------------------------------------------------- /sources/Solver/backtrack.h: -------------------------------------------------------------------------------- 1 | /* backtrack.h 2 | * 3 | * Trial and error strategy. 4 | * 5 | * Returns TRUE is successful. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef BACKTRACK 11 | #define BACKTRACK 12 | 13 | int backtrack(int); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/box_line.c: -------------------------------------------------------------------------------- 1 | /* box_line.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "box_line.h" 9 | #include "box_line_unit.h" 10 | #include "def.h" 11 | 12 | int box_line() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- box_line >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9 && !result; k++) { 18 | if (box_line_unit(ROW, row[k]) || box_line_unit(COL, col[k])) { 19 | result = TRUE; 20 | } 21 | } 22 | #ifdef LOG_IN_OUT 23 | printf("<<< box_line ---\n"); 24 | #endif 25 | return result; 26 | } 27 | -------------------------------------------------------------------------------- /sources/Solver/box_line.h: -------------------------------------------------------------------------------- 1 | /* box_line.h 2 | * 3 | * box-line strategy. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef BOX_LINE 9 | #define BOX_LINE 10 | 11 | int box_line(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/box_line_unit.c: -------------------------------------------------------------------------------- 1 | /* box_line_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "box_line_unit.h" 9 | #include "cleanup_around.h" 10 | #include "def.h" 11 | #include "remove_candidate.h" 12 | 13 | int box_line_unit(int row_col, char line[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- box_line_unit (%s) >>>\n", unit_names[row_col]); 16 | #endif 17 | int result = FALSE; 18 | int b[10]; for (int i = 0; i < 10; i++) { b[i] = -1; } 19 | int rc[10]; 20 | for (int j1 = 0; j1 < 9; j1++) { 21 | int kR = line[j1][ROW]; 22 | int kC = line[j1][COL]; 23 | char *elem = grid[kR][kC]; 24 | if (elem[0] > 1) { 25 | for (int i = 1; i <= 9; i++) { 26 | if (elem[i] != FALSE) { 27 | int kB = kR/3*3 + kC/3; 28 | if (b[i] == -1) { 29 | b[i] = kB; 30 | rc[i] = (row_col == ROW) ? kR : kC; 31 | } 32 | else if (b[i] != kB) { 33 | b[i] = -2; 34 | } 35 | } // if (elem[i].. 36 | } // for (int i.. 37 | } // if (elem[0].. 38 | } // for (int j1.. 39 | 40 | for (int i = 1; i <= 9; i++) { 41 | if (b[i] >= 0) { 42 | int log_printed = FALSE; 43 | int kB = b[i]; 44 | int kL = rc[i]; 45 | for (int kE = 0; kE < 9; kE++) { 46 | int kR = box[kB][kE][ROW]; 47 | int kC = box[kB][kE][COL]; 48 | int kRC = (row_col == ROW) ? kR : kC; 49 | if (kRC != kL) { 50 | char *elem = grid[kR][kC]; 51 | if (elem[i] != FALSE) { 52 | result = TRUE; 53 | #ifdef LOG_BOX_LINE 54 | if (!log_printed && !silent) { 55 | printf("box_line_unit: all candidates for %d of %s %d" 56 | " are in box %d\n", i, unit_names[row_col], kL, kB 57 | ); 58 | log_printed = TRUE; 59 | } 60 | #endif 61 | remove_candidate("box_line_unit", i, kR, kC); 62 | if (grid[kR][kC][0] == 1) { 63 | cleanup_around(kR, kC); 64 | } 65 | } // if (elem[i].. 66 | } // if (kRC.. 67 | } // for (int kE.. 68 | } // if (b[i].. 69 | } // for (int i.. 70 | 71 | #ifdef LOG_IN_OUT 72 | printf("<<< box_line_unit (%s) ---\n", unit_names[row_col]); 73 | #endif 74 | return result; 75 | } 76 | -------------------------------------------------------------------------------- /sources/Solver/box_line_unit.h: -------------------------------------------------------------------------------- 1 | /* box_line_unit.h 2 | * 3 | * box-line strategy. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef BOX_LINE_UNIT 9 | #define BOX_LINE_UNIT 10 | 11 | int box_line_unit(int, char[9][2]); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/cleanup.c: -------------------------------------------------------------------------------- 1 | /* cleanup.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup.h" 9 | #include "cleanup_around.h" 10 | #include "def.h" 11 | 12 | void cleanup() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- cleanup >>>\n"); 15 | #endif 16 | for (int k = 0; k < 9 && !problem_found; k++) { 17 | for (int j = 0; j < 9 && !problem_found; j++) { 18 | if (grid[k][j][0] == 1) cleanup_around(k, j); 19 | } 20 | } 21 | #ifdef LOG_IN_OUT 22 | printf("<<< cleanup ---\n"); 23 | #endif 24 | } 25 | -------------------------------------------------------------------------------- /sources/Solver/cleanup.h: -------------------------------------------------------------------------------- 1 | /* cleanup.h 2 | * 3 | * Removes duplicate numbers from rows, columns, and boxes. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef CLEANUP 9 | #define CLEANUP 10 | 11 | void cleanup(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/cleanup_around.c: -------------------------------------------------------------------------------- 1 | /* cleanup_around.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "cleanup_unit.h" 10 | #include "def.h" 11 | 12 | void cleanup_around(int k, int j) { 13 | #ifdef LOG_IN_OUT 14 | printf("--- cleanup_around (%d,%d) >>>\n", k, j); 15 | #endif 16 | cleanup_unit("row", k, j, row[k]); 17 | if (!problem_found) cleanup_unit("column", k, j, col[j]); 18 | if (!problem_found) cleanup_unit("box", k, j, box[k/3*3+j/3]); 19 | #ifdef LOG_IN_OUT 20 | printf("<<< cleanup_around (%d,%d) ---\n", k, j); 21 | #endif 22 | } 23 | -------------------------------------------------------------------------------- /sources/Solver/cleanup_around.h: -------------------------------------------------------------------------------- 1 | /* cleanup_around.h 2 | * 3 | * Removes duplicate numbers around a cell. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef CLEANUP_AROUND 9 | #define CLEANUP_AROUND 10 | 11 | void cleanup_around(int, int); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/cleanup_unit.c: -------------------------------------------------------------------------------- 1 | /* cleanup_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "cleanup_unit.h" 10 | #include "def.h" 11 | #include "remove_candidate.h" 12 | 13 | void cleanup_unit(char *what, int kElem, int jElem, char unit[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- cleanup_unit (%s) for (%d,%d) >>>\n", what, kElem, jElem); 16 | #endif 17 | char *elem = grid[kElem][jElem]; 18 | if (elem[0] == 1) { 19 | int i = 0; 20 | do { i++; } while (elem[i] == FALSE); 21 | for (int j1 = 0; j1 < 9 && !problem_found; j1++) { 22 | int kR = unit[j1][ROW]; 23 | int kC = unit[j1][COL]; 24 | if ((kR != kElem || kC != jElem) && grid[kR][kC][i] != FALSE) { 25 | char mess[40]; 26 | sprintf(mess, "cleanup_unit [%s of (%d,%d)]", what, kElem, jElem); 27 | remove_candidate(mess, i, kR, kC); 28 | if (grid[kR][kC][0] == 1 && !problem_found) { 29 | cleanup_around(kR, kC); 30 | } 31 | } 32 | } 33 | } 34 | #ifdef LOG_IN_OUT 35 | printf("<<< cleanup_unit (%s) for (%d,%d) ---\n", what, kElem, jElem); 36 | #endif 37 | } 38 | -------------------------------------------------------------------------------- /sources/Solver/cleanup_unit.h: -------------------------------------------------------------------------------- 1 | /* cleanup_unit.h 2 | * 3 | * Removes duplicate numbers from a unit. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef CLEANUP_UNIT 9 | #define CLEANUP_UNIT 10 | 11 | void cleanup_unit(char*, int, int, char[9][2]); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/count_candidates.c: -------------------------------------------------------------------------------- 1 | /* count_candidates.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "count_candidates.h" 9 | #include "def.h" 10 | 11 | int count_candidates() { 12 | #ifdef LOG_IN_OUT 13 | printf("--- count_candidates >>>\n"); 14 | #endif 15 | int result = 0; 16 | for (int k = 0; k < 9; k++) { 17 | for (int j = 0; j < 9; j++) { 18 | result += grid[k][j][0]; 19 | } 20 | } 21 | #ifdef LOG_IN_OUT 22 | printf("<<< count_candidates ---\n"); 23 | #endif 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /sources/Solver/count_candidates.h: -------------------------------------------------------------------------------- 1 | /* count_candidates.h 2 | * 3 | * Counts the total number of candidates in the game, including those in the 4 | * solved cells. That is, a solved game has 81 candidates. 5 | * 6 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 7 | * 8 | */ 9 | #ifndef COUNT_CANDIDATES 10 | #define COUNT_CANDIDATES 11 | 12 | int count_candidates(void); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sources/Solver/count_solved.c: -------------------------------------------------------------------------------- 1 | /* count_solved.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "count_solved.h" 9 | #include "def.h" 10 | 11 | int count_solved() { 12 | #ifdef LOG_IN_OUT 13 | printf("--- count_solved >>>\n"); 14 | #endif 15 | int result = 0; 16 | for (int k = 0; k < 9; k++) { 17 | for (int j = 0; j < 9; j++) { 18 | if (grid[k][j][0] == 1) result++; 19 | } 20 | } 21 | #ifdef LOG_IN_OUT 22 | printf("<<< count_solved ---\n"); 23 | #endif 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /sources/Solver/count_solved.h: -------------------------------------------------------------------------------- 1 | /* count_solved.h 2 | * 3 | * Counts the number of solved cells. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef COUNT_SOLVED 9 | #define COUNT_SOLVED 10 | 11 | int count_solved(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/def.h: -------------------------------------------------------------------------------- 1 | /* def.h 2 | * 3 | * Definitions and declarations 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef DEF 9 | #define DEF 10 | 11 | // General definitions 12 | #define FALSE 0 13 | #define TRUE 1 14 | 15 | // Definitions for logging 16 | #define LOG_FOOTPRINT 17 | #define LOG_HIDDEN_PAIR 18 | #define LOG_NAKED_QUAD 19 | #define LOG_HIDDEN_TRIPLE 20 | //#define LOG_IN_OUT 21 | #define LOG_LINES 22 | #define LOG_NAKED_PAIR 23 | #define LOG_NAKED_TRIPLE 24 | #define LOG_POINTING_LINE 25 | #define LOG_RECTANGLE 26 | #define LOG_REMOVE_CANDIDATE 27 | #define LOG_BOX_LINE 28 | #define LOG_UNIQUE 29 | #define LOG_XY_CHAIN 30 | #define LOG_Y_WING 31 | 32 | // Definitions to distinguish between Y-wing and XY-chain when invoking 33 | // pairs_find() 34 | #define DEF_Y_WING 0 35 | #define DEF_XY_CHAIN 1 36 | 37 | // Structure and typedef to build chains of cell coordinates. 38 | // It makes possible to develop functions that return lists of cells. 39 | #define MAX_INTER_N 13 40 | typedef struct rc_struct *rc_p_t; 41 | typedef struct rc_struct { 42 | int row; 43 | int col; 44 | rc_p_t next; 45 | } rc_struct_t; 46 | 47 | // Strategy functions 48 | typedef int (*f_ptr_t)(void); 49 | extern f_ptr_t *strat_all[]; 50 | extern char **strat_all_names[]; 51 | extern int n_strat_all[]; 52 | extern int n_levels; 53 | 54 | // List of strategies used in a solution 55 | // 0 means 'unique', 40 means 'backtrack' 56 | // Other strategies: (strat level) * 10 + (strat ID within the level) 57 | extern int strats_used[]; 58 | extern int n_strats_used; 59 | 60 | // Used in some strategies for clarity 61 | #define ROW 0 62 | #define COL 1 63 | #define BOX 2 64 | extern char *unit_names[3]; 65 | 66 | // Sudoku declarations in sudoku_solver.c 67 | extern char grid[9][9][10]; 68 | extern char row[9][9][2]; 69 | extern char col[9][9][2]; 70 | extern char box[9][9][2]; 71 | 72 | // Flags 73 | extern int problem_found; 74 | extern int silent; 75 | extern int backtracking; 76 | 77 | // Patch because Windows doesn't recognize srandom() and random() 78 | #ifdef __WIN32__ 79 | #define srandom srand 80 | #define random rand 81 | #endif 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /sources/Solver/display.c: -------------------------------------------------------------------------------- 1 | /* display.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "display.h" 10 | 11 | void display() { 12 | char *h = " ++---+---+---++---+---+---++---+---+---++"; 13 | char *hh = " ++===+===+===++===+===+===++===+===+===++"; 14 | int jBase[] = {2, 6, 10, 15, 19, 23, 28, 32, 36}; 15 | printf(" 0 1 2 3 4 5 6 7 8\n"); 16 | for (int k = 0; k < 9; k++) { 17 | if (k%3 == 0) { 18 | printf("%s\n", hh); 19 | } 20 | else { 21 | printf("%s\n", h); 22 | } 23 | // 000 000 111 111 122 222 223 333 333 24 | // 234 678 012 567 901 345 890 234 678 25 | char top[42] = "|| | | || | | || | | ||"; 26 | char mid[42] = "|| | | || | | || | | ||"; 27 | char bot[42] = "|| | | || | | || | | ||"; 28 | char *displ[42] = {top, mid, bot}; 29 | for (int j = 0; j < 9; j++) { 30 | if (grid[k][j][0] == 1) { 31 | int i = 0; 32 | do { i++; } while (grid[k][j][i] == 0); 33 | mid[jBase[j]] = '('; 34 | mid[jBase[j]+1] = '0'+i; 35 | mid[jBase[j]+2] = ')'; 36 | } 37 | else { 38 | for (int i = 0; i < 9; i++) { 39 | if (grid[k][j][i+1] != 0) { 40 | displ[i/3][jBase[j] + i%3] = '0' + (i+1); 41 | } 42 | } // for (int i.. 43 | } // else.. 44 | } // for (int j.. 45 | printf(" %s\n", displ[0]); 46 | printf("%d %s\n", k, displ[1]); 47 | printf(" %s\n", displ[2]); 48 | } 49 | printf("%s\n", hh); 50 | } 51 | -------------------------------------------------------------------------------- /sources/Solver/display.h: -------------------------------------------------------------------------------- 1 | /* display.h 2 | * 3 | * Displays the sudoku grid. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef DISPLAY 9 | #define DISPLAY 10 | 11 | void display(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/display_strats_in_clear.c: -------------------------------------------------------------------------------- 1 | /* display_strats_in_clear.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "display_strats_in_clear.h" 10 | 11 | void display_strats_in_clear() { 12 | for (int k = 0; k < n_strats_used; k++) { 13 | int level = strats_used[k] / 10; 14 | int k_strat = strats_used[k] - level * 10; 15 | printf(" '%s'", strat_all_names[level][k_strat]); 16 | } 17 | printf("\n"); 18 | } 19 | -------------------------------------------------------------------------------- /sources/Solver/display_strats_in_clear.h: -------------------------------------------------------------------------------- 1 | /* display_strats_in_clear.h 2 | * 3 | * Displays the list of strategy used 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef DISPLAY_STRATS_IN_CLEAR 9 | #define DISPLAY_STRATS_IN_CLEAR 10 | 11 | void display_strats_in_clear(); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/display_string.c: -------------------------------------------------------------------------------- 1 | /* display_string.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "display_string.h" 10 | 11 | void display_string() { 12 | printf("****** "); 13 | for (int k = 0; k < 9; k++) { 14 | for (int j = 0; j < 9; j++) { 15 | char *elem = grid[k][j]; 16 | if (elem[0] > 1) { 17 | printf("0"); 18 | } 19 | else { 20 | int i = 0; 21 | do { i++; } while (!elem[i]); 22 | printf("%d", i); 23 | } 24 | } 25 | } 26 | printf("\n"); 27 | } 28 | -------------------------------------------------------------------------------- /sources/Solver/display_string.h: -------------------------------------------------------------------------------- 1 | /* display_string.h 2 | * 3 | * Displays the sudoku string. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef DISPLAY_STRING 9 | #define DISPLAY_STRING 10 | 11 | void display_string(); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/execute_strategies.c: -------------------------------------------------------------------------------- 1 | /* execute_strategies.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "count_candidates.h" 9 | #include "count_solved.h" 10 | #include "def.h" 11 | #include "display.h" 12 | #include "display_string.h" 13 | #include "execute_strategies.h" 14 | #include "keep_going.h" 15 | #include "unique_loop.h" 16 | 17 | /* 18 | * It returns TRUE when at least one candidate is removed. 19 | * 20 | * It goes through all the strategies of the level, but only as long as no 21 | * candidate is removed. When that happens, it aborts the loop and returns. 22 | */ 23 | int execute_strategies(int level) { 24 | #ifdef LOG_IN_OUT 25 | printf("--- execute_strategies >>>\n"); 26 | #endif 27 | f_ptr_t *strats = strat_all[level]; 28 | char **strat_names = strat_all_names[level]; 29 | int n_strat = n_strat_all[level]; 30 | int n_candidates = count_candidates(); 31 | int n_candidates_initial = n_candidates; 32 | for ( int k = 0; 33 | k < n_strat && keep_going() && n_candidates == n_candidates_initial; 34 | k++ 35 | ) { 36 | (void)strats[k](); 37 | n_candidates = count_candidates(); 38 | if (n_candidates < n_candidates_initial) { 39 | if (!backtracking) { 40 | strats_used[n_strats_used] = level * 10 + k; 41 | n_strats_used++; 42 | } 43 | if (!silent) { 44 | printf("strategy: after '%s' the grid contains " 45 | "%d solved cells\n\n", strat_names[k], count_solved() 46 | ); 47 | } 48 | if (!silent) { display(); display_string(); } 49 | } 50 | } 51 | #ifdef LOG_IN_OUT 52 | printf("<<< execute_strategies ---\n"); 53 | #endif 54 | return (n_candidates < n_candidates_initial); 55 | } 56 | -------------------------------------------------------------------------------- /sources/Solver/execute_strategies.h: -------------------------------------------------------------------------------- 1 | /* execute_strategies.h 2 | * 3 | * Loops through all strategies of a unit as long as something happens. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef EXECUTE_STRATEGIES 9 | #define EXECUTE_STRATEGIES 10 | 11 | int execute_strategies(int); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/footprint.c: -------------------------------------------------------------------------------- 1 | /* footprint.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "footprint.h" 10 | 11 | rc_p_t footprint(int row, int col, void *mem) { 12 | #ifdef LOG_IN_OUT 13 | printf("--- footprint >>>\n"); 14 | #endif 15 | 16 | rc_p_t rc = (rc_p_t)mem; 17 | int box = row/3*3+col/3; 18 | 19 | rc_p_t p = rc; 20 | rc_p_t next; 21 | for (int k = 0; k < 9; k++) { 22 | for (int j = 0; j < 9; j++) { 23 | if (k != row || j != col) { 24 | if (k == row || j == col || k/3*3+j/3 == box) { 25 | p->row = k; 26 | p->col = j; 27 | next = p + 1; 28 | p->next = next; 29 | p = next; 30 | } // if (k == row.. 31 | } // if (k.. 32 | } // for (int j.. 33 | } // for (int k.. 34 | 35 | // Terminate the chain by clearing the 'next' pointer of the last cell 36 | p = rc + (FOOT_N - 1); 37 | p->next = NULL; 38 | 39 | #ifdef LOG_IN_OUT 40 | printf("<<< footprint ---\n"); 41 | #endif 42 | return rc; 43 | } 44 | -------------------------------------------------------------------------------- /sources/Solver/footprint.h: -------------------------------------------------------------------------------- 1 | /* footprint.h 2 | * 3 | * It returns the list of cells affected by a given cell. 4 | * 5 | * The cells affected are those that share either the row, the column, or the 6 | * box with the given cell. After eliminating the duplicates, it makes a 7 | * total of 20 cells. The function returns the coordinates by rows and then 8 | * columns, with the lowest row ID first and, within each row, with the lowest 9 | * column ID first. 10 | * 11 | * Parameters: 12 | * 1: IN, row ID of the cell for which the footprint is to be determined. 13 | * 2: IN, column ID of the cell for which the footprint is to be determined. 14 | * 3: IN, pointer to an area of memory large enough to contain the list = 15 | * sizeof(struct rc_struct) * 20. 16 | * 17 | * Development note: 18 | * The chunk of memory in which to store the list is passed in as an argument 19 | * to avoid allocating within the function the memory that must then be 20 | * released outside the function. 21 | * 22 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 23 | * 24 | */ 25 | #ifndef FOOTPRINT 26 | #define FOOTPRINT 27 | #include "def.h" 28 | 29 | #define FOOT_N 20 30 | 31 | rc_p_t footprint(int p1, int p2, void* p3); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /sources/Solver/hidden_pair.c: -------------------------------------------------------------------------------- 1 | /* hidden_pair.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "hidden_pair.h" 10 | #include "hidden_pair_unit.h" 11 | 12 | int hidden_pair() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- hidden_pair >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9 && !result; k++) { 18 | if ( hidden_pair_unit("row", row[k]) 19 | || hidden_pair_unit("column", col[k]) 20 | || hidden_pair_unit("box", box[k]) 21 | ) { 22 | result = TRUE; 23 | } 24 | } 25 | #ifdef LOG_IN_OUT 26 | printf("<<< hidden_pair ---\n"); 27 | #endif 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /sources/Solver/hidden_pair.h: -------------------------------------------------------------------------------- 1 | /* hidden_pair.h 2 | * 3 | * Hidden pair strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef HIDDEN_PAIR 11 | #define HIDDEN_PAIR 12 | 13 | int hidden_pair(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/hidden_pair_unit.c: -------------------------------------------------------------------------------- 1 | /* hidden_pair_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "hidden_pair_unit.h" 11 | #include "remove_candidate.h" 12 | 13 | int hidden_pair_unit(char *what, char unit[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- hidden_pair_unit (%s) >>>\n", what); 16 | #endif 17 | int result = FALSE; 18 | int n[10] = {0}; 19 | int coords[10][2][2]; 20 | for (int j1 = 0; j1 < 9; j1++) { 21 | int kR = unit[j1][ROW]; 22 | int kC = unit[j1][COL]; 23 | char *elem = grid[kR][kC]; 24 | if (elem[0] > 1) { 25 | for (int i = 1; i <= 9; i++) { 26 | if (elem[i] != FALSE) { 27 | if (n[i] < 2) { 28 | coords[i][n[i]][ROW] = kR; 29 | coords[i][n[i]][COL] = kC; 30 | } 31 | n[i]++; 32 | } // if (elem[i].. 33 | } // for (int i.. 34 | } // if (elem[0].. 35 | } // for (int j1.. 36 | 37 | for (int i = 1; i <= 9; i++) { 38 | if (n[i] == 2) { 39 | int log_printed = FALSE; 40 | for (int ii = i+1; ii <= 9; ii++) { 41 | if (n[ii] == 2 42 | && coords[i][0][ROW] == coords[ii][0][ROW] 43 | && coords[i][0][COL] == coords[ii][0][COL] 44 | && coords[i][1][ROW] == coords[ii][1][ROW] 45 | && coords[i][1][COL] == coords[ii][1][COL] 46 | ) { 47 | for (int kCell = 0; kCell < 2; kCell++) { 48 | int kR = coords[i][kCell][ROW]; 49 | int kC = coords[i][kCell][COL]; 50 | char *elem = grid[kR][kC]; 51 | if (elem[0] > 2) { 52 | result = TRUE; 53 | #ifdef LOG_HIDDEN_PAIR 54 | if (log_printed == FALSE && !silent) { 55 | printf("hidden_pair_unit: %d and %d are only in (%d,%d) and (%d,%d) of the same %s\n", 56 | i, ii, coords[i][0][0], coords[i][0][1], coords[i][1][0], coords[i][1][1], what 57 | ); 58 | log_printed = TRUE; 59 | } 60 | #endif 61 | for (int iii = 1; iii <= 9; iii++) { 62 | if (elem[iii] != FALSE && i != iii && ii != iii) { 63 | remove_candidate("hidden_pair_unit", iii, kR, kC); 64 | } 65 | } 66 | } // if (elem[0].. 67 | } // for (int kCell.. 68 | } // if (n[ii].. 69 | } // for (int ii.. 70 | } // if (n[i].. 71 | } // for (int i.. 72 | 73 | #ifdef LOG_IN_OUT 74 | printf("<<< hidden_pair_unit (%s) ---\n", what); 75 | #endif 76 | return result; 77 | } 78 | -------------------------------------------------------------------------------- /sources/Solver/hidden_pair_unit.h: -------------------------------------------------------------------------------- 1 | /* hidden_pair_unit.h 2 | * 3 | * Applies the hidden pair strategy to a unit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef HIDDEN_PAIR_UNIT 11 | #define HIDDEN_PAIR_UNIT 12 | 13 | int hidden_pair_unit(char*, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/hidden_triple.c: -------------------------------------------------------------------------------- 1 | /* hidden_triple.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "hidden_triple.h" 10 | #include "hidden_triple_unit.h" 11 | 12 | int hidden_triple() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- hidden_triple >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9 && !result; k++) { 18 | if ( hidden_triple_unit("row", row[k]) 19 | || hidden_triple_unit("column", col[k]) 20 | || hidden_triple_unit("box", box[k]) 21 | ) { 22 | result = TRUE; 23 | } 24 | } 25 | #ifdef LOG_IN_OUT 26 | printf("<<< hidden_triple ---\n"); 27 | #endif 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /sources/Solver/hidden_triple.h: -------------------------------------------------------------------------------- 1 | /* hidden_triple.h 2 | * 3 | * Hidden triple strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef HIDDEN_TRIPLE 11 | #define HIDDEN_TRIPLE 12 | 13 | int hidden_triple(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/hidden_triple_unit.c: -------------------------------------------------------------------------------- 1 | /* hidden_triple_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "hidden_triple_unit.h" 10 | #include "remove_candidate.h" 11 | 12 | int hidden_triple_unit(char *what, char unit[9][2]) { 13 | #ifdef LOG_IN_OUT 14 | printf("--- hidden_triple_unit (%s) >>>\n", what); 15 | #endif 16 | int result = FALSE; 17 | int n[10] = {0}; 18 | int coords[10][3][2]; 19 | for (int j1 = 0; j1 < 9; j1++) { 20 | int kR = unit[j1][ROW]; 21 | int kC = unit[j1][COL]; 22 | char *elem = grid[kR][kC]; 23 | if (elem[0] > 1) { 24 | for (int i = 1; i <= 9; i++) { 25 | if (elem[i] != FALSE) { 26 | if (n[i] < 3) { 27 | coords[i][n[i]][ROW] = kR; 28 | coords[i][n[i]][COL] = kC; 29 | } 30 | n[i]++; 31 | } // if (elem[i].. 32 | } // for (int i.. 33 | } // if (elem[0].. 34 | } // for (int j1.. 35 | 36 | for (int i1 = 1; i1 <= 9; i1++) { 37 | if (n[i1] == 3) { 38 | int log_printed = FALSE; 39 | for (int i2 = i1+1; i2 <= 9; i2++) { 40 | if ( n[i2] == 3 41 | && coords[i1][0][ROW] == coords[i2][0][ROW] 42 | && coords[i1][0][COL] == coords[i2][0][COL] 43 | && coords[i1][1][ROW] == coords[i2][1][ROW] 44 | && coords[i1][1][COL] == coords[i2][1][COL] 45 | && coords[i1][2][ROW] == coords[i2][2][ROW] 46 | && coords[i1][2][COL] == coords[i2][2][COL] 47 | ) { 48 | for (int i3 = i2+1; i3 <= 9; i3++) { 49 | if ( n[i3] == 3 50 | && coords[i1][0][ROW] == coords[i3][0][ROW] 51 | && coords[i1][0][COL] == coords[i3][0][COL] 52 | && coords[i1][1][ROW] == coords[i3][1][ROW] 53 | && coords[i1][1][COL] == coords[i3][1][COL] 54 | && coords[i1][2][ROW] == coords[i3][2][ROW] 55 | && coords[i1][2][COL] == coords[i3][2][COL] 56 | ) { 57 | for (int kCell = 0; kCell < 3; kCell++) { 58 | int kRow = coords[i1][kCell][ROW]; 59 | int kCol = coords[i1][kCell][COL]; 60 | char *elem = grid[kRow][kCol]; 61 | if (elem[0] > 3) { 62 | result = TRUE; 63 | #ifdef LOG_HIDDEN_TRIPLE 64 | if (log_printed == FALSE && !silent) { 65 | printf("hidden_triple_unit: %d, %d, and %d are only in " 66 | "(%d,%d), (%d,%d), and (%d,%d) of the same %s\n", 67 | i1, i2, i3, coords[i1][0][0], coords[i1][0][1], 68 | coords[i1][1][0], coords[i1][1][1], 69 | coords[i1][2][0], coords[i1][2][1], what 70 | ); 71 | log_printed = TRUE; 72 | } 73 | #endif 74 | for (int ki = 1; ki <= 9; ki++) { 75 | if (elem[ki] && ki != i1 && ki != i2 && ki != i3) { 76 | remove_candidate("hidden_triple_unit", ki, kRow, kCol); 77 | } 78 | } 79 | } // if (elem[0].. 80 | } // for (int kCell.. 81 | } // if (n[i3].. 82 | } // for (int i3.. 83 | } // if (n[i2].. 84 | } // for (int i2.. 85 | } // if (n[i1].. 86 | } // for (int i1.. 87 | 88 | #ifdef LOG_IN_OUT 89 | printf("<<< hidden_triple_unit (%s) ---\n", what); 90 | #endif 91 | return result; 92 | } 93 | -------------------------------------------------------------------------------- /sources/Solver/hidden_triple_unit.h: -------------------------------------------------------------------------------- 1 | /* hidden_triple_unit.h 2 | * 3 | * Applies the hidden triple strategy to a unit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef HIDDEN_TRIPLE_UNIT 11 | #define HIDDEN_TRIPLE_UNIT 12 | 13 | int hidden_triple_unit(char*, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/inconsistent_grid.c: -------------------------------------------------------------------------------- 1 | /* inconsistent_grid.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "inconsistent_grid.h" 10 | #include "inconsistent_unit.h" 11 | 12 | int inconsistent_grid() { 13 | int result = FALSE; 14 | for (int k = 0; k < 9 && !result; k++) { 15 | result |= inconsistent_unit("row", k, row[k]); 16 | if (!result) { 17 | result |= inconsistent_unit("column", k, col[k]); 18 | if (!result) { 19 | result |= inconsistent_unit("box", k, box[k]); 20 | } 21 | } 22 | } // for (int k.. 23 | return result; 24 | } 25 | -------------------------------------------------------------------------------- /sources/Solver/inconsistent_grid.h: -------------------------------------------------------------------------------- 1 | /* inconsistent_grid.h 2 | * 3 | * Checks that there are no repeated solutions. 4 | * Returns TRUE if it finds a problem. 5 | * 6 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 7 | * 8 | */ 9 | #ifndef INCONSISTENT_GRID 10 | #define INCONSISTENT_GRID 11 | 12 | int inconsistent_grid(); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sources/Solver/inconsistent_unit.c: -------------------------------------------------------------------------------- 1 | /* inconsistent_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "inconsistent_unit.h" 10 | 11 | int inconsistent_unit(char *what, int kG, char unit[9][2]) { 12 | int result = FALSE; 13 | int i_vect[10] = {0}; 14 | for (int k = 0; k < 9 && !result; k++) { 15 | int kR = unit[k][ROW]; 16 | int kC = unit[k][COL]; 17 | char *elem = grid[kR][kC]; 18 | if (elem[0] < 1) { // we have an empty cell 19 | result = TRUE; 20 | if (!silent) { 21 | printf("*** (%d,%d) has %d candidates\n", kR, kC, elem[0]); 22 | } 23 | } // if (elem[0].. 24 | else if (elem[0] == 1) { 25 | int i = 0; 26 | do { i++; } while (!elem[i]); 27 | if (i_vect[i] == FALSE) { 28 | i_vect[i] = TRUE; 29 | } 30 | else { // we have a duplicate solution 31 | result = TRUE; 32 | if (!silent) { 33 | printf("*** More than a single %d solution in %s %d\n", i, what, kG); 34 | } 35 | } // else.. 36 | } // else if (elem[0].. 37 | } // for (int k.. 38 | problem_found = result; 39 | return result; 40 | } 41 | -------------------------------------------------------------------------------- /sources/Solver/inconsistent_unit.h: -------------------------------------------------------------------------------- 1 | /* inconsistent_unit.h 2 | * 3 | * Checks that there are no repeated solutions within a unit and that all 4 | * cells have at least a candidate. 5 | * Returns TRUE if it finds a problem. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef INCONSISTENT_UNIT 11 | #define INCONSISTENT_UNIT 12 | 13 | int inconsistent_unit(char*, int, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/init.c: -------------------------------------------------------------------------------- 1 | /* init.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "init.h" 10 | 11 | void init(char *arg) { 12 | #ifdef LOG_IN_OUT 13 | printf("--- init >>>\n"); 14 | #endif 15 | 16 | // Initialize the sudoku arrays 17 | for (int k = 0; k < 9; k++) { 18 | for (int j = 0; j < 9; j++) { 19 | grid[k][j][0] = 9; 20 | for (int i = 1; i <= 9; i++) { 21 | grid[k][j][i] = TRUE; 22 | } 23 | row[k][j][0] = k; 24 | row[k][j][1] = j; 25 | col[j][k][0] = k; 26 | col[j][k][1] = j; 27 | box[k/3*3+j/3][k%3*3+j%3][0] = k; 28 | box[k/3*3+j/3][k%3*3+j%3][1] = j; 29 | } 30 | } 31 | 32 | // Save the sudoku string into the array 33 | for (int k = 0; k < 81; k++) { 34 | int kR = k / 9; 35 | int kC = k - kR * 9; 36 | if (arg[k] != '0') { 37 | for (int i = 1; i <= 9; i++) { 38 | grid[kR][kC][i] = FALSE; 39 | } 40 | grid[kR][kC][arg[k] - '0'] = TRUE; 41 | grid[kR][kC][0] = 1; 42 | } 43 | } 44 | 45 | /* 46 | // Display the allocated numbers 47 | for (int k = 0; k < 9; k++) { 48 | for (int j = 0; j < 9; j++) { 49 | if (grid[k][j][0] == 1) { 50 | int i = 0; 51 | do { 52 | i++; 53 | } while (grid[k][j][i] == 0); 54 | printf("%d", i); 55 | } 56 | else { 57 | printf("."); 58 | } 59 | } 60 | printf("\n"); 61 | } 62 | */ 63 | #ifdef LOG_IN_OUT 64 | printf("<<< init ---\n"); 65 | #endif 66 | } 67 | -------------------------------------------------------------------------------- /sources/Solver/init.h: -------------------------------------------------------------------------------- 1 | /* init.h 2 | * 3 | * Initialises a sudoku grid. 4 | * 5 | * Returns the number of solved cells. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef INIT 11 | #define INIT 12 | 13 | void init(char*); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/intersection.c: -------------------------------------------------------------------------------- 1 | /* intersection.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "footprint.h" 10 | #include "intersection.h" 11 | 12 | rc_p_t intersection(int r1, int c1, int r2, int c2, void *mem) { 13 | #ifdef LOG_IN_OUT 14 | printf("--- intersection (%d,%d) (%d,%d) >>>\n", r1, c1, r2, c2); 15 | #endif 16 | 17 | int cells_found = FALSE; 18 | rc_p_t retval = (rc_p_t)mem; 19 | rc_p_t foot1; 20 | rc_p_t foot2; 21 | 22 | // Allocate the memory for the two footprints 23 | void *mem_foots = malloc((FOOT_N * sizeof(rc_struct_t)) << 1); 24 | if (mem_foots != NULL) { 25 | rc_p_t mem1 = (rc_p_t)mem_foots; 26 | rc_p_t mem2 = (rc_p_t)(mem_foots + FOOT_N * sizeof(rc_struct_t)); 27 | 28 | // Obtain the two footprints 29 | foot1 = footprint(r1, c1, mem1); 30 | foot2 = footprint(r2, c2, mem2); 31 | } 32 | else { 33 | printf("*** intersection (%d,%d) (%d,%d): malloc failure\n", 34 | r1, c1, r2, c2 35 | ); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | // Build the list of cells common to the two footprints 40 | rc_p_t p = retval; 41 | rc_p_t p1 = foot1; 42 | rc_p_t p_prev = NULL; 43 | rc_p_t p_temp; 44 | do { 45 | rc_p_t p2 = foot2; 46 | do { 47 | if (p2->row == p1->row && p2->col == p1->col) { 48 | cells_found = TRUE; 49 | p->row = p1->row; 50 | p->col = p1->col; 51 | p_prev = p; 52 | p_temp = p + 1; 53 | p->next = p_temp; 54 | p = p_temp; 55 | } 56 | p_temp = p2->next; 57 | p2 = p_temp; 58 | } while (p2 != NULL); 59 | p_temp = p1->next; 60 | p1 = p_temp; 61 | } while (p1 != NULL); 62 | 63 | // Terminate the chain by clearing the 'next' pointer of the last cell 64 | p_prev->next = NULL; 65 | 66 | free(mem_foots); 67 | 68 | #ifdef LOG_IN_OUT 69 | printf("<<< intersection(%d,%d) (%d,%d) ---\n", r1, c1, r2, c2); 70 | #endif 71 | return (cells_found) ? retval : NULL; 72 | } 73 | -------------------------------------------------------------------------------- /sources/Solver/intersection.h: -------------------------------------------------------------------------------- 1 | /* intersection.h 2 | * 3 | * It returns the list of cells affected by two distinct cells or NULL if 4 | * the intersection is empty. 5 | * The coordinates are ordered by rows and then by columns, with the lowest 6 | * row ID first and, within each row, with the lowest column ID first. 7 | * 8 | * Two cells can affect different numbers of cells, depending on how their 9 | * units overlap: 10 | * No overlapping: 2 cells, (r1,c2) and (r2,c1). 11 | * Line overlapping: 7 cells, (r1,!c1 && !c2) or (!r1 && !r2, c1). 12 | * box overlapping: 7 cells, all within the box except the two. 13 | * box and line overlapping: 13 cells, all within the box except the 14 | * two, plus all within the line except the one within the same box. 15 | * 16 | * Parameters: 17 | * 1: IN, row ID of cell 1. 18 | * 2: IN, column ID of cell 1. 19 | * 3: IN, row ID of cell 2. 20 | * 4: IN, column ID of cell 2. 21 | * 5: IN, pointer to an area of memory large enough to contain the list = 22 | * sizeof(struct rc_struct) * 13. 23 | * 24 | * Development note: 25 | * The chunk of memory in which to store the list is passed in as an argument 26 | * to avoid allocating within the function the memory that must then be 27 | * released outside the function. 28 | * 29 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 30 | * 31 | */ 32 | #ifndef INTERSECTION 33 | #define INTERSECTION 34 | #include "def.h" 35 | 36 | rc_p_t intersection(int p1, int p2, int p3, int p4, void* p5); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /sources/Solver/keep_going.c: -------------------------------------------------------------------------------- 1 | /* keep_going.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "count_solved.h" 9 | #include "def.h" 10 | 11 | int keep_going(void) { 12 | return (count_solved() < 81 && !problem_found); 13 | } 14 | -------------------------------------------------------------------------------- /sources/Solver/keep_going.h: -------------------------------------------------------------------------------- 1 | /* keep_going.h 2 | * 3 | * It checks for errors and whether the puzzle has been completed. 4 | * It returns TRUE if there are no errors and the puzzle has not been completed. 5 | * 6 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 7 | * 8 | */ 9 | #ifndef KEEP_GOING 10 | #define KEEP_GOING 11 | 12 | int keep_going(void); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sources/Solver/lines.c: -------------------------------------------------------------------------------- 1 | /* lines.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include "cleanup_around.h" 10 | #include "def.h" 11 | #include "lines.h" 12 | #include "remove_candidate.h" 13 | 14 | int lines(int kRC, char *comb, int n, int i) { 15 | #ifdef LOG_IN_OUT 16 | printf("--- lines (%s) [", unit_names[kRC]); 17 | for (int k = 0; k < n; k++) printf("%d", comb[k]); 18 | printf("] %d >>>\n", i); 19 | #endif 20 | int result = FALSE; 21 | int list[9] = {0}; 22 | int n_list = 0; 23 | int abort = FALSE; 24 | for (int k = 0; k < n && !abort; k++) { 25 | int kk[2]; 26 | kk[0] = comb[k]; 27 | for (int j = 0; j < 9 && !abort; j++) { 28 | kk[1] = j; 29 | int kR = kk[kRC]; 30 | int kC = kk[1-kRC]; 31 | char *elem = grid[kR][kC]; 32 | if (elem[i]) { 33 | if (elem[0] == 1) { 34 | abort = TRUE; 35 | } 36 | else { 37 | if (!list[j]) n_list++; 38 | list[j] = TRUE; 39 | } 40 | } // if (elem[i].. 41 | } // for (int j.. 42 | } // for (int k.. 43 | 44 | if (!abort && n_list == n) { 45 | int log_printed = FALSE; 46 | for (int jj = 0; jj < 9; jj++) { 47 | if (list[jj]) { 48 | int kk[2]; 49 | kk[1] = jj; 50 | for (int k = 0; k < 9; k++) { 51 | if (memchr(comb, k, n) == NULL) { 52 | kk[0] = k; 53 | int kR = kk[kRC]; 54 | int kC = kk[1-kRC]; 55 | char *elem = grid[kR][kC]; 56 | 57 | // As usual, we assume that the Sudoku is not corrupted. It means 58 | // that 'i' doesn't solve any of the cells we are considering. 59 | // Otherwise, the candidate for 'i' would have already been removed 60 | // from the row, and the column ID would have not been saved in list. 61 | if (elem[i]) { 62 | result = TRUE; 63 | #ifdef LOG_LINES 64 | if (!log_printed && !silent) { 65 | printf("lines(%d): the %ss", n, unit_names[kRC]); 66 | for (int k1 = 0; k1 < n; k1++) printf(" %d", comb[k1]); 67 | printf(" let us eliminate %d from the %ss", i, 68 | unit_names[1-kRC] 69 | ); 70 | for (int k1 = 0; k1 < 9; k1++) { 71 | if (list[k1]) printf(" %d", k1); 72 | } 73 | printf("\n"); 74 | log_printed = TRUE; 75 | } 76 | #endif 77 | remove_candidate("lines", i, kR, kC); 78 | if (grid[kR][kC][0] == 1) { 79 | cleanup_around(kR, kC); 80 | } 81 | } // if (elem[i].. 82 | } // if (memchr(.. 83 | } // for (int k.. 84 | } // if (list[jj].. 85 | } // for (int jj.. 86 | } // if (!abort.. 87 | #ifdef LOG_IN_OUT 88 | printf("<<< lines (%s) [", unit_names[kRC]); 89 | for (int k = 0; k < n; k++) printf("%d", comb[k]); 90 | printf("] %d ---\n", i); 91 | #endif 92 | return result; 93 | } 94 | -------------------------------------------------------------------------------- /sources/Solver/lines.h: -------------------------------------------------------------------------------- 1 | /* lines.h 2 | * 3 | * Multiple-line strategy applied to a combination of lines and a digit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef LINES 11 | #define LINES 12 | 13 | int lines(int, char*, int, int); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/lines_2.c: -------------------------------------------------------------------------------- 1 | /* lines_2.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "lines.h" 10 | #include "lines_2.h" 11 | 12 | int lines_2() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- lines_2 >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | char comb[2]; 18 | 19 | // Try all 9*8 / 2! = 36 combinations 20 | for (int kRC = 0; kRC < 2 && !result; kRC++) { 21 | for (int k1 = 0; k1 < 8 && !result; k1++) { 22 | for (int k2 = k1+1; k2 < 9 && !result; k2++) { 23 | comb[0] = k1; 24 | comb[1] = k2; 25 | for (int i = 1; i <= 9 && !result; i++) { 26 | result |= lines(kRC, comb, 2, i); 27 | } 28 | } // for (int k2.. 29 | } // for (int k1.. 30 | } // for int kRC.. 31 | #ifdef LOG_IN_OUT 32 | printf("<<< lines_2 ---\n"); 33 | #endif 34 | return result; 35 | } 36 | -------------------------------------------------------------------------------- /sources/Solver/lines_2.h: -------------------------------------------------------------------------------- 1 | /* lines_2.h 2 | * 3 | * Two-line strategy (X-wing). 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef LINES_2 11 | #define LINES_2 12 | 13 | int lines_2(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/lines_3.c: -------------------------------------------------------------------------------- 1 | /* lines_3.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "lines.h" 10 | #include "lines_3.h" 11 | 12 | int lines_3() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- lines_3 >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | char comb[3]; 18 | 19 | // Try all 9*8*7 / 3! = 84 combinations 20 | for (int kRC = 0; kRC < 2 && !result; kRC++) { 21 | for (int k1 = 0; k1 < 7 && !result; k1++) { 22 | for (int k2 = k1+1; k2 < 8 && !result; k2++) { 23 | for (int k3 = k2+1; k3 < 9 && !result; k3++) { 24 | comb[0] = k1; 25 | comb[1] = k2; 26 | comb[2] = k3; 27 | for (int i = 1; i <= 9 && !result; i++) { 28 | result |= lines(kRC, comb, 3, i); 29 | } 30 | } // for (int k3.. 31 | } // for (int k2.. 32 | } // for (int k1.. 33 | } // for int kRC.. 34 | #ifdef LOG_IN_OUT 35 | printf("<<< lines_3 ---\n"); 36 | #endif 37 | return result; 38 | } 39 | -------------------------------------------------------------------------------- /sources/Solver/lines_3.h: -------------------------------------------------------------------------------- 1 | /* lines_3.h 2 | * 3 | * Three-line strategy (Swordfish). 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef LINES_3 11 | #define LINES_3 12 | 13 | int lines_3(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/lines_4.c: -------------------------------------------------------------------------------- 1 | /* lines_4.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "lines.h" 10 | #include "lines_4.h" 11 | 12 | int lines_4() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- lines_4 >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | char comb[4]; 18 | 19 | // Try all 9*8*7*6 / 4! = 126 combinations 20 | for (int kRC = 0; kRC < 2 && !result; kRC++) { 21 | for (int k1 = 0; k1 < 6 && !result; k1++) { 22 | for (int k2 = k1+1; k2 < 7 && !result; k2++) { 23 | for (int k3 = k2+1; k3 < 8 && !result; k3++) { 24 | for (int k4 = k3+1; k4 < 9 && !result; k4++) { 25 | comb[0] = k1; 26 | comb[1] = k2; 27 | comb[2] = k3; 28 | comb[3] = k4; 29 | for (int i = 1; i <= 9 && !result; i++) { 30 | result |= lines(kRC, comb, 4, i); 31 | } 32 | } // for (int k4.. 33 | } // for (int k3.. 34 | } // for (int k2.. 35 | } // for (int k1.. 36 | } // for int kRC.. 37 | #ifdef LOG_IN_OUT 38 | printf("<<< lines_4 ---\n"); 39 | #endif 40 | return result; 41 | } 42 | -------------------------------------------------------------------------------- /sources/Solver/lines_4.h: -------------------------------------------------------------------------------- 1 | /* lines_4.h 2 | * 3 | * Four-line strategy (Jellyfish). 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef LINES_4 11 | #define LINES_4 12 | 13 | int lines_4(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/naked_pair.c: -------------------------------------------------------------------------------- 1 | /* naked_pair.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "naked_pair.h" 10 | #include "naked_pair_unit.h" 11 | 12 | int naked_pair() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- naked_pair >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9 && !result; k++) { 18 | if ( naked_pair_unit("row", row[k]) 19 | || naked_pair_unit("column", col[k]) 20 | || naked_pair_unit("box", box[k]) 21 | ) { 22 | result = TRUE; 23 | } 24 | } 25 | #ifdef LOG_IN_OUT 26 | printf("<<< naked_pair ---\n"); 27 | #endif 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /sources/Solver/naked_pair.h: -------------------------------------------------------------------------------- 1 | /* naked_pair.h 2 | * 3 | * Naked pair strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef NAKED_PAIR 11 | #define NAKED_PAIR 12 | 13 | int naked_pair(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/naked_pair_unit.c: -------------------------------------------------------------------------------- 1 | /* naked_pair_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "naked_pair_unit.h" 11 | #include "remove_candidate.h" 12 | 13 | int naked_pair_unit(char *what, char unit[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- naked_pair_unit (%s) >>>\n", what); 16 | #endif 17 | int result = FALSE; 18 | int i1[9] = {0}; 19 | int i2[9] = {0}; 20 | int kRow[9] = {0}; 21 | int kCol[9] = {0}; 22 | int kk[9] = {0}; 23 | int n_pair = 0; 24 | 25 | // Make a list of the cells with naked pairs. 26 | for (int k = 0; k < 9; k++) { 27 | int kR = unit[k][0]; 28 | int kC = unit[k][1]; 29 | char *elem = grid[kR][kC]; 30 | if (elem[0] == 2) { 31 | kRow[n_pair] = kR; 32 | kCol[n_pair] = kC; 33 | kk[n_pair] = k; 34 | for (int i = 1; i <= 9 && i2[n_pair] == 0; i++) { 35 | if (elem[i] == TRUE) { 36 | if (i1[n_pair] == 0) { 37 | i1[n_pair] = i; 38 | } 39 | else { 40 | i2[n_pair] = i; 41 | } 42 | } // if (elem[i].. 43 | } // for (int i.. 44 | n_pair++; 45 | } // if (elem[0].. 46 | } // for (int k.. 47 | 48 | if (n_pair > 1) { 49 | for (int k1 = 0; k1 < n_pair - 1; k1++) { 50 | for (int k2 = k1 + 1; k2 < n_pair; k2++) { 51 | if (i1[k1] == i1[k2] && i2[k1] == i2[k2]) { 52 | int printed = FALSE; 53 | for (int k = 0; k < 9; k++) { 54 | if (k != kk[k1] && k != kk[k2]) { 55 | int kR = unit[k][0]; 56 | int kC = unit[k][1]; 57 | char *elem = grid[kR][kC]; 58 | int i_remove[2]; 59 | int n_remove = 0; 60 | if (elem[i1[k1]] == TRUE) { 61 | i_remove[n_remove] = i1[k1]; 62 | n_remove++; 63 | result = TRUE; 64 | } 65 | if (elem[i2[k1]] == TRUE) { 66 | i_remove[n_remove] = i2[k1]; 67 | n_remove++; 68 | result = TRUE; 69 | } 70 | #ifdef LOG_NAKED_PAIR 71 | if (n_remove > 0 && !printed && !silent) { 72 | printf("naked_pair_unit: (%d,%d) and (%d,%d) in the same %s" 73 | " only contain %d and %d\n", kRow[k1], kCol[k1], kRow[k2], 74 | kCol[k2], what, i1[k1], i2[k1] 75 | ); 76 | printed = TRUE; 77 | } 78 | #endif 79 | for (int ki = 0; ki < n_remove; ki++) { 80 | remove_candidate("naked_pair_unit", i_remove[ki], kR, kC); 81 | if (grid[kR][kC][0] == 1) { 82 | cleanup_around(kR, kC); 83 | } 84 | } 85 | } // if (k.. 86 | } // for (int k.. 87 | } // if (i1[k1].. 88 | } // for (int k2.. 89 | } // for (int k1.. 90 | } // if (n_pair.. 91 | 92 | #ifdef LOG_IN_OUT 93 | printf("<<< naked_pair_unit (%s) ---\n", what); 94 | #endif 95 | return result; 96 | } 97 | -------------------------------------------------------------------------------- /sources/Solver/naked_pair_unit.h: -------------------------------------------------------------------------------- 1 | /* naked_pair_unit.h 2 | * 3 | * Applies the naked pair strategy to a unit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef NAKED_PAIR_UNIT 11 | #define NAKED_PAIR_UNIT 12 | 13 | int naked_pair_unit(char*, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/naked_quad.c: -------------------------------------------------------------------------------- 1 | /* naked_quad.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "naked_quad.h" 10 | #include "naked_quad_unit.h" 11 | 12 | int naked_quad() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- naked_quad >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9 && !result; k++) { 18 | if ( naked_quad_unit("row", row[k]) 19 | || naked_quad_unit("column", col[k]) 20 | || naked_quad_unit("box", box[k]) 21 | ) { 22 | result = TRUE; 23 | } 24 | } 25 | #ifdef LOG_IN_OUT 26 | printf("<<< naked_quad ---\n"); 27 | #endif 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /sources/Solver/naked_quad.h: -------------------------------------------------------------------------------- 1 | /* naked_quad.h 2 | * 3 | * Naked quad strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef NAKED_QUAD 11 | #define NAKED_QUAD 12 | 13 | int naked_quad(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/naked_quad_unit.c: -------------------------------------------------------------------------------- 1 | /* naked_quad_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "naked_quad_unit.h" 11 | #include "remove_candidate.h" 12 | 13 | int naked_quad_unit(char *what, char unit[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- naked_quad_unit (%s) >>>\n", what); 16 | #endif 17 | int result = FALSE; 18 | int i1[9] = {0}; 19 | int i2[9] = {0}; 20 | int i3[9] = {0}; 21 | int i4[9] = {0}; 22 | int kRow[9] = {0}; 23 | int kCol[9] = {0}; 24 | int kk[9] = {0}; 25 | int n_quad = 0; 26 | 27 | // Make a list of the cells with naked quads. 28 | for (int k = 0; k < 9; k++) { 29 | int kR = unit[k][0]; 30 | int kC = unit[k][1]; 31 | char *elem = grid[kR][kC]; 32 | if (elem[0] == 4) { 33 | kRow[n_quad] = kR; 34 | kCol[n_quad] = kC; 35 | kk[n_quad] = k; 36 | for (int i = 1; i <= 9 && i4[n_quad] == 0; i++) { 37 | if (elem[i] == TRUE) { 38 | if (i1[n_quad] == 0) { 39 | i1[n_quad] = i; 40 | } 41 | else if (i2[n_quad] == 0) { 42 | i2[n_quad] = i; 43 | } 44 | else if (i3[n_quad] == 0) { 45 | i3[n_quad] = i; 46 | } 47 | else { 48 | i4[n_quad] = i; 49 | } 50 | } // if (elem[i].. 51 | } // for (int i.. 52 | n_quad++; 53 | } // if (elem[0].. 54 | } // for (int k.. 55 | 56 | if (n_quad > 3) { 57 | for (int k1 = 0; k1 < n_quad - 3; k1++) { 58 | for (int k2 = k1 + 1; k2 < n_quad - 2; k2++) { 59 | for (int k3 = k2 + 1; k3 < n_quad - 1; k3++) { 60 | for (int k4 = k3 + 1; k4 < n_quad; k4++) { 61 | if ( i1[k1] == i1[k2] && i1[k1] == i1[k3] && i1[k1] == i1[k4] 62 | && i2[k1] == i2[k2] && i2[k1] == i2[k3] && i2[k1] == i2[k4] 63 | && i3[k1] == i3[k2] && i3[k1] == i3[k3] && i3[k1] == i3[k4] 64 | && i4[k1] == i4[k2] && i4[k1] == i4[k3] && i4[k1] == i4[k4] 65 | ) { 66 | int printed = FALSE; 67 | for (int k = 0; k < 9; k++) { 68 | if (k != kk[k1] && k != kk[k2] && k != kk[k3] && k != kk[k4]) { 69 | int kR = unit[k][0]; 70 | int kC = unit[k][1]; 71 | char *elem = grid[kR][kC]; 72 | int i_remove[4]; 73 | int n_remove = 0; 74 | if (elem[i1[k1]] == TRUE) { 75 | i_remove[n_remove] = i1[k1]; 76 | n_remove++; 77 | result = TRUE; 78 | } 79 | if (elem[i2[k1]] == TRUE) { 80 | i_remove[n_remove] = i2[k1]; 81 | n_remove++; 82 | result = TRUE; 83 | } 84 | if (elem[i3[k1]] == TRUE) { 85 | i_remove[n_remove] = i3[k1]; 86 | n_remove++; 87 | result = TRUE; 88 | } 89 | if (elem[i4[k1]] == TRUE) { 90 | i_remove[n_remove] = i4[k1]; 91 | n_remove++; 92 | result = TRUE; 93 | } 94 | #ifdef LOG_NAKED_QUAD 95 | if (n_remove > 0 && !printed && !silent) { 96 | printf("naked_quad_unit: (%d,%d), (%d,%d), (%d,%d)," 97 | " and (%d,%d)" 98 | " in the same %s only contain %d, %d, %d, and %d\n", 99 | kRow[k1], kCol[k1], kRow[k2], kCol[k2], kRow[k3], 100 | kCol[k3], kRow[k4], kCol[k4], what, i1[k1], i2[k1], 101 | i3[k1], i4[k1] 102 | ); 103 | printed = TRUE; 104 | } 105 | #endif 106 | for (int ki = 0; ki < n_remove; ki++) { 107 | remove_candidate("naked_quad_unit", i_remove[ki], kR, kC); 108 | if (grid[kR][kC][0] == 1) { 109 | cleanup_around(kR, kC); 110 | } 111 | } 112 | } // if (k.. 113 | } // for (int k.. 114 | } // if (i1[k1].. 115 | } // for (int k4.. 116 | } // for (int k3.. 117 | } // for (int k2.. 118 | } // for (int k1.. 119 | } // if (n_quad.. 120 | 121 | #ifdef LOG_IN_OUT 122 | printf("<<< naked_quad_unit (%s) ---\n", what); 123 | #endif 124 | return result; 125 | } 126 | -------------------------------------------------------------------------------- /sources/Solver/naked_quad_unit.h: -------------------------------------------------------------------------------- 1 | /* naked_quad_unit.h 2 | * 3 | * Applies the naked quad strategy to a unit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef NAKED_QUAD_UNIT 11 | #define NAKED_QUAD_UNIT 12 | 13 | int naked_quad_unit(char*, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/naked_triple.c: -------------------------------------------------------------------------------- 1 | /* naked_triple.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "naked_triple.h" 10 | #include "naked_triple_unit.h" 11 | 12 | int naked_triple() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- naked_triple >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9 && !result; k++) { 18 | if ( naked_triple_unit("row", row[k]) 19 | || naked_triple_unit("column", col[k]) 20 | || naked_triple_unit("box", box[k]) 21 | ) { 22 | result = TRUE; 23 | } 24 | } 25 | #ifdef LOG_IN_OUT 26 | printf("<<< naked_triple ---\n"); 27 | #endif 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /sources/Solver/naked_triple.h: -------------------------------------------------------------------------------- 1 | /* naked_triple.h 2 | * 3 | * Naked triple strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef NAKED_TRIPLE 11 | #define NAKED_TRIPLE 12 | 13 | int naked_triple(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/naked_triple_unit.c: -------------------------------------------------------------------------------- 1 | /* naked_triple_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "naked_triple_unit.h" 11 | #include "remove_candidate.h" 12 | 13 | int naked_triple_unit(char *what, char unit[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- naked_triple_unit (%s) >>>\n", what); 16 | #endif 17 | int result = FALSE; 18 | int i1[9] = {0}; 19 | int i2[9] = {0}; 20 | int i3[9] = {0}; 21 | int kRow[9] = {0}; 22 | int kCol[9] = {0}; 23 | int kk[9] = {0}; 24 | int n_triple = 0; 25 | 26 | // Make a list of the cells with naked triples. 27 | for (int k = 0; k < 9; k++) { 28 | int kR = unit[k][0]; 29 | int kC = unit[k][1]; 30 | char *elem = grid[kR][kC]; 31 | if (elem[0] == 3) { 32 | kRow[n_triple] = kR; 33 | kCol[n_triple] = kC; 34 | kk[n_triple] = k; 35 | for (int i = 1; i <= 9 && i3[n_triple] == 0; i++) { 36 | if (elem[i] == TRUE) { 37 | if (i1[n_triple] == 0) { 38 | i1[n_triple] = i; 39 | } 40 | else if (i2[n_triple] == 0) { 41 | i2[n_triple] = i; 42 | } 43 | else { 44 | i3[n_triple] = i; 45 | } 46 | } // if (elem[i].. 47 | } // for (int i.. 48 | n_triple++; 49 | } // if (elem[0].. 50 | } // for (int k.. 51 | 52 | if (n_triple > 2) { 53 | for (int k1 = 0; k1 < n_triple - 2; k1++) { 54 | for (int k2 = k1 + 1; k2 < n_triple - 1; k2++) { 55 | for (int k3 = k2 + 1; k3 < n_triple; k3++) { 56 | if ( i1[k1] == i1[k2] && i1[k1] == i1[k3] 57 | && i2[k1] == i2[k2] && i2[k1] == i2[k3] 58 | && i3[k1] == i3[k2] && i3[k1] == i3[k3] 59 | ) { 60 | int printed = FALSE; 61 | for (int k = 0; k < 9; k++) { 62 | if (k != kk[k1] && k != kk[k2] && k != kk[k3]) { 63 | int kR = unit[k][0]; 64 | int kC = unit[k][1]; 65 | char *elem = grid[kR][kC]; 66 | int i_remove[3]; 67 | int n_remove = 0; 68 | if (elem[i1[k1]] == TRUE) { 69 | i_remove[n_remove] = i1[k1]; 70 | n_remove++; 71 | result = TRUE; 72 | } 73 | if (elem[i2[k1]] == TRUE) { 74 | i_remove[n_remove] = i2[k1]; 75 | n_remove++; 76 | result = TRUE; 77 | } 78 | if (elem[i3[k1]] == TRUE) { 79 | i_remove[n_remove] = i3[k1]; 80 | n_remove++; 81 | result = TRUE; 82 | } 83 | #ifdef LOG_NAKED_TRIPLE 84 | if (n_remove > 0 && !printed && !silent) { 85 | printf("naked_triple_unit: (%d,%d), (%d,%d)," 86 | " and (%d,%d)" 87 | " in the same %s only contain %d, %d, and %d\n", 88 | kRow[k1], kCol[k1], kRow[k2], kCol[k2], kRow[k3], 89 | kCol[k3], what, i1[k1], i2[k1], i3[k1] 90 | ); 91 | printed = TRUE; 92 | } 93 | #endif 94 | for (int ki = 0; ki < n_remove; ki++) { 95 | remove_candidate("naked_triple_unit", i_remove[ki], 96 | kR, kC 97 | ); 98 | if (grid[kR][kC][0] == 1) { 99 | cleanup_around(kR, kC); 100 | } 101 | } 102 | } // if (k.. 103 | } // for (int k.. 104 | } // if (i1[k1].. 105 | } // for (int k3.. 106 | } // for (int k2.. 107 | } // for (int k1.. 108 | } // if (n_triple.. 109 | 110 | #ifdef LOG_IN_OUT 111 | printf("<<< naked_triple_unit (%s) ---\n", what); 112 | #endif 113 | return result; 114 | } 115 | -------------------------------------------------------------------------------- /sources/Solver/naked_triple_unit.h: -------------------------------------------------------------------------------- 1 | /* naked_triple_unit.h 2 | * 3 | * Applies the naked triple strategy to a unit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef NAKED_TRIPLE_UNIT 11 | #define NAKED_TRIPLE_UNIT 12 | 13 | int naked_triple_unit(char*, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/pairs_data.c: -------------------------------------------------------------------------------- 1 | /* pairs_data.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include "pairs_data.h" 7 | 8 | char n_x_pairs[10][10] = {{0}}; 9 | char *x_pairs[10][10][3] = {{{0}}}; // 0= row, 1=column, 2=box 10 | -------------------------------------------------------------------------------- /sources/Solver/pairs_data.h: -------------------------------------------------------------------------------- 1 | /* pairs_data.h 2 | * 3 | * Data arrays to implement the Y-wing and XY-wing strategies. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef PAIRS_DATA 9 | #define PAIRS_DATA 10 | 11 | extern char n_x_pairs[10][10]; 12 | extern char *x_pairs[10][10][3]; // 0= row, 1=column, 2=box 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /sources/Solver/pairs_find.c: -------------------------------------------------------------------------------- 1 | /* pairs_find.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "pairs_data.h" 10 | #include "pairs_find.h" 11 | #include "xy_chain_digit.h" 12 | #include "y_wing_digit.h" 13 | 14 | int pairs_find(int chain_type) { 15 | #ifdef LOG_IN_OUT 16 | printf("--- pairs_find (%d) >>>\n", chain_type); 17 | #endif 18 | 19 | int result = FALSE; 20 | 21 | for (int k = 0; k <= 9; k++) { 22 | for (int j = 0; j <= 9; j++) { 23 | n_x_pairs[k][j] = 0; 24 | } 25 | } 26 | 27 | // Scan the grid to determine the distribution of pairs across candidates 28 | for (int k = 0; k < 9; k++) { 29 | for (int j = 0; j < 9; j++) { 30 | char *elem = grid[k][j]; 31 | if (elem[0] == 2) { 32 | int nn[2] = {0, 0}; 33 | int n = 0; 34 | for (int i = 1; j <= 9 && n < 2; i++) { 35 | if (elem[i] == TRUE) { 36 | nn[n] = i; 37 | n++; 38 | } 39 | } 40 | n_x_pairs[nn[0]][nn[1]]++; 41 | n_x_pairs[nn[0]][0]++; 42 | n_x_pairs[nn[1]][nn[0]]++; // let's make the matrix symmetrical... 43 | n_x_pairs[nn[1]][0]++; // ...not needed but makes life simpler 44 | n_x_pairs[0][0]++; // total count of pairs 45 | } // if (elem[0].. 46 | } // for (int j.. 47 | } // for (int k.. 48 | 49 | // Allocate space for the lists of row, column, and box IDs. 50 | // Multiply it by three to save row, column, and box (which is redundant). 51 | char *data_block = (char*)malloc(n_x_pairs[0][0] * sizeof(char*) * 3); 52 | if (data_block != NULL) { 53 | char *offset = data_block; 54 | for (int i1 = 1; i1 <= 9; i1++) { 55 | for (int i2 = 1; i2 <= 9; i2++) { 56 | for (int kkk = 0; kkk < 3; kkk++) { 57 | x_pairs[i1][i2][kkk] = offset; 58 | offset += n_x_pairs[i1][i2]; 59 | } 60 | } // for (int i2.. 61 | } // for (int i1.. 62 | } // if (data_block.. 63 | else { 64 | printf("*** pairs_find: malloc failure\n"); 65 | exit(EXIT_FAILURE); 66 | } 67 | 68 | // Clear the pair counters and then populate the pair grid while recounting 69 | // the pairs 70 | for (int i1 = 1; i1 <= 9; i1++) { 71 | for (int i2 = 1; i2 <= 9; i2++) { 72 | n_x_pairs[i1][i2] = 0; 73 | } 74 | } 75 | for (int k = 0; k < 9; k++) { 76 | for (int j = 0; j < 9; j++) { 77 | char *elem = grid[k][j]; 78 | if (elem[0] == 2) { 79 | int nn[2] = {0, 0}; 80 | int n = 0; 81 | for (int i = 1; j <= 9 && n < 2; i++) { 82 | if (elem[i] == TRUE) { 83 | nn[n] = i; 84 | n++; 85 | } 86 | } // for (int i.. 87 | int i1 = nn[0]; 88 | int i2 = nn[1]; 89 | int np = n_x_pairs[i1][i2]; 90 | n_x_pairs[i1][i2]++; 91 | n_x_pairs[i2][i1]++; 92 | x_pairs[i1][i2][ROW][np] = (char)k; 93 | x_pairs[i1][i2][COL][np] = (char)j; 94 | x_pairs[i1][i2][BOX][np] = (char)(k/3*3+j/3); 95 | x_pairs[i2][i1][ROW][np] = (char)k; 96 | x_pairs[i2][i1][COL][np] = (char)j; 97 | x_pairs[i2][i1][BOX][np] = (char)(k/3*3+j/3); 98 | } // if (elem[0].. 99 | } // for (int j.. 100 | } // for (int k.. 101 | 102 | // Go through the digits, but only if they have at least two pairs. 103 | typedef int (*chain_funct_ptr_t)(int); 104 | chain_funct_ptr_t chain_functs[] = {y_wing_digit, xy_chain_digit}; 105 | for (int i = 1; i <= 9 && !result; i++) { 106 | if (n_x_pairs[i][0] >= 2) { 107 | result |= chain_functs[chain_type](i); 108 | } 109 | } // for (int i.. 110 | 111 | /* Displaying the list of pairs */ /* 112 | for (int i1 = 1; i1 <= 9; i1++) { 113 | if (n_x_pairs[i1][0] > 0) { 114 | printf("\ntotal #pairs for %d: %d\n", i1, 115 | n_x_pairs[i1][0] 116 | ); 117 | } 118 | for (int i2 = 1; i2 <= 9; i2++) { 119 | if (n_x_pairs[i1][i2] > 0) { 120 | printf("%d %d [%d]:", i1, i2, 121 | n_x_pairs[i1][i2] 122 | ); 123 | for (int kkk = 0; 124 | kkk < n_x_pairs[i1][i2]; 125 | kkk++ 126 | ) { 127 | printf(" (%d,%d)", x_pairs[i1][i2][0][kkk], 128 | x_pairs[i1][i2][1][kkk] 129 | ); 130 | } 131 | printf("\n"); 132 | } 133 | } 134 | } 135 | */ 136 | free(data_block); 137 | 138 | #ifdef LOG_IN_OUT 139 | printf("<<< pairs_find (%d) ---\n", chain_type); 140 | #endif 141 | return result; 142 | } 143 | -------------------------------------------------------------------------------- /sources/Solver/pairs_find.h: -------------------------------------------------------------------------------- 1 | /* pairs_find.h 2 | * 3 | * Executes either the Y-wing or the XY-wing strategy 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef PAIRS_FIND 11 | #define PAIRS_FIND 12 | 13 | int pairs_find(int); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/pointing_line.c: -------------------------------------------------------------------------------- 1 | /* pointing_line.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "pointing_line.h" 10 | #include "pointing_line_box.h" 11 | 12 | int pointing_line() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- pointing_line >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9 && !result; k++) { 18 | result = pointing_line_box(k, box[k]); 19 | } 20 | #ifdef LOG_IN_OUT 21 | printf("<<< pointing_line ---\n"); 22 | #endif 23 | return result; 24 | } 25 | -------------------------------------------------------------------------------- /sources/Solver/pointing_line.h: -------------------------------------------------------------------------------- 1 | /* pointing_line.h 2 | * 3 | * Pointing-line strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * along with this program. If not, see . 9 | * 10 | */ 11 | #ifndef POINTING_LINE 12 | #define POINTING_LINE 13 | 14 | int pointing_line(void); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /sources/Solver/pointing_line_box.c: -------------------------------------------------------------------------------- 1 | /* pointing_line_box.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "pointing_line_box.h" 11 | #include "remove_candidate.h" 12 | 13 | int pointing_line_box(int boxid, char box[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- pointing_line_box >>>\n"); 16 | #endif 17 | int result = FALSE; 18 | int rc[10][2]; 19 | for (int i = 0; i < 10; i++) { 20 | for (int k = 0; k < 2; k++) { 21 | rc[i][k] = -1; 22 | } 23 | } 24 | for (int k = 0; k < 9; k++) { 25 | int kR = box[k][ROW]; 26 | int kC = box[k][COL]; 27 | char *elem = grid[kR][kC]; 28 | if (elem[0] > 1) { 29 | for (int i = 1; i <= 9; i++) { 30 | if (elem[i]) { 31 | for (int krc = 0; krc < 2; krc++) { 32 | if (rc[i][krc] == -1) { 33 | rc[i][krc] = box[k][krc]; 34 | } 35 | else if (box[k][krc] != rc[i][krc]) { 36 | rc[i][krc] = -2; 37 | } 38 | } // for (int krc.. 39 | } // if (elem[i].. 40 | } // for (int i.. 41 | } // if (elem[0].. 42 | } // for (int k.. 43 | 44 | int log_printed = FALSE; 45 | int kRC[2] = {0}; 46 | for (int i = 1; i <= 9; i++) { 47 | for (int krc = 0; krc < 2; krc++) { 48 | if (rc[i][krc] >= 0) { 49 | kRC[krc] = rc[i][krc]; 50 | for (int kk = 0; kk < 9; kk++) { 51 | kRC[1-krc] = kk; 52 | int kR = kRC[ROW]; 53 | int kC = kRC[COL]; 54 | if (boxid != kR/3*3+kC/3) { 55 | char *elem = grid[kR][kC]; 56 | if (elem[i]) { 57 | result = TRUE; 58 | #ifdef LOG_POINTING_LINE 59 | if (!log_printed && !silent) { 60 | printf("pointing_line_box: all candidates for %d" 61 | " of box %d are in ", i, boxid 62 | ); 63 | if (krc == ROW) { 64 | printf("row %d\n", kR); 65 | } 66 | else { 67 | printf("column %d\n", kC); 68 | } 69 | log_printed = TRUE; 70 | } 71 | #endif 72 | remove_candidate("pointing_line_box", i, kR, kC); 73 | if (grid[kR][kC][0] == 1) { 74 | cleanup_around(kR, kC); 75 | } 76 | } // if (elem[i].. 77 | } // if (boxid.. 78 | } // for (int kk.. 79 | } // if (rc[i][k].. 80 | } // for (int k.. 81 | } // for (int i.. 82 | 83 | #ifdef LOG_IN_OUT 84 | printf("<<< pointing_line_box ---\n"); 85 | #endif 86 | return result; 87 | } 88 | -------------------------------------------------------------------------------- /sources/Solver/pointing_line_box.h: -------------------------------------------------------------------------------- 1 | /* pointing_line_box.h 2 | * 3 | * Pointing-line strategy applied to a single box. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef POINTING_LINE_BOX 11 | #define POINTING_LINE_BOX 12 | 13 | int pointing_line_box(int, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/rectangle.c: -------------------------------------------------------------------------------- 1 | /* rectangle.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "rectangle.h" 10 | #include "rectangle_cell.h" 11 | #include "rectangle_pattern.h" 12 | 13 | int rectangle() { 14 | #ifdef LOG_IN_OUT 15 | printf("--- rectangle >>>\n"); 16 | #endif 17 | int result = FALSE; 18 | int pattern[9][4] = { 19 | {0,1,4,3}, {0,2,5,3}, {0,1,7,6}, 20 | {0,2,8,6}, {1,2,5,4}, {1,2,8,7}, 21 | {3,4,7,6}, {3,5,8,6}, {4,5,8,7} 22 | }; 23 | for (int k = 0; k < 9 && !result; k++) { 24 | result = rectangle_pattern(pattern[k]); 25 | } 26 | #ifdef LOG_IN_OUT 27 | printf("<<< rectangle ---\n"); 28 | #endif 29 | return result; 30 | } 31 | -------------------------------------------------------------------------------- /sources/Solver/rectangle.h: -------------------------------------------------------------------------------- 1 | /* rectangle.h 2 | * 3 | * Rectangle strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef RECTANGLE 11 | #define RECTANGLE 12 | 13 | int rectangle(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/rectangle_cell.c: -------------------------------------------------------------------------------- 1 | /* rectangle_cell.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "rectangle_cell.h" 11 | #include "rectangle_step.h" 12 | #include "remove_candidate.h" 13 | 14 | int rectangle_cell(int seq[4], int kR, int kC) { 15 | #ifdef LOG_IN_OUT 16 | printf("--- rectangle_cell ["); 17 | for (int k = 0; k < 4; k++) { 18 | if (k > 0) printf(","); 19 | printf("%d", seq[k]); 20 | } 21 | printf("] (%d,%d) >>>\n", kR, kC); 22 | #endif 23 | int result = FALSE; 24 | 25 | char *elem = grid[kR][kC]; 26 | for (int i = 1; i <= 9 && !result; i++) { 27 | if (elem[i]) { 28 | int res = rectangle_step(seq, 0, kR, kC, i, kR, kC); 29 | if (res == 0) { 30 | #ifdef LOG_RECTANGLE 31 | if (!silent) { 32 | printf("rectangle_cell: %d in (%d,%d) leads to contradiction" 33 | " when chained through the boxes [%d,%d,%d,%d]\n", 34 | i, kR, kC, seq[0], seq[1], seq[2], seq[3] 35 | ); 36 | } 37 | #endif 38 | remove_candidate("rectangle_cell", i, kR, kC); 39 | if (grid[kR][kC][0] == 1) { 40 | cleanup_around(kR, kC); 41 | } 42 | result = TRUE; 43 | } // if (res.. 44 | else if (res == -2) { 45 | result = TRUE; 46 | } 47 | } // if (elem[i].. 48 | } // for (int i.. 49 | 50 | #ifdef LOG_IN_OUT 51 | printf("<<< rectangle_cell ["); 52 | for (int k = 0; k < 4; k++) { 53 | if (k > 0) printf(","); 54 | printf("%d", seq[k]); 55 | } 56 | printf("] (%d,%d) ---\n", kR, kC); 57 | #endif 58 | return result; 59 | } 60 | -------------------------------------------------------------------------------- /sources/Solver/rectangle_cell.h: -------------------------------------------------------------------------------- 1 | /* rectangle_cell.h 2 | * 3 | * Rectangle strategy applied to all numbers in a cell within a pattern. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef RECTANGLE_CELL 11 | #define RECTANGLE_CELL 12 | 13 | int rectangle_cell(int[4], int, int); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/rectangle_pattern.c: -------------------------------------------------------------------------------- 1 | /* rectangle_pattern.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "rectangle_cell.h" 10 | #include "rectangle_pattern.h" 11 | 12 | int rectangle_pattern(int pattern[4]) { 13 | #ifdef LOG_IN_OUT 14 | printf("--- rectangle_pattern ("); 15 | for (int k = 0; k < 4; k++) { 16 | if (k > 0) printf(","); 17 | printf("%d", pattern[k]); 18 | } 19 | printf(") >>>\n"); 20 | #endif 21 | int result = FALSE; 22 | int cells = TRUE; 23 | for (int kB = 0; kB < 4 && cells; kB++) { 24 | cells = FALSE; 25 | int sID = pattern[kB]; 26 | for (int kE = 0; kE < 9 && !cells; kE++) { 27 | int kR = box[sID][kE][ROW]; 28 | int kC = box[sID][kE][COL]; 29 | if (grid[kR][kC][0] > 1) cells = TRUE; 30 | } 31 | } 32 | 33 | if (cells) { 34 | for (int kB = 0; kB < 4 && !result; kB++) { 35 | int seq[4]; 36 | for (int k = 0; k < 4; k++) { 37 | int kk = (kB + k) % 4; 38 | seq[k] = pattern[kk]; 39 | } 40 | int sID = seq[0]; 41 | for (int kE = 0; kE < 9 && !result; kE++) { 42 | int kR = box[sID][kE][ROW]; 43 | int kC = box[sID][kE][COL]; 44 | if (grid[kR][kC][0] > 1) result = rectangle_cell(seq, kR, kC); 45 | } // for (int kE.. 46 | } // for (int kB.. 47 | } // if (cells.. 48 | 49 | #ifdef LOG_IN_OUT 50 | printf("<<< rectangle_pattern ("); 51 | for (int k = 0; k < 4; k++) { 52 | if (k > 0) printf(","); 53 | printf("%d", pattern[k]); 54 | } 55 | printf(") ---\n"); 56 | #endif 57 | return result; 58 | } 59 | -------------------------------------------------------------------------------- /sources/Solver/rectangle_pattern.h: -------------------------------------------------------------------------------- 1 | /* rectangle_pattern.h 2 | * 3 | * Rectangle strategy applied to everything inside four specified boxes. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef RECTANGLE_PATTERN 11 | #define RECTANGLE_PATTERN 12 | 13 | #include "rectangle_cell.h" 14 | 15 | int rectangle_pattern(int[4]); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /sources/Solver/rectangle_step.c: -------------------------------------------------------------------------------- 1 | /* rectangle_step.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "rectangle_cell.h" 11 | #include "rectangle_step.h" 12 | #include "remove_candidate.h" 13 | 14 | int rectangle_step(int seq[4], int kBeq, int kR, int kC, int kN, 15 | int iR, int iC 16 | ) { 17 | #ifdef LOG_IN_OUT 18 | printf("--- rectangle_step ["); 19 | for (int k = kBeq; k < 4; k++) { 20 | printf("%d", seq[k]); 21 | if (k < 3) printf(","); 22 | } 23 | printf("] (%d,%d) %d >>>\n", kR, kC, kN); 24 | #endif 25 | int result = 0; 26 | int kB = seq[kBeq+1]; 27 | if (kBeq == 3) kB = seq[0]; 28 | int n = 0; 29 | int rows[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 30 | int cols[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; 31 | for (int kE = 0; kE < 9 && result >= 0; kE++) { 32 | int kkR = box[kB][kE][0]; 33 | int kkC = box[kB][kE][1]; 34 | char *elem = grid[kkR][kkC]; 35 | if (elem[0] == 1) { 36 | if (elem[kN] != FALSE) { 37 | result = -1; 38 | } 39 | } // if (elem[0].. 40 | else if (elem[kN] != FALSE && kkR != kR && kkC != kC) { 41 | rows[n] = kkR; 42 | cols[n] = kkC; 43 | n++; 44 | } // if (elem[0].. else.. 45 | } // for (int kE.. 46 | 47 | if (n > 0 || kBeq == 3) { 48 | if (kBeq < 3) { 49 | for (int k = 0; k < n && result >= 0; k++) { 50 | int res = rectangle_step(seq, kBeq+1, rows[k], cols[k], kN, iR, iC); 51 | if (res < 0) { 52 | result = res; 53 | } 54 | else { 55 | result |= res; 56 | } 57 | } // for (int k.. 58 | } // if (kBeq.. 59 | else { 60 | for (int k = 0; k < n && result == 0; k++) { 61 | if (rows[k] == iR && cols[k] == iC) { 62 | result = 1; 63 | } 64 | } // for (int k.. 65 | } // if (kBeq.. else.. 66 | } // if (n > 0.. 67 | else if (n == 0 && result != -1) { // the pointing-line strategy applies 68 | result = -2; 69 | #ifdef LOG_POINTING_LINE 70 | if (!silent) { 71 | printf("rectangle_step: %d cannot solve (%d,%d) because all the %ds " 72 | "in box %d are aligned with it (pointing-line strategy)\n", 73 | kN, kR, kC, kN, kB 74 | ); 75 | } 76 | #endif 77 | remove_candidate("rectangle_step", kN, kR, kC); 78 | if (grid[kR][kC][0] == 1) { 79 | cleanup_around(kR, kC); 80 | } 81 | } // if (n > 0.. else if (n.. 82 | 83 | #ifdef LOG_IN_OUT 84 | printf("<<< rectangle_step ["); 85 | for (int k = kBeq; k < 4; k++) { 86 | printf("%d", seq[k]); 87 | if (k < 3) printf(","); 88 | } 89 | printf("] (%d,%d) %d return=%d ---\n", kR, kC, kN, result); 90 | #endif 91 | return result; 92 | } 93 | -------------------------------------------------------------------------------- /sources/Solver/rectangle_step.h: -------------------------------------------------------------------------------- 1 | /* rectangle_step.h 2 | * 3 | * Rectangle strategy: moving to the next box. 4 | * 5 | * Returns 0 if no paths are possible, 1 or more if at least one path is 6 | * possible, -1 if the search on this cell and candidate should be aborted, 7 | * and -2 if rectangle should be aborted. 8 | * 9 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 10 | * 11 | */ 12 | #ifndef RECTANGLE_STEP 13 | #define RECTANGLE_STEP 14 | 15 | int rectangle_step(int[4], int, int, int, int, int, int); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /sources/Solver/remove_candidate.c: -------------------------------------------------------------------------------- 1 | /* remove_candidate.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "remove_candidate.h" 10 | 11 | void remove_candidate(char *caller, int i, int k, int j) { 12 | grid[k][j][i] = FALSE; 13 | grid[k][j][0]--; 14 | #ifdef LOG_REMOVE_CANDIDATE 15 | if (!silent) { 16 | printf("%s: removed %d from (%d,%d)\n", caller, i, k, j); 17 | } 18 | #endif 19 | if (grid[k][j][0] < 1) { 20 | if (!silent) { 21 | printf("*** No candidates left in (%d,%d)\n", k, j); 22 | } 23 | problem_found = TRUE; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /sources/Solver/remove_candidate.h: -------------------------------------------------------------------------------- 1 | /* remove_candidate.h 2 | * 3 | * Removes a single candidate. 4 | * It is appropriate to have all the removals done through a single function, 5 | * so that consistency checks can be performed. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef REMOVE_CANDIDATE 11 | #define REMOVE_CANDIDATE 12 | 13 | void remove_candidate(char *, int, int, int); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/solve.c: -------------------------------------------------------------------------------- 1 | /* solve.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include "count_candidates.h" 10 | #include "def.h" 11 | #include "display.h" 12 | #include "display_string.h" 13 | #include "execute_strategies.h" 14 | #include "keep_going.h" 15 | #include "solve.h" 16 | 17 | void solve() { 18 | #ifdef LOG_IN_OUT 19 | printf("--- solve >>>\n"); 20 | #endif 21 | if (!backtracking) n_strats_used = 0; 22 | int n_candidates = count_candidates(); 23 | int n_candidates_old = n_candidates + 1; 24 | 25 | while (keep_going() && n_candidates < n_candidates_old) { 26 | n_candidates_old = n_candidates; 27 | if (keep_going() && !execute_strategies(0)) { 28 | if (keep_going() && !execute_strategies(1)) { 29 | if (keep_going() && !execute_strategies(2)) { 30 | execute_strategies(3); 31 | } 32 | } 33 | } 34 | n_candidates = count_candidates(); 35 | } 36 | #ifdef LOG_IN_OUT 37 | printf("<<< solve ---\n"); 38 | #endif 39 | } 40 | -------------------------------------------------------------------------------- /sources/Solver/solve.h: -------------------------------------------------------------------------------- 1 | /* solve.h 2 | * 3 | * Solves a Sudoku without backtracking. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #ifndef SOLVE 9 | #define SOLVE 10 | 11 | void solve(); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /sources/Solver/sudoku_solver.c: -------------------------------------------------------------------------------- 1 | /* sudoku_solver.c 2 | * 3 | * Main program. 4 | * 5 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 6 | * 7 | */ 8 | #include 9 | #include 10 | #include 11 | #include "backtrack.h" 12 | #include "box_line.h" 13 | #include "cleanup.h" 14 | #include "count_candidates.h" 15 | #include "count_solved.h" 16 | #include "def.h" 17 | #include "display.h" 18 | #include "display_strats_in_clear.h" 19 | #include "display_string.h" 20 | #include "hidden_pair.h" 21 | #include "hidden_triple.h" 22 | #include "inconsistent_grid.h" 23 | #include "init.h" 24 | #include "lines_2.h" 25 | #include "lines_3.h" 26 | #include "lines_4.h" 27 | #include "naked_pair.h" 28 | #include "naked_quad.h" 29 | #include "naked_triple.h" 30 | #include "pointing_line.h" 31 | #include "rectangle.h" 32 | #include "solve.h" 33 | #include "unique_loop.h" 34 | #include "xy_chain.h" 35 | #include "y_wing.h" 36 | 37 | #define USE_FILES___NO 38 | #define N_LEVELS 4 // levels of strategies 39 | 40 | // Sudoku grid and Sudoku indexing arrays 41 | char grid[9][9][10]; 42 | char row[9][9][2]; 43 | char col[9][9][2]; 44 | char box[9][9][2]; 45 | 46 | // unit names used for display in clear 47 | char *unit_names[3] = {"row", "column", "box"}; 48 | 49 | // Arrays of strategies 50 | // 51 | // Trivial strategies (level 0) 52 | f_ptr_t strat0[] = {unique_loop}; 53 | char *strat0_names[] = { 54 | "unique-loop" 55 | }; 56 | // 57 | // Easy strategies (level 1) 58 | f_ptr_t strat1[] = {naked_pair, hidden_pair, box_line, pointing_line}; 59 | char *strat1_names[] = { 60 | "naked-pair", "hidden-pair", "box-line", "pointing-line" 61 | }; 62 | // 63 | // Intermediate strategies (level 2) 64 | f_ptr_t strat2[] = {naked_triple, hidden_triple, lines_2, 65 | naked_quad, y_wing 66 | }; 67 | char *strat2_names[] = { 68 | "naked-triple", "hidden-triple", "lines-2", "naked-quad", "Y-wing" 69 | }; 70 | // 71 | // Complex strategies (level 3) 72 | f_ptr_t strat3[] = {rectangle, xy_chain, lines_3, lines_4}; 73 | char *strat3_names[] = { 74 | "rectangle", "XY-chain", "lines-3", "lines-4" 75 | }; 76 | // 77 | // All strategies 78 | f_ptr_t *strat_all[] = { 79 | &strat0[0], &strat1[0], &strat2[0], &strat3[0] 80 | }; 81 | char **strat_all_names[] = { 82 | &strat0_names[0], &strat1_names[0], &strat2_names[0], &strat3_names[0] 83 | }; 84 | int n_strat_all[] = { 85 | sizeof(strat0)/sizeof(f_ptr_t), 86 | sizeof(strat1)/sizeof(f_ptr_t), 87 | sizeof(strat2)/sizeof(f_ptr_t), 88 | sizeof(strat3)/sizeof(f_ptr_t) 89 | }; 90 | int n_levels = N_LEVELS; 91 | 92 | // List of used strategies (never seen more than 27) 93 | int strats_used[50]; 94 | int n_strats_used; 95 | 96 | // Global flags, to 'pop out' from nested loops and calls 97 | int problem_found = FALSE; 98 | int silent = FALSE; 99 | int backtracking = FALSE; 100 | 101 | //==================================================================== main 102 | int main(int argc, char *argv[]) { 103 | printf("*** sudoku_solver ***\n"); 104 | 105 | #ifdef USE_FILES 106 | 107 | char *infile = "puzzles.txt"; 108 | char *outfile = "solutions.txt"; 109 | FILE *fpr = fopen(infile, "r"); 110 | FILE *fpw = fopen(outfile, "a"); 111 | if (fpr == NULL) { 112 | printf("File \"%s\" failed to open\n", infile); 113 | } 114 | else if (fpw == NULL) { 115 | printf("File \"%s\" failed to open\n", outfile); 116 | } 117 | else { 118 | silent = TRUE; 119 | 120 | // Keep reading from file until you reach the EOF 121 | int n_lines = 0; 122 | int n_hints = 0; 123 | while (!feof(fpr) && n_hints >= 0) { 124 | char line[100]; // 90 would be enough, but... 125 | line[0] = '\0'; 126 | (void)fgets(line, 99, fpr); 127 | if (line != NULL && strlen(line) > 80) { 128 | char sudoku_s[82]; 129 | int seed; 130 | n_hints = -1; 131 | sscanf(line, "%s\t%d\t%d", sudoku_s, &seed, &n_hints); 132 | if (n_hints > 0) { 133 | fprintf(fpw, "%s\t%d\t%d", sudoku_s, seed, n_hints); 134 | init(sudoku_s); 135 | cleanup(); 136 | solve(); 137 | if (count_solved() < 81) { 138 | backtracking = TRUE; 139 | backtrack(0); 140 | backtracking = FALSE; 141 | } 142 | printf("%d\n", n_lines); 143 | fprintf(fpw, "\t%s\t%d\t%d", 144 | inconsistent_grid() ? "inconsistent" : "consistent", 145 | count_solved(), 146 | n_strats_used 147 | ); 148 | for (int k = 0; k < n_strats_used; k++) { 149 | fprintf(fpw, "\t%d", strats_used[k]); 150 | } 151 | fprintf(fpw, "\n"); 152 | n_lines++; 153 | } // if (n_hints.. 154 | } // if (line.. 155 | } // while (TRUE.. 156 | } // if (fpr .. else .. 157 | if (fpr != NULL) fclose(fpr); 158 | if (fpw != NULL) fclose(fpw); 159 | 160 | #else 161 | 162 | // Check for the presence of an input Sudoku string 163 | if (argc < 2) { 164 | puts("*** You need to provide a sudoku string"); 165 | return EXIT_FAILURE; 166 | } 167 | 168 | // Check that the Sudoku string is 81-characters long 169 | if (strlen(argv[1]) != 81) { 170 | puts("*** The sudoku string must be 81 characters long"); 171 | return EXIT_FAILURE; 172 | } 173 | 174 | // Check that the Sudoku string consists of digits between 0 and 9 175 | for (int k = 0; k < 81; k++) { 176 | if (argv[1][k] < '0' || argv[1][k] > '9') { 177 | puts("*** The sudoku string must only contain 0 to 9 digits"); 178 | return EXIT_FAILURE; 179 | } 180 | } 181 | 182 | // Print the Sudoku string 183 | if (argc > 2) { 184 | printf("--- \"%s\"\n", argv[2]); 185 | } 186 | printf("--- \"%s\"\n", argv[1]); 187 | 188 | // Initialize the Sudoku arrays 189 | init(argv[1]); 190 | display(); 191 | 192 | // Remove the impossible numbers with an initial cleanup without 193 | // displaying any logging messages 194 | printf("sudoku: the initial grid contains %d solved cells\n", 195 | count_solved() 196 | ); 197 | silent = TRUE; 198 | cleanup(); 199 | silent = FALSE; 200 | printf("sudoku: after the initial cleanup, the grid" 201 | " contains %d solved cells\n", count_solved() 202 | ); 203 | display(); 204 | 205 | // Execute the strategies 206 | solve(); 207 | 208 | // Backtrack if necessary 209 | if (count_solved() < 81) { 210 | backtracking = TRUE; 211 | backtrack(0); 212 | backtracking = FALSE; 213 | } 214 | 215 | 216 | // Check that everything is OK 217 | if (inconsistent_grid()) { 218 | printf("*** The grid is inconsistent\n"); 219 | } 220 | 221 | printf("sudoku: the final grid contains %d solved cells\n", 222 | count_solved() 223 | ); 224 | display(); 225 | display_string(); 226 | printf("Strategies used %d:", n_strats_used); 227 | /* 228 | for (int k = 0; k < n_strats_used; k++) { 229 | printf(" %d", strats_used[k]); 230 | } 231 | printf("\n"); 232 | */ 233 | display_strats_in_clear(); 234 | 235 | #endif 236 | 237 | return EXIT_SUCCESS; 238 | } 239 | -------------------------------------------------------------------------------- /sources/Solver/unique.c: -------------------------------------------------------------------------------- 1 | /* unique.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "unique.h" 10 | #include "unique_unit.h" 11 | 12 | int unique() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- unique >>>\n"); 15 | #endif 16 | int result = FALSE; 17 | for (int k = 0; k < 9; k++) { 18 | result |= unique_unit("row", row[k]); 19 | result |= unique_unit("column", col[k]); 20 | result |= unique_unit("box", box[k]); 21 | } 22 | #ifdef LOG_IN_OUT 23 | printf("<<< unique ---\n"); 24 | #endif 25 | return result; 26 | } 27 | -------------------------------------------------------------------------------- /sources/Solver/unique.h: -------------------------------------------------------------------------------- 1 | /* unique.h 2 | * 3 | * Looks for unique candidates. 4 | * 5 | * Returns TRUE if it finds at least one unique number. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef UNIQUE 11 | #define UNIQUE 12 | 13 | int unique(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/unique_loop.c: -------------------------------------------------------------------------------- 1 | /* unique_loop.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "unique.h" 10 | #include "unique_loop.h" 11 | 12 | int unique_loop() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- unique_loop >>>\n"); 15 | #endif 16 | int found; 17 | int something = FALSE; 18 | do { 19 | found = unique(); 20 | something |= found; 21 | } while (found && !problem_found); 22 | #ifdef LOG_IN_OUT 23 | printf("<<< unique_loop ---\n"); 24 | #endif 25 | return something; 26 | } 27 | -------------------------------------------------------------------------------- /sources/Solver/unique_loop.h: -------------------------------------------------------------------------------- 1 | /* unique_loop.h 2 | * 3 | * Keeps looking for unique candidates until it doesn't find any. 4 | * 5 | * Returns TRUE if something is found. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef UNIQUE_LOOP 11 | #define UNIQUE_LOOP 12 | 13 | int unique_loop(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/unique_unit.c: -------------------------------------------------------------------------------- 1 | /* unique_unit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "remove_candidate.h" 11 | #include "unique_unit.h" 12 | 13 | int unique_unit(char *what, char unit[9][2]) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- unique_unit (%s) >>>\n", what); 16 | #endif 17 | int result = FALSE; 18 | int r[10]; for (int i = 0; i < 10; i++) { r[i] = -1; } 19 | int c[10]; 20 | for (int j1 = 0; j1 < 9; j1++) { 21 | int kR = unit[j1][0]; 22 | int kC = unit[j1][1]; 23 | char *elem = grid[kR][kC]; 24 | if (elem[0] > 1) { 25 | for (int i = 1; i <= 9; i++) { 26 | if (elem[i] != FALSE) { 27 | if (r[i] == -1) { 28 | r[i] = kR; 29 | c[i] = kC; 30 | } 31 | else { 32 | r[i] = -2; 33 | } 34 | } // if (elem[i].. 35 | } // for (int i.. 36 | } // if (elem[0].. 37 | } // for (int j1.. 38 | 39 | for (int i = 1; i <= 9 && !problem_found; i++) { 40 | if (r[i] >= 0) { 41 | result = TRUE; 42 | int kR = r[i]; 43 | int kC = c[i]; 44 | #ifdef LOG_UNIQUE 45 | if (!silent) { 46 | printf("unique_unit: %d in (%d,%d) is unique within the %s\n", 47 | i, kR, kC, what 48 | ); 49 | } 50 | #endif 51 | char *elem = grid[kR][kC]; 52 | for (int ii = 1; ii <= 9 && !problem_found; ii++) { 53 | if (elem[ii] != FALSE && i != ii) { 54 | remove_candidate("unique_unit", ii, kR, kC); 55 | } 56 | } 57 | if (!problem_found) cleanup_around(kR, kC); 58 | } // if (r[i].. 59 | } // for int i.. 60 | 61 | #ifdef LOG_IN_OUT 62 | printf("<<< unique_unit (%s) ---\n", what); 63 | #endif 64 | return result; 65 | } 66 | -------------------------------------------------------------------------------- /sources/Solver/unique_unit.h: -------------------------------------------------------------------------------- 1 | /* unique_unit.h 2 | * 3 | * Looks for unique candidates in a unit. 4 | * 5 | * Returns TRUE if it finds at least one unique number within the unit. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef UNIQUE_UNIT 11 | #define UNIQUE_UNIT 12 | 13 | int unique_unit(char*, char[9][2]); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/xy_chain.c: -------------------------------------------------------------------------------- 1 | /* xy_chain.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "pairs_find.h" 10 | #include "xy_chain.h" 11 | 12 | int xy_chain() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- xy_chain >>>\n"); 15 | #endif 16 | int result = pairs_find(DEF_XY_CHAIN); 17 | #ifdef LOG_IN_OUT 18 | printf("<<< xy_chain ---\n"); 19 | #endif 20 | return result; 21 | } 22 | -------------------------------------------------------------------------------- /sources/Solver/xy_chain.h: -------------------------------------------------------------------------------- 1 | /* xy_chain.h 2 | * 3 | * XY-chain strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef XY_CHAIN 11 | #define XY_CHAIN 12 | 13 | int xy_chain(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/xy_chain_digit.c: -------------------------------------------------------------------------------- 1 | /* xy_chain_digit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "pairs_data.h" 10 | #include "xy_chain_digit.h" 11 | #include "xy_chain_step.h" 12 | 13 | int xy_chain_digit(int i0) { 14 | #ifdef LOG_IN_OUT 15 | printf("--- xy_chain_digit (%d) >>>\n", i0); 16 | #endif 17 | 18 | int n_found = 0; 19 | for (int i1 = 1; i1 <= 9 && n_found == 0; i1++) { 20 | for (int i01 = 0; i01 < n_x_pairs[i0][i1] && n_found == 0; i01++) { 21 | 22 | // Flag x_pairs[i0][i1][ROW][i01] and x_pairs[i0][i1][COL][i01] 23 | // to avoid using the same cell more than once within the chain 24 | int kR01 = x_pairs[i0][i1][ROW][i01]; 25 | int kC01 = x_pairs[i0][i1][COL][i01]; 26 | x_pairs[i0][i1][ROW][i01] += 10; 27 | x_pairs[i1][i0][ROW][i01] += 10; 28 | 29 | // Start the chain. 30 | { 31 | int kB01 = x_pairs[i0][i1][BOX][i01]; 32 | chain_info_struct_t i0_info; 33 | chain_info_struct_t i1_info; 34 | i0_info.digit = i0; 35 | i1_info.digit = i1; 36 | i1_info.coords[ROW] = i0_info.coords[ROW] = kR01; 37 | i1_info.coords[COL] = i0_info.coords[COL] = kC01; 38 | i1_info.coords[BOX] = i0_info.coords[BOX] = kB01; 39 | i0_info.next = &i1_info; 40 | i1_info.next = NULL; 41 | n_found += xy_chain_step(&i0_info, 1); 42 | } 43 | 44 | // Restore the grid. 45 | x_pairs[i0][i1][ROW][i01] -= 10; 46 | x_pairs[i1][i0][ROW][i01] -= 10; 47 | } // for (int i01.. 48 | } // for (int i1 = 1.. 49 | 50 | #ifdef LOG_IN_OUT 51 | printf("<<< xy_chain_digit (%d) ---\n", i0); 52 | #endif 53 | return n_found > 0; 54 | } 55 | -------------------------------------------------------------------------------- /sources/Solver/xy_chain_digit.h: -------------------------------------------------------------------------------- 1 | /* xy_chain_digit.h 2 | * 3 | * XY-chain strategy applied to a single digit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef XY_CHAIN_DIGIT 11 | #define XY_CHAIN_DIGIT 12 | 13 | int xy_chain_digit(int); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/xy_chain_step.c: -------------------------------------------------------------------------------- 1 | /* xy_chain_step.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "intersection.h" 11 | #include "pairs_data.h" 12 | #include "remove_candidate.h" 13 | #include "xy_chain_step.h" 14 | 15 | #define MAX_DEPTH 8 16 | 17 | int chain_length; 18 | 19 | int xy_chain_step(chain_info_struct_p info, int depth) { 20 | #ifdef LOG_IN_OUT 21 | printf("--- xy_chain_step (%d) >>>\n", depth); 22 | #endif 23 | 24 | int n_found = 0; 25 | chain_info_struct_p next = info->next; 26 | chain_info_struct_p ix_info_p; 27 | do { 28 | ix_info_p = next; 29 | next = ix_info_p->next; 30 | } while (next != NULL); 31 | int i0 = info->digit; 32 | int ix = ix_info_p->digit; 33 | 34 | for (int iy = 1; iy <= 9 && n_found == 0; iy++) { 35 | for (int ixy = 0; ixy < n_x_pairs[ix][iy] && n_found == 0; ixy++) { 36 | 37 | int kRxy = x_pairs[ix][iy][ROW][ixy]; 38 | if (kRxy < 9) { 39 | int kCxy = x_pairs[ix][iy][COL][ixy]; 40 | int kBxy = x_pairs[ix][iy][BOX][ixy]; 41 | if ( kRxy == ix_info_p->coords[ROW] 42 | || kCxy == ix_info_p->coords[COL] 43 | || kBxy == ix_info_p->coords[BOX] 44 | ) { 45 | int found_something_this_time = FALSE; 46 | if (iy == i0 && depth > 2) { 47 | int printed = FALSE; 48 | void *mem_block = malloc(MAX_INTER_N * sizeof(struct rc_struct)); 49 | if (mem_block == NULL) { 50 | printf("*** xy_chain_step: malloc failure\n"); 51 | exit(EXIT_FAILURE); 52 | } 53 | int kR0 = info->coords[ROW]; 54 | int kC0 = info->coords[COL]; 55 | rc_p_t inter = intersection(kR0, kC0, kRxy, kCxy, mem_block); 56 | 57 | // Check whether intersecting cells contain i0 as candidates. 58 | rc_p_t p = inter; 59 | rc_p_t pp = p; 60 | while (p != NULL) { 61 | int kR = pp->row; 62 | int kC = pp->col; 63 | if (kR < 9 && grid[kR][kC][i0]) { 64 | found_something_this_time = TRUE; 65 | n_found++; 66 | #ifdef LOG_XY_CHAIN 67 | if (!printed && !silent) { 68 | printf("xy_chain_step: (%d,%d):%d", info->coords[ROW], 69 | info->coords[COL], info->digit 70 | ); 71 | next = info->next; 72 | printf("%d", next->digit); 73 | do { 74 | chain_info_struct_p next1 = next->next; 75 | if (next1 != NULL) { 76 | printf(" (%d,%d):%d%d", next1->coords[ROW], 77 | next1->coords[COL], next->digit, next1->digit 78 | ); 79 | } 80 | next = next1; 81 | } while (next != NULL); 82 | printf(" (%d,%d):%d%d\n", kRxy, kCxy, ix, iy); 83 | printf("xy_chain_step: intersection of (%d,%d) and (%d,%d):", 84 | kR0, kC0, kRxy, kCxy 85 | ); 86 | rc_p_t p = inter; 87 | rc_p_t pp = p; 88 | do { 89 | printf(" (%d,%d)", pp->row, pp->col); 90 | p = pp->next; 91 | pp = p; 92 | } while (p != NULL); 93 | printf("\n"); 94 | printed = TRUE; 95 | } // if (!printed.. 96 | #endif 97 | 98 | { // Scan the whole chain to determine its length 99 | // and update chain_length 100 | chain_info_struct_p info1 = info->next; 101 | chain_length = 1; 102 | do { 103 | chain_length++; 104 | chain_info_struct_p info2 = info1->next; 105 | info1 = info2; 106 | } while (info1 != NULL); 107 | } 108 | 109 | remove_candidate("xy_chain_step", i0, kR, kC); 110 | if (grid[kR][kC][0] == 1) { 111 | cleanup_around(kR, kC); 112 | } 113 | } // if (elem[i0].. 114 | p = pp->next; 115 | pp = p; 116 | } 117 | 118 | free(mem_block); 119 | } // if (iy.. 120 | 121 | if (!found_something_this_time) { 122 | 123 | // The chain is to be extended 124 | x_pairs[ix][iy][ROW][ixy] += 10; 125 | x_pairs[iy][ix][ROW][ixy] += 10; 126 | chain_info_struct_t iy_info; 127 | iy_info.digit = iy; 128 | iy_info.coords[ROW] = kRxy; 129 | iy_info.coords[COL] = kCxy; 130 | iy_info.coords[BOX] = kBxy; 131 | iy_info.next = NULL; 132 | ix_info_p->next = &iy_info; 133 | 134 | // Keep following the chain 135 | if (depth < MAX_DEPTH) { 136 | n_found += xy_chain_step(info, depth + 1); 137 | } 138 | 139 | // Clean up behind you 140 | ix_info_p->next = NULL; 141 | x_pairs[ix][iy][ROW][ixy] -= 10; 142 | x_pairs[iy][ix][ROW][ixy] -= 10; 143 | } // if (!found_something_this_time.. 144 | } // if (kRxy ==.. 145 | } // if (kRxy <.. 146 | } // for (int ixy.. 147 | } // for (int iy.. 148 | 149 | #ifdef LOG_IN_OUT 150 | printf("<<< xy_chain_step (%d) ---\n", depth); 151 | #endif 152 | return n_found; 153 | } 154 | -------------------------------------------------------------------------------- /sources/Solver/xy_chain_step.h: -------------------------------------------------------------------------------- 1 | /* xy_chain_step.h 2 | * 3 | * XY-chain strategy: moving along the chain till the end. 4 | * 5 | * Returns the number of candidates removed. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef XY_CHAIN_STEP 11 | #define XY_CHAIN_STEP 12 | 13 | typedef struct chain_info_struct *chain_info_struct_p; 14 | typedef struct chain_info_struct { 15 | int digit; 16 | int coords[3]; 17 | chain_info_struct_p next; 18 | } chain_info_struct_t; 19 | 20 | extern int chain_length; 21 | 22 | int xy_chain_step(chain_info_struct_p, int); 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /sources/Solver/y_wing.c: -------------------------------------------------------------------------------- 1 | /* y_wing.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "def.h" 9 | #include "pairs_find.h" 10 | #include "y_wing.h" 11 | 12 | int y_wing() { 13 | #ifdef LOG_IN_OUT 14 | printf("--- y_wing >>>\n"); 15 | #endif 16 | int result = pairs_find(DEF_Y_WING); 17 | #ifdef LOG_IN_OUT 18 | printf("<<< y_wing ---\n"); 19 | #endif 20 | return result; 21 | } 22 | -------------------------------------------------------------------------------- /sources/Solver/y_wing.h: -------------------------------------------------------------------------------- 1 | /* y_wing.h 2 | * 3 | * Y-wing strategy. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef Y_WING 11 | #define Y_WING 12 | 13 | int y_wing(void); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /sources/Solver/y_wing_digit.c: -------------------------------------------------------------------------------- 1 | /* y_wing_digit.c 2 | * 3 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 4 | * 5 | */ 6 | #include 7 | #include 8 | #include "cleanup_around.h" 9 | #include "def.h" 10 | #include "intersection.h" 11 | #include "pairs_data.h" 12 | #include "remove_candidate.h" 13 | #include "y_wing_digit.h" 14 | 15 | int y_wing_digit(int i0) { 16 | #ifdef LOG_IN_OUT 17 | printf("--- y_wing_digit (%d) >>>\n", i0); 18 | #endif 19 | 20 | #define A 0 21 | #define B 1 22 | #define C 2 23 | 24 | int success = FALSE; 25 | 26 | // +-------+ 27 | // | i0+i1 | 28 | // +-------+-------+ 29 | // | i1+i2 | i2+i0 | 30 | // +-------+-------+ 31 | int coords[3][3]; // [cell][unit] 32 | for (int i1 = 1; i1 <= 9; i1++) { 33 | for (int i1k = 0; i1k < n_x_pairs[i0][i1]; i1k++) { 34 | 35 | // If we arrive here, i0 is paired with i1, and 36 | // i1k goes through all the pairs of i0 with i1 37 | coords[A][ROW] = x_pairs[i0][i1][ROW][i1k]; 38 | coords[A][COL] = x_pairs[i0][i1][COL][i1k]; 39 | coords[A][BOX] = x_pairs[i0][i1][BOX][i1k]; 40 | for (int i2 = 1; i2 <= 9; i2++) { 41 | if (i2 != i0) { 42 | for (int i2k = 0; i2k < n_x_pairs[i1][i2]; i2k++) { 43 | 44 | // If we arrive here, i1 is paired with i2, and 45 | // i2k goes through all the pairs of i1 with i2 46 | coords[B][ROW] = x_pairs[i1][i2][ROW][i2k]; 47 | coords[B][COL] = x_pairs[i1][i2][COL][i2k]; 48 | coords[B][BOX] = x_pairs[i1][i2][BOX][i2k]; 49 | 50 | if (i2 > i1 && 51 | ( coords[A][ROW] == coords[B][ROW] 52 | || coords[A][COL] == coords[B][COL] 53 | || coords[A][BOX] == coords[B][BOX] 54 | ) 55 | ) { 56 | for (int i3k = 0; i3k < n_x_pairs[i2][i0]; i3k++) { 57 | 58 | // If we arrive here, i2 is paired with i0, and 59 | // i3k goes through all the pairs of i2 made with i0 60 | coords[C][ROW] = x_pairs[i2][i0][ROW][i3k]; 61 | coords[C][COL] = x_pairs[i2][i0][COL][i3k]; 62 | coords[C][BOX] = x_pairs[i2][i0][BOX][i3k]; 63 | 64 | if ( coords[C][ROW] != coords[A][ROW] 65 | && coords[C][COL] != coords[A][COL] 66 | && coords[C][BOX] != coords[A][BOX] 67 | && ( coords[C][ROW] == coords[B][ROW] 68 | || coords[C][COL] == coords[B][COL] 69 | || coords[C][BOX] == coords[B][BOX] 70 | ) 71 | ) { 72 | int printed = FALSE; 73 | void *mem_block = malloc(MAX_INTER_N*sizeof(struct rc_struct)); 74 | if (mem_block == NULL) { 75 | printf("*** y_wing_digit (%d): malloc failure\n", i0); 76 | exit(EXIT_FAILURE); 77 | } 78 | rc_p_t inter = intersection(coords[A][ROW], coords[A][COL], 79 | coords[C][ROW], coords[C][COL], mem_block 80 | ); 81 | rc_p_t p = inter; 82 | rc_p_t pp = p; 83 | while (p != NULL) { 84 | int kR = pp->row; 85 | int kC = pp->col; 86 | char *elem = grid[kR][kC]; 87 | if (elem[i0]) { 88 | success = TRUE; 89 | #ifdef LOG_Y_WING 90 | if (!printed && !silent) { 91 | printf("y_wing_digit: (%d,%d):%d%d (%d,%d):%d%d" 92 | " (%d,%d):%d%d\n", 93 | coords[A][ROW], coords[A][COL], i0, i1, 94 | coords[B][ROW], coords[B][COL], i1, i2, 95 | coords[C][ROW], coords[C][COL], i2, i0 96 | ); 97 | printf("y_wing_digit: intersection of (%d,%d) and" 98 | " (%d,%d):", coords[A][ROW], coords[A][COL], 99 | coords[C][ROW], coords[C][COL] 100 | ); 101 | rc_p_t p1 = inter; 102 | rc_p_t pp1 = p1; 103 | do { 104 | if ( pp1->row != coords[B][ROW] 105 | || pp1->col != coords[B][COL] 106 | ) { 107 | printf(" (%d,%d)", pp1->row, pp1->col); 108 | } 109 | p1 = pp1->next; 110 | pp1 = p1; 111 | } while (p1 != NULL); 112 | printf("\n"); 113 | printed = TRUE; 114 | } // if (!printed.. 115 | #endif 116 | remove_candidate("y_wing_digit", i0, kR, kC); 117 | if (grid[kR][kC][0] == 1) { 118 | cleanup_around(kR, kC); 119 | } 120 | } // if (elem[i0].. 121 | p = pp->next; 122 | pp = p; 123 | } 124 | 125 | free(mem_block); 126 | } // if (coords[C][ROW].. 127 | } // for (int i3k.. 128 | } // if (i2 > i1.. 129 | } // for (int i2k.. 130 | } // if (i2 != i0.. 131 | } // for (int i2.. 132 | } // for (int i1k.. 133 | } // for (int i1.. 134 | 135 | #ifdef LOG_IN_OUT 136 | printf("<<< y_wing_digit (%d) ---\n", i0); 137 | #endif 138 | return success; 139 | } 140 | -------------------------------------------------------------------------------- /sources/Solver/y_wing_digit.h: -------------------------------------------------------------------------------- 1 | /* y_wing_digit.h 2 | * 3 | * Y-wing strategy applied to a single digit. 4 | * 5 | * Returns TRUE if it removes at least one candidate. 6 | * 7 | * Copyright (C) 2015 Giulio Zambon - http://zambon.com.au/ 8 | * 9 | */ 10 | #ifndef Y_WING_DIGIT 11 | #define Y_WING_DIGIT 12 | 13 | int y_wing_digit(int); 14 | 15 | #endif 16 | --------------------------------------------------------------------------------