[2] | 1 | %
|
---|
| 2 | % verslag.tex 9.2.2006
|
---|
| 3 | % Sudoku verslag
|
---|
| 4 | %
|
---|
| 5 |
|
---|
| 6 | \documentclass[12pt]{article}
|
---|
| 7 |
|
---|
| 8 | \frenchspacing
|
---|
| 9 | \usepackage[english]{babel}
|
---|
| 10 | \selectlanguage{english}
|
---|
| 11 | \usepackage{graphicx}
|
---|
| 12 | \usepackage{wrapfig}
|
---|
| 13 |
|
---|
| 14 | \author{Rick van der Zwet, Leiden University \\ Leiden Institute of Advanced Computer Science}
|
---|
| 15 | \title{Creating and solving Sudoku's}
|
---|
| 16 |
|
---|
| 17 | \begin{document}
|
---|
| 18 | \maketitle
|
---|
| 19 | \section{Introduction}
|
---|
| 20 | \subsection{History}
|
---|
| 21 | \begin{quote}
|
---|
| 22 | The name Sudoku is the Japanese abbreviation of a longer phrase, ''suuji wa dokushin ni kagiru'' meaning ''the digits must remain single''; it is a trademark of puzzle publisher Nikoli Co. Ltd in Japan.
|
---|
| 23 |
|
---|
| 24 | The numerals in Sudoku puzzles are used for convenience; arithmetic relationships between numerals are absolutely irrelevant. Any set of distinct symbols will do; letters, shapes, or colors may be used without altering the rules (Penny Press' Scramblets and Knight Features Syndicate's Sudoku Word both use letters). Dell Magazines, the puzzle's originator, has been using numerals for Number Place in its magazines since they first published it in 1979. Numerals are used throughout this article.
|
---|
| 25 |
|
---|
| 26 | The attraction of the puzzle is that the completion rules are simple, yet the line of reasoning required to reach the completion may be complex. Sudoku is recommended by some teachers as an exercise in logical reasoning. The level of difficulty of the puzzles can be selected to suit the audience. The puzzles are often available free from published sources and also may be custom-generated using software.\cite{wikipedia}
|
---|
| 27 | \end{quote}
|
---|
| 28 |
|
---|
| 29 | \newpage
|
---|
| 30 | \subsection{Game-play}
|
---|
| 31 | \begin{wrapfigure}{r}{50mm}
|
---|
| 32 | \includegraphics[scale=0.5]{sudoku.eps}
|
---|
| 33 | \caption{Sample sudoku}
|
---|
| 34 | \end{wrapfigure}
|
---|
| 35 | The puzzle is most frequently a 9Ã9 grid, made up of 3Ã3 sub-grids called ''regions'' (other terms include ''boxes'', ''blocks'', and the like when referring to the standard variation; even ''quadrant'' is sometimes used, despite this being an inaccurate term for a 9Ã9 grid). Some cells already contain numerals, known as ''givens'' (or sometimes as ''clues''). The goal is to fill in the empty cells, one numeral in each, so that each column, row, and region contains the numerals 1â9 exactly once. Each numeral in the solution therefore occurs only once in each of three ''directions'' or ''scopes'', hence the ''single numbers'' implied by the puzzle's name.\cite{wikipedia}
|
---|
| 36 |
|
---|
| 37 | \section{Problem}
|
---|
| 38 |
|
---|
| 39 | Not every combination of a board, is going to be successful and there is no algorithm who can predict whether a generated board is valid without completely solving the puzzle. So there has to be some other way to generate valid puzzles. First, there need to be a perfect solver written to test whether a puzzle has got only one solution.
|
---|
| 40 | The second way to generate a valid puzzle is by creating a completely solved valid puzzle and delete a few spots, by checking if the puzzle still has got 1 unique solution. We are able to generate Sudoku's too.
|
---|
| 41 |
|
---|
| 42 | \newpage
|
---|
| 43 | \section{Solution finding theories}
|
---|
| 44 |
|
---|
| 45 | There are currently 3 solutions know (by me) about solving the Soduku somehow.
|
---|
| 46 |
|
---|
| 47 | \subsection{Marking up}
|
---|
| 48 | By deleting the non-available spots at every location, the remaining possibilities will become clear, you will notice at certain points only one option will be left, so this will be the number to be filled in. As can be showed by figure \ref{marking_up}.
|
---|
| 49 |
|
---|
| 50 | \begin{figure}[!ht]
|
---|
| 51 | \begin{center}
|
---|
| 52 | \includegraphics{marking_up.eps}
|
---|
| 53 | \end{center}
|
---|
| 54 | \caption{Candidates for each empty cell have been entered. Some cells have only one candidate once obvious invalids have been excluded. Also, some mark with dots instead of numbers, simply using the position of the dot within the cell to distinguish them.\cite{wikipedia}}
|
---|
| 55 | \label{marking_up}
|
---|
| 56 | \end{figure}
|
---|
| 57 |
|
---|
| 58 |
|
---|
| 59 | \newpage
|
---|
| 60 | \subsection{Scanning}
|
---|
| 61 | Scanning will be a easy solution too to be used by humans, computers however need slight more code to accomplish the same result. With scanning you can "force" certain numbers into their spot. See figure \ref{scanning} for a example.
|
---|
| 62 |
|
---|
| 63 | \begin{figure}[!ht]
|
---|
| 64 | \begin{center}
|
---|
| 65 | \includegraphics{scanning.eps}
|
---|
| 66 | \end{center}
|
---|
| 67 | \caption{The 3Ã3 region in the top-left corner. The solver can eliminate all of the empty cells in the top-right corner which cannot contain a 5. This leaves only one possible cell (highlighted in green).\cite{wikipedia}}
|
---|
| 68 | \label{scanning}
|
---|
| 69 | \end{figure}
|
---|
| 70 |
|
---|
| 71 | \newpage
|
---|
| 72 | \subsection{Analysis}
|
---|
| 73 | Analysis will be even more complex. It can consist many methods to logically gain a solution. There is one pointed out (and implemented). Let's pretend we have a row in which are 3 spot's still to be filled.
|
---|
| 74 |
|
---|
| 75 | Options to spot A: 1, 2 ,3
|
---|
| 76 | Options to spot B: 2, 3
|
---|
| 77 | Options to spot C: 2, 3
|
---|
| 78 |
|
---|
| 79 | B and C together will use number 2 and 3, so A has to be 1. It's just an other ''simple solution'', but implementing it it's a bit hard.
|
---|
| 80 | \begin{figure}[!ht]
|
---|
| 81 | \begin{center}
|
---|
| 82 | \includegraphics{cplusplus.eps}
|
---|
| 83 | \end{center}
|
---|
| 84 | \label{cplusplus}
|
---|
| 85 | \end{figure}
|
---|
| 86 |
|
---|
| 87 | \section{Implementation}
|
---|
| 88 |
|
---|
| 89 | The solver and create program are both written in C$\stackrel{++}{}$. It uses a 2d array to implement the sudoku board and a 3d array to implement the current available choices at the board.
|
---|
| 90 |
|
---|
| 91 | \newpage
|
---|
| 92 | \section{Creating Sudoku's}
|
---|
| 93 |
|
---|
| 94 | There are 3 main ways to create Sudoku's
|
---|
| 95 | \begin{enumerate}
|
---|
| 96 | \item Randomizing stupid, just push for example 17 random numbers inside the sudoku and hope none of them will interference.
|
---|
| 97 | \item Randomizing smart, push for example 17 random numbers inside the sudoku and be sure none of them will be a violation of the structure.
|
---|
| 98 | \item ''Cleaning'' first generate a complete sudoku. Then get your wiper\/cleaner and delete some numbers. This solution is a bit difficult and will use a lot of math to generate a full puzzle and you are not sure if the puzzle has got only one solution.
|
---|
| 99 | \end{enumerate}
|
---|
| 100 |
|
---|
| 101 | \section{Experiments}
|
---|
| 102 |
|
---|
| 103 | \subsection{Solver}
|
---|
| 104 | First we will test the solver. The website of G.~Royle\cite{gordon} has got plenty solvable 17 Sudoku's. A few of them are placed at Appendix C. There is a small shell script written (Appendix B) to test the result. By trying to solve 1000 puzzles, the program managed to complete 547, the other puzzles requires some more logic implemented to solve them.
|
---|
| 105 |
|
---|
| 106 |
|
---|
| 107 | \subsection{Generator}
|
---|
| 108 | The generator will generate of puzzle of class 2 (Random and not very stupid), the solver will try to fix this puzzle. No checks for unique solutions will be made. Table below will point out the results by running the test 10000 times.
|
---|
| 109 |
|
---|
| 110 | \begin{center}
|
---|
| 111 | \begin{tabular}{l|l|l}
|
---|
| 112 | Percent sudoku filled initially & Solutions found 1st round & Solutions found 2nd round\\
|
---|
| 113 | \hline
|
---|
| 114 | 10\% &0 &0\\
|
---|
| 115 | 20\% &0 &0\\
|
---|
| 116 | 30\% &160 &0\\
|
---|
| 117 | 40\% &0 &0\\
|
---|
| 118 | 50\% &0 &0\\
|
---|
| 119 | \end{tabular}
|
---|
| 120 | \end{center}
|
---|
| 121 |
|
---|
| 122 |
|
---|
| 123 | \section{Conclusion}
|
---|
| 124 |
|
---|
| 125 | The solver ain't good enough yet, he should fix every puzzle and not 50\%, need to program some additional logic. The creator isn't very good either, only 30\% will generate some solvable puzzles, It properly have something to do with the very bad random generator, the random seed if filled with the Unix time in which in 100 occurred process will be the same. The creator needs method 3 to be implemented to validate this assumption or a rewrite of the code.
|
---|
| 126 |
|
---|
| 127 | \begin{thebibliography}{1}
|
---|
| 128 | \bibitem{wikipedia}
|
---|
| 129 | Wikipedia Foundation Inc,
|
---|
| 130 | http://en.wikipedia.org/wiki/Sudoku
|
---|
| 131 | \bibitem{gordon}
|
---|
| 132 | G.~Royle, Minimum Sudoku
|
---|
| 133 | http://www.csse.uwa.edu.au/\~{}Gordon/sudokumin.php
|
---|
| 134 | \end{thebibliography}
|
---|
| 135 |
|
---|
| 136 | \newpage
|
---|
| 137 | \section*{Appendix A: sudoku.cpp}
|
---|
| 138 | The following C$\stackrel{++}{}$ has been used to solve the puzzles
|
---|
| 139 |
|
---|
| 140 | \begin{small}
|
---|
| 141 | \begin{verbatim}
|
---|
| 142 |
|
---|
| 143 | /* file: sudoku.c
|
---|
| 144 | * author: rick van der Zwet 0433373, 2006
|
---|
| 145 | * University Leiden, LIACS
|
---|
| 146 | */
|
---|
| 147 |
|
---|
| 148 | #include <stdio.h>
|
---|
| 149 | #include <stdlib.h>
|
---|
| 150 | #include <string.h>
|
---|
| 151 | #include <time.h>
|
---|
| 152 | #include <signal.h>
|
---|
| 153 |
|
---|
| 154 | #define MAX_XYZ 9
|
---|
| 155 | #define EMPTY_SPOT '_'
|
---|
| 156 |
|
---|
| 157 |
|
---|
| 158 | #define bold "[1m"
|
---|
| 159 | #define normal "[0m"
|
---|
| 160 |
|
---|
| 161 | #define DEBUGPLACE stderr
|
---|
| 162 | const char esc = 27; /* escape character */
|
---|
| 163 |
|
---|
| 164 |
|
---|
| 165 | int debug(const int level = 0)
|
---|
| 166 | {
|
---|
| 167 | #if DEBUG
|
---|
| 168 | if (level <= DEBUG)
|
---|
| 169 | {
|
---|
| 170 | return(1);
|
---|
| 171 | }
|
---|
| 172 | else
|
---|
| 173 | {
|
---|
| 174 | return(0);
|
---|
| 175 | }
|
---|
| 176 | #else
|
---|
| 177 | return(0);
|
---|
| 178 | #endif
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | class Sudoku {
|
---|
| 182 | public:
|
---|
| 183 | Sudoku();
|
---|
| 184 | void printNice(const int boldRow = -1, const int boldCol = -1, const char emptcolSpace = EMPTY_SPOT);
|
---|
| 185 | void printRaw();
|
---|
| 186 | void printPossible();
|
---|
| 187 | void printPossibleAtNumber(const int row, const int col);
|
---|
| 188 | void reset();
|
---|
| 189 | int randomNumbers(const double chance);
|
---|
| 190 | int fromFile(FILE *handle);
|
---|
| 191 | int insert(const int row, const int col, const int number);
|
---|
| 192 | int solutionFinder();
|
---|
| 193 | private:
|
---|
| 194 | int _sudoku[MAX_XYZ][MAX_XYZ];
|
---|
| 195 | bool _possible[MAX_XYZ][MAX_XYZ][MAX_XYZ];
|
---|
| 196 | int _numbersFilled;
|
---|
| 197 | void _updatePossibleList(const int row, const int col, const int number);
|
---|
| 198 | bool _solution1(int &row, int &col, int &number);
|
---|
| 199 | bool _solution2(int &row, int &col, int &number);
|
---|
| 200 | bool _solution3a(int &row, int &col, int &number);
|
---|
| 201 | bool _solution3b(int &row, int &col, int &number);
|
---|
| 202 | };
|
---|
| 203 |
|
---|
| 204 | Sudoku::Sudoku()
|
---|
| 205 | {
|
---|
| 206 | reset();
|
---|
| 207 | }
|
---|
| 208 |
|
---|
| 209 |
|
---|
| 210 | void Sudoku::printRaw()
|
---|
| 211 | {
|
---|
| 212 | int row,col;
|
---|
| 213 | for (row = 0; row < MAX_XYZ ; row++)
|
---|
| 214 | {
|
---|
| 215 | for (col = 0; col < MAX_XYZ; col++)
|
---|
| 216 | {
|
---|
| 217 | printf("%i ", _sudoku[row][col]);
|
---|
| 218 | }
|
---|
| 219 | printf("\n");
|
---|
| 220 | }
|
---|
| 221 | }
|
---|
| 222 | void Sudoku::printNice(const int boldRow, const int boldCol,
|
---|
| 223 | const char emptcolSpace)
|
---|
| 224 | {
|
---|
| 225 | int row,col;
|
---|
| 226 | int tmpRow;
|
---|
| 227 | const int maxRow = (MAX_XYZ + (MAX_XYZ / 3)) * 2 + 1;
|
---|
| 228 | for(tmpRow = 0; tmpRow < maxRow; tmpRow++)
|
---|
| 229 | {
|
---|
| 230 | if ((tmpRow%8) == 0) { printf("+"); }else {printf("-");}
|
---|
| 231 | }
|
---|
| 232 | printf("\n");
|
---|
| 233 | for (row = 0; row < MAX_XYZ ; row++)
|
---|
| 234 | {
|
---|
| 235 | printf("| ");
|
---|
| 236 | for (col = 0; col < MAX_XYZ; col++)
|
---|
| 237 | {
|
---|
| 238 | if ( _sudoku[row][col] == 0)
|
---|
| 239 | {
|
---|
| 240 | printf("%c ",emptcolSpace);
|
---|
| 241 | }
|
---|
| 242 | else
|
---|
| 243 | {
|
---|
| 244 | if (row == boldRow && col == boldCol)
|
---|
| 245 | {
|
---|
| 246 | printf("%c%s%i%c%s ",esc, bold, _sudoku[row][col],
|
---|
| 247 | esc, normal);
|
---|
| 248 | }
|
---|
| 249 | else
|
---|
| 250 | {
|
---|
| 251 | printf("%i ", _sudoku[row][col]);
|
---|
| 252 | }
|
---|
| 253 | }
|
---|
| 254 | if ( ((col - 2) % 3) == 0 )
|
---|
| 255 | {
|
---|
| 256 | printf("| ");
|
---|
| 257 | }
|
---|
| 258 | }
|
---|
| 259 | printf("\n");
|
---|
| 260 | if ( ((row - 2) % 3) == 0 )
|
---|
| 261 | {
|
---|
| 262 | for(tmpRow = 0; tmpRow < maxRow; tmpRow++)
|
---|
| 263 | {
|
---|
| 264 | if ((tmpRow%8) == 0)
|
---|
| 265 | {
|
---|
| 266 | printf("+");
|
---|
| 267 | }
|
---|
| 268 | else
|
---|
| 269 | {
|
---|
| 270 | printf("-");
|
---|
| 271 | }
|
---|
| 272 | }
|
---|
| 273 | printf("\n");
|
---|
| 274 | }
|
---|
| 275 | }
|
---|
| 276 | printf("\n\n");
|
---|
| 277 | }
|
---|
| 278 |
|
---|
| 279 | void Sudoku::printPossibleAtNumber(const int row, const int col)
|
---|
| 280 | {
|
---|
| 281 | if (debug(3))
|
---|
| 282 | {
|
---|
| 283 | int tmpPossible;
|
---|
| 284 | fprintf(DEBUGPLACE, "Possible at [%i,%i]: ", row, col);
|
---|
| 285 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 286 | {
|
---|
| 287 | if (_possible[row][col][tmpPossible] == true)
|
---|
| 288 | {
|
---|
| 289 | fprintf(DEBUGPLACE,"%i ", tmpPossible + 1);
|
---|
| 290 | }
|
---|
| 291 | }
|
---|
| 292 | fprintf(DEBUGPLACE, "\n");
|
---|
| 293 | }
|
---|
| 294 | }
|
---|
| 295 |
|
---|
| 296 | void Sudoku::printPossible()
|
---|
| 297 | {
|
---|
| 298 | int row,col;
|
---|
| 299 | if (debug(3))
|
---|
| 300 | {
|
---|
| 301 | for (row = 0; row < MAX_XYZ ; row++)
|
---|
| 302 | {
|
---|
| 303 | for (col = 0; col < MAX_XYZ; col++)
|
---|
| 304 | {
|
---|
| 305 | if(_sudoku[row][col] == 0)
|
---|
| 306 | {
|
---|
| 307 | printPossibleAtNumber(row,col);
|
---|
| 308 | }
|
---|
| 309 | }
|
---|
| 310 | }
|
---|
| 311 | }
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 |
|
---|
| 315 | void Sudoku::_updatePossibleList(const int row, const int col, const int number)
|
---|
| 316 | {
|
---|
| 317 | int tmpRow;
|
---|
| 318 | int tmpCol;
|
---|
| 319 | int blockRow;
|
---|
| 320 | int blockCol;
|
---|
| 321 | int c;
|
---|
| 322 |
|
---|
| 323 |
|
---|
| 324 | /* Row and Col and Number own */
|
---|
| 325 | for (c = 0; c < MAX_XYZ; c++)
|
---|
| 326 | {
|
---|
| 327 | _possible[row][col][c] = false;
|
---|
| 328 | _possible[row][c][number - 1] = false;
|
---|
| 329 | _possible[c][col][number - 1] = false;
|
---|
| 330 | }
|
---|
| 331 |
|
---|
| 332 | /* Block */
|
---|
| 333 | tmpRow = row - (row % (MAX_XYZ / 3));
|
---|
| 334 | tmpCol = col - (col % (MAX_XYZ / 3));
|
---|
| 335 | for (blockRow = tmpRow; blockRow < (tmpRow + 3); blockRow++)
|
---|
| 336 | {
|
---|
| 337 | for (blockCol = tmpCol; blockCol < (tmpCol + 3); blockCol++)
|
---|
| 338 | {
|
---|
| 339 | _possible[blockRow][blockCol][number - 1] = false;
|
---|
| 340 | }
|
---|
| 341 | }
|
---|
| 342 | }
|
---|
| 343 |
|
---|
| 344 | int Sudoku::insert(const int row, const int col, const int number)
|
---|
| 345 | {
|
---|
| 346 | if (debug(1)) { fprintf(DEBUGPLACE, "Will insert %i at [%i,%i]: %i\n",
|
---|
| 347 | number, row, col, _possible[row][col][number - 1]); }
|
---|
| 348 |
|
---|
| 349 | if (_possible[row][col][number - 1] == true)
|
---|
| 350 | {
|
---|
| 351 | _updatePossibleList(row, col, number);
|
---|
| 352 | _sudoku[row][col] = number;
|
---|
| 353 | _numbersFilled++;
|
---|
| 354 | return(0);
|
---|
| 355 | }
|
---|
| 356 | else
|
---|
| 357 | {
|
---|
| 358 | return(1);
|
---|
| 359 | }
|
---|
| 360 | }
|
---|
| 361 |
|
---|
| 362 | int Sudoku::randomNumbers(const double chance)
|
---|
| 363 | {
|
---|
| 364 | if (debug(1)) { fprintf(DEBUGPLACE, "Running createsudoku\n"); }
|
---|
| 365 | int row;
|
---|
| 366 | int col;
|
---|
| 367 | int c;
|
---|
| 368 | int randomnumber;
|
---|
| 369 | int numberdone[MAX_XYZ];
|
---|
| 370 | int numbertried;
|
---|
| 371 |
|
---|
| 372 | srand( (unsigned)time( NULL ) );
|
---|
| 373 |
|
---|
| 374 | for (row = 0; row < MAX_XYZ; row++)
|
---|
| 375 | {
|
---|
| 376 | for (col = 0; col < MAX_XYZ; col++)
|
---|
| 377 | {
|
---|
| 378 | if (rand() < (RAND_MAX * (chance / 100)))
|
---|
| 379 | {
|
---|
| 380 | numbertried = 0;
|
---|
| 381 | for (c = 0; c < MAX_XYZ; c++ ) { numberdone[c] = 0; }
|
---|
| 382 | do
|
---|
| 383 | {
|
---|
| 384 | if (numbertried == 9)
|
---|
| 385 | {
|
---|
| 386 | return(1);
|
---|
| 387 | }
|
---|
| 388 | else
|
---|
| 389 | {
|
---|
| 390 | numbertried++;
|
---|
| 391 | }
|
---|
| 392 | do
|
---|
| 393 | {
|
---|
| 394 | randomnumber = 1 + (int) ( (double)MAX_XYZ * (random() / (RAND_MAX + 1.0)));
|
---|
| 395 | } while (numberdone[randomnumber - 1] == 1);
|
---|
| 396 | numberdone[randomnumber - 1] = 1;
|
---|
| 397 | if (debug(2)) { fprintf(DEBUGPLACE, "Random check number %i at [%i,%i]\n",
|
---|
| 398 | randomnumber, row,col); }
|
---|
| 399 | } while ( insert(row, col, randomnumber) == 1);
|
---|
| 400 | }
|
---|
| 401 | else
|
---|
| 402 | {
|
---|
| 403 | _sudoku[row][col] = 0;
|
---|
| 404 | }
|
---|
| 405 | }
|
---|
| 406 | }
|
---|
| 407 | return(0);
|
---|
| 408 | }
|
---|
| 409 |
|
---|
| 410 | void Sudoku::reset()
|
---|
| 411 | {
|
---|
| 412 | //temp counters
|
---|
| 413 | int row;
|
---|
| 414 | int col;
|
---|
| 415 | int z;
|
---|
| 416 |
|
---|
| 417 | _numbersFilled = 0;
|
---|
| 418 | for (row = 0; row < MAX_XYZ; row++)
|
---|
| 419 | {
|
---|
| 420 | for (col = 0; col < MAX_XYZ; col++)
|
---|
| 421 | {
|
---|
| 422 | _sudoku[row][col] = 0;
|
---|
| 423 | for (z = 0; z < MAX_XYZ; z++)
|
---|
| 424 | {
|
---|
| 425 | _possible[row][col][z] = true;
|
---|
| 426 | }
|
---|
| 427 | }
|
---|
| 428 | }
|
---|
| 429 | }
|
---|
| 430 |
|
---|
| 431 | int Sudoku::fromFile(FILE *handle)
|
---|
| 432 | {
|
---|
| 433 | int row;
|
---|
| 434 | int col;
|
---|
| 435 | int tmpInt;
|
---|
| 436 | for (row = 0; row < MAX_XYZ; row++)
|
---|
| 437 | {
|
---|
| 438 | for (col = 0; col < MAX_XYZ; col++)
|
---|
| 439 | {
|
---|
| 440 | fscanf(handle, "%1i", &tmpInt);
|
---|
| 441 | if (tmpInt != 0)
|
---|
| 442 | {
|
---|
| 443 | insert(row, col, tmpInt);
|
---|
| 444 | }
|
---|
| 445 | }
|
---|
| 446 | }
|
---|
| 447 | fclose(handle);
|
---|
| 448 | return(0);
|
---|
| 449 | }
|
---|
| 450 |
|
---|
| 451 | /* Use Basic technique of finding places with just one number left to place */
|
---|
| 452 | bool Sudoku::_solution1(int &row, int &col, int &number)
|
---|
| 453 | {
|
---|
| 454 | #define NOTHING_FOUND 0
|
---|
| 455 | #define ONE_FOUND 1
|
---|
| 456 | #define MORE_THEN_ONE_FOUND 2
|
---|
| 457 | int tmpRow;
|
---|
| 458 | int tmpCol;
|
---|
| 459 | int tmpPossible;
|
---|
| 460 | int tmpNumber;
|
---|
| 461 | int searchState;
|
---|
| 462 |
|
---|
| 463 | for (tmpRow = 0; tmpRow < MAX_XYZ; tmpRow++)
|
---|
| 464 | {
|
---|
| 465 | for (tmpCol = 0; tmpCol < MAX_XYZ; tmpCol++)
|
---|
| 466 | {
|
---|
| 467 | if (_sudoku[tmpRow][tmpCol] == 0)
|
---|
| 468 | {
|
---|
| 469 | tmpNumber = 0;
|
---|
| 470 | searchState = NOTHING_FOUND;
|
---|
| 471 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 472 | {
|
---|
| 473 | if (_possible[tmpRow][tmpCol][tmpPossible] == true &&
|
---|
| 474 | searchState == ONE_FOUND)
|
---|
| 475 | {
|
---|
| 476 | searchState = MORE_THEN_ONE_FOUND;
|
---|
| 477 | break;
|
---|
| 478 | }
|
---|
| 479 | else if (_possible[tmpRow][tmpCol][tmpPossible] == true &&
|
---|
| 480 | searchState == NOTHING_FOUND)
|
---|
| 481 | {
|
---|
| 482 | tmpNumber = tmpPossible + 1;
|
---|
| 483 | searchState = ONE_FOUND;
|
---|
| 484 | }
|
---|
| 485 | }
|
---|
| 486 | if (searchState == ONE_FOUND)
|
---|
| 487 | {
|
---|
| 488 | row = tmpRow;
|
---|
| 489 | col = tmpCol;
|
---|
| 490 | number = tmpNumber;
|
---|
| 491 | return(true);
|
---|
| 492 | }
|
---|
| 493 | }
|
---|
| 494 | }
|
---|
| 495 | }
|
---|
| 496 |
|
---|
| 497 | return(false);
|
---|
| 498 | }
|
---|
| 499 |
|
---|
| 500 | /* Check if number can onlcol be placed somewhere, if not able to place anywhere else */
|
---|
| 501 | /* FIXME: Should be more modular, to reduce line length and readabilitcol */
|
---|
| 502 | /* FIXME: find nice solution for goto's */
|
---|
| 503 | bool Sudoku::_solution2(int &row, int &col, int &number)
|
---|
| 504 | {
|
---|
| 505 | int tmpRow;
|
---|
| 506 | int tmpCol;
|
---|
| 507 | int tmpPossible;
|
---|
| 508 | int tmpNumber;
|
---|
| 509 |
|
---|
| 510 | int blockRow;
|
---|
| 511 | int blockTmpRow;
|
---|
| 512 | int blockCol;
|
---|
| 513 | int blockTmpCol;
|
---|
| 514 | bool result;
|
---|
| 515 |
|
---|
| 516 | for (tmpRow = 0; tmpRow < MAX_XYZ; tmpRow++)
|
---|
| 517 | {
|
---|
| 518 | for (tmpCol = 0; tmpCol < MAX_XYZ; tmpCol++)
|
---|
| 519 | {
|
---|
| 520 | if (_sudoku[tmpRow][tmpCol] == 0)
|
---|
| 521 | {
|
---|
| 522 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 523 | {
|
---|
| 524 | if (_possible[tmpRow][tmpCol][tmpPossible] == true)
|
---|
| 525 | {
|
---|
| 526 | if (debug(3))
|
---|
| 527 | {
|
---|
| 528 | fprintf(DEBUGPLACE,
|
---|
| 529 | "DEBUG SOL 2: Checking [%i,%i], number: %i...\n",
|
---|
| 530 | tmpRow,tmpCol,(tmpPossible +1));
|
---|
| 531 | }
|
---|
| 532 | /* checkRow */
|
---|
| 533 | result = true;
|
---|
| 534 | for (tmpNumber = 0; tmpNumber < MAX_XYZ; tmpNumber++)
|
---|
| 535 | {
|
---|
| 536 | if (_possible[tmpNumber][tmpCol][tmpPossible] == true &&
|
---|
| 537 | tmpRow != tmpNumber)
|
---|
| 538 | {
|
---|
| 539 | if (debug(3))
|
---|
| 540 | {
|
---|
| 541 | fprintf(DEBUGPLACE,
|
---|
| 542 | "DEBUG SOL 2: ..failed at Rowcheck bcol [%i,%i]\n",
|
---|
| 543 | tmpNumber,tmpCol);
|
---|
| 544 | }
|
---|
| 545 | result = false;
|
---|
| 546 | break;
|
---|
| 547 | }
|
---|
| 548 | }
|
---|
| 549 | if (result == true)
|
---|
| 550 | {
|
---|
| 551 | if (debug(3)) { fprintf(DEBUGPLACE,"DEBUG SOL 2: ..succesfull at Rowcheck\n"); }
|
---|
| 552 | goto solutionFound;
|
---|
| 553 | }
|
---|
| 554 |
|
---|
| 555 | /* checkCol */
|
---|
| 556 | result = true;
|
---|
| 557 | for (tmpNumber = 0; tmpNumber < MAX_XYZ; tmpNumber++)
|
---|
| 558 | {
|
---|
| 559 | if (_possible[tmpRow][tmpNumber][tmpPossible] == true &&
|
---|
| 560 | tmpCol != tmpNumber)
|
---|
| 561 | {
|
---|
| 562 | if (debug(3))
|
---|
| 563 | {
|
---|
| 564 | fprintf(
|
---|
| 565 | DEBUGPLACE,
|
---|
| 566 | "DEBUG SOL 2: ..failed at Cowcheck bcol [%i,%i]\n",
|
---|
| 567 | tmpRow,tmpNumber);
|
---|
| 568 | }
|
---|
| 569 | result = false;
|
---|
| 570 | break;
|
---|
| 571 | }
|
---|
| 572 | }
|
---|
| 573 | if (result == true)
|
---|
| 574 | {
|
---|
| 575 | if (debug(3)) { fprintf(DEBUGPLACE,"DEBUG SOL 2: ..succesfull at Cowcheck\n"); }
|
---|
| 576 | goto solutionFound;
|
---|
| 577 | }
|
---|
| 578 |
|
---|
| 579 | /* checkBlock */
|
---|
| 580 | result = true;
|
---|
| 581 | blockTmpRow = tmpRow - (tmpRow % (MAX_XYZ / 3));
|
---|
| 582 | blockTmpCol = tmpCol - (tmpCol % (MAX_XYZ / 3));
|
---|
| 583 | for (blockRow = blockTmpRow; blockRow < (blockTmpRow + 3); blockRow++)
|
---|
| 584 | {
|
---|
| 585 | for (blockCol = blockTmpCol; blockCol < (blockTmpCol + 3); blockCol++)
|
---|
| 586 | {
|
---|
| 587 | if (debug(4))
|
---|
| 588 | {
|
---|
| 589 | fprintf(DEBUGPLACE,"DEBUG SOL 2: ..checking [%i,%i]\n",blockRow,blockCol);
|
---|
| 590 | }
|
---|
| 591 | if(_possible[blockRow][blockCol][tmpPossible] == true &&
|
---|
| 592 | (not (tmpRow == blockRow && tmpCol == blockCol)) )
|
---|
| 593 | {
|
---|
| 594 | if (debug(4)) { fprintf(DEBUGPLACE,"DEBUG SOL 2: ...will cause failure\n"); }
|
---|
| 595 | result = false;
|
---|
| 596 | goto blockCheckFailed;
|
---|
| 597 | }
|
---|
| 598 | else
|
---|
| 599 | {
|
---|
| 600 | if (debug(4)) { fprintf(DEBUGPLACE,"DEBUG SOL 2: ...will be no harm\n"); }
|
---|
| 601 | }
|
---|
| 602 | }
|
---|
| 603 | }
|
---|
| 604 | blockCheckFailed:
|
---|
| 605 | if (result == true)
|
---|
| 606 | {
|
---|
| 607 | if (debug(3)) { fprintf(DEBUGPLACE,"DEBUG SOL 2: ..succesfull at Blockcheck\n"); }
|
---|
| 608 | goto solutionFound;
|
---|
| 609 | }
|
---|
| 610 | }
|
---|
| 611 | }
|
---|
| 612 | }
|
---|
| 613 | }
|
---|
| 614 | }
|
---|
| 615 |
|
---|
| 616 | return(false);
|
---|
| 617 |
|
---|
| 618 | solutionFound:
|
---|
| 619 | row = tmpRow;
|
---|
| 620 | col = tmpCol;
|
---|
| 621 | number = tmpPossible + 1;
|
---|
| 622 | return(true);
|
---|
| 623 | }
|
---|
| 624 |
|
---|
| 625 | /* available striper, row based */
|
---|
| 626 | /* FIXME: Should be more modular, to reduce line length and readabilitcol */
|
---|
| 627 | bool Sudoku::_solution3a(int &row, int &col, int &number)
|
---|
| 628 | {
|
---|
| 629 | int tmpRow;
|
---|
| 630 | int tmpCol;
|
---|
| 631 | int tmpPossible;
|
---|
| 632 | int tmpPossible2;
|
---|
| 633 | int tmpColNumber;
|
---|
| 634 | int tmpNumber[MAX_XYZ];
|
---|
| 635 | int tmpAllNumbers;
|
---|
| 636 | int tmpAllNumbersFound;
|
---|
| 637 |
|
---|
| 638 | bool result;
|
---|
| 639 |
|
---|
| 640 | for (tmpRow = 0; tmpRow < MAX_XYZ; tmpRow++)
|
---|
| 641 | {
|
---|
| 642 | for (tmpCol = 0; tmpCol < MAX_XYZ; tmpCol++)
|
---|
| 643 | {
|
---|
| 644 | if (_sudoku[tmpRow][tmpCol] == 0)
|
---|
| 645 | {
|
---|
| 646 | if (debug(3)) { fprintf(DEBUGPLACE,"SOL 3a DEBUG Checking [%i,%i]...\n",tmpRow,tmpCol); }
|
---|
| 647 | /* Set all numbers */
|
---|
| 648 | tmpAllNumbers = 0;
|
---|
| 649 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 650 | {
|
---|
| 651 | if (_possible[tmpRow][tmpCol][tmpPossible] == true)
|
---|
| 652 | {
|
---|
| 653 | tmpNumber[tmpPossible] = 1;
|
---|
| 654 | tmpAllNumbers++;
|
---|
| 655 | }
|
---|
| 656 | else
|
---|
| 657 | {
|
---|
| 658 | tmpNumber[tmpPossible] = 0;
|
---|
| 659 | }
|
---|
| 660 | }
|
---|
| 661 | if (debug(3)) { fprintf(DEBUGPLACE,"SOL 3a DEBUG %i\n", tmpAllNumbers); }
|
---|
| 662 | if (tmpAllNumbers != 0)
|
---|
| 663 | {
|
---|
| 664 | for (tmpColNumber = 0; tmpColNumber < MAX_XYZ; tmpColNumber++)
|
---|
| 665 | {
|
---|
| 666 | if (_sudoku[tmpRow][tmpColNumber] == 0 && tmpColNumber != tmpCol)
|
---|
| 667 | {
|
---|
| 668 | result = true;
|
---|
| 669 | for (tmpPossible2 = 0; tmpPossible2 < MAX_XYZ; tmpPossible2++)
|
---|
| 670 | {
|
---|
| 671 | if ( _possible[tmpRow][tmpColNumber][tmpPossible2] == true &&
|
---|
| 672 | _possible[tmpRow][tmpCol][tmpPossible2] == false)
|
---|
| 673 | {
|
---|
| 674 | if (debug(3))
|
---|
| 675 | {
|
---|
| 676 | fprintf(DEBUGPLACE,"SOL 3a DEBUG [%i,%i] failed at %i\n",
|
---|
| 677 | tmpRow, tmpColNumber,tmpPossible2+1);
|
---|
| 678 | }
|
---|
| 679 | result = false;
|
---|
| 680 | break;
|
---|
| 681 | }
|
---|
| 682 | }
|
---|
| 683 | if (result == true)
|
---|
| 684 | {
|
---|
| 685 | if (debug(3))
|
---|
| 686 | {
|
---|
| 687 | fprintf(DEBUGPLACE,"SOL 3a DEBUG [%i,%i] will increase\n",
|
---|
| 688 | tmpRow, tmpColNumber);
|
---|
| 689 | }
|
---|
| 690 | for (tmpPossible2 = 0; tmpPossible2 < MAX_XYZ; tmpPossible2++)
|
---|
| 691 | {
|
---|
| 692 | if (_possible[tmpRow][tmpColNumber][tmpPossible2] == true)
|
---|
| 693 | {
|
---|
| 694 | if (debug(3)) { fprintf(DEBUGPLACE,
|
---|
| 695 | "SOL 3a DEBUG [%i,%i] will increase possible %i to %i\n",
|
---|
| 696 | tmpRow, tmpColNumber, tmpPossible2 + 1, tmpNumber[tmpPossible2] + 1);
|
---|
| 697 | }
|
---|
| 698 |
|
---|
| 699 | if (tmpNumber[tmpPossible2] == tmpAllNumbers)
|
---|
| 700 | {
|
---|
| 701 | goto colCheckFailed;
|
---|
| 702 | }
|
---|
| 703 | else
|
---|
| 704 | {
|
---|
| 705 | tmpNumber[tmpPossible2]++;
|
---|
| 706 | }
|
---|
| 707 | }
|
---|
| 708 | }
|
---|
| 709 | }
|
---|
| 710 | }
|
---|
| 711 | }
|
---|
| 712 |
|
---|
| 713 | /* calculate if result found */
|
---|
| 714 | tmpAllNumbersFound = 1;
|
---|
| 715 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 716 | {
|
---|
| 717 | if (tmpNumber[tmpPossible] == tmpAllNumbers)
|
---|
| 718 | {
|
---|
| 719 | tmpAllNumbersFound++;
|
---|
| 720 | if (debug(3))
|
---|
| 721 | {
|
---|
| 722 | fprintf(DEBUGPLACE,
|
---|
| 723 | "SOL 3b DEBUG %i reduced tmpAllNumbers to %i\n",
|
---|
| 724 | tmpPossible + 1, tmpAllNumbers);
|
---|
| 725 | }
|
---|
| 726 | }
|
---|
| 727 | }
|
---|
| 728 |
|
---|
| 729 | if (tmpAllNumbersFound == tmpAllNumbers)
|
---|
| 730 | {
|
---|
| 731 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 732 | {
|
---|
| 733 | if (tmpNumber[tmpPossible] == 1)
|
---|
| 734 | {
|
---|
| 735 | row = tmpRow;
|
---|
| 736 | col = tmpCol;
|
---|
| 737 | number = tmpPossible + 1;
|
---|
| 738 | return(true);
|
---|
| 739 | }
|
---|
| 740 | }
|
---|
| 741 | }
|
---|
| 742 | }
|
---|
| 743 | } //end if
|
---|
| 744 | colCheckFailed:
|
---|
| 745 | if (debug(3)) { fprintf(DEBUGPLACE,"SOL 3c DEBUG no failed solution found\n"); }
|
---|
| 746 | }
|
---|
| 747 | }
|
---|
| 748 | return(false);
|
---|
| 749 | }
|
---|
| 750 |
|
---|
| 751 | /* available striper, col based, note row number will change ;-) */
|
---|
| 752 | /* FIXME: Should be more modular, to reduce line length and readabilitcol */
|
---|
| 753 | bool Sudoku::_solution3b(int &row, int &col, int &number)
|
---|
| 754 | {
|
---|
| 755 | int tmpRow;
|
---|
| 756 | int tmpCol;
|
---|
| 757 | int tmpPossible;
|
---|
| 758 | int tmpPossible2;
|
---|
| 759 | int tmpRowNumber;
|
---|
| 760 | int tmpNumber[MAX_XYZ];
|
---|
| 761 | int tmpAllNumbers;
|
---|
| 762 | int tmpAllNumbersFound;
|
---|
| 763 |
|
---|
| 764 | bool result;
|
---|
| 765 |
|
---|
| 766 | for (tmpRow = 0; tmpRow < MAX_XYZ; tmpRow++)
|
---|
| 767 | {
|
---|
| 768 | for (tmpCol = 0; tmpCol < MAX_XYZ; tmpCol++)
|
---|
| 769 | {
|
---|
| 770 | if (_sudoku[tmpRow][tmpCol] == 0)
|
---|
| 771 | {
|
---|
| 772 | if (debug(3)) { fprintf(DEBUGPLACE,"SOL 3b DEBUG Checking [%i,%i]...\n",tmpRow,tmpCol); }
|
---|
| 773 | /* Set all numbers */
|
---|
| 774 | tmpAllNumbers = 0;
|
---|
| 775 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 776 | {
|
---|
| 777 | if (_possible[tmpRow][tmpCol][tmpPossible] == true)
|
---|
| 778 | {
|
---|
| 779 | tmpNumber[tmpPossible] = 1;
|
---|
| 780 | tmpAllNumbers++;
|
---|
| 781 | }
|
---|
| 782 | else
|
---|
| 783 | {
|
---|
| 784 | tmpNumber[tmpPossible] = 0;
|
---|
| 785 | }
|
---|
| 786 | }
|
---|
| 787 | if (debug(3)) { fprintf(DEBUGPLACE,"SOL 3b DEBUG %i\n", tmpAllNumbers); }
|
---|
| 788 | if (tmpAllNumbers != 0)
|
---|
| 789 | {
|
---|
| 790 | for (tmpRowNumber = 0; tmpRowNumber < MAX_XYZ; tmpRowNumber++)
|
---|
| 791 | {
|
---|
| 792 | if (_sudoku[tmpRowNumber][tmpCol] == 0 && tmpRowNumber != tmpRow)
|
---|
| 793 | {
|
---|
| 794 | result = true;
|
---|
| 795 | for (tmpPossible2 = 0; tmpPossible2 < MAX_XYZ; tmpPossible2++)
|
---|
| 796 | {
|
---|
| 797 | if ( _possible[tmpRowNumber][tmpCol][tmpPossible2] == true &&
|
---|
| 798 | _possible[tmpRow][tmpCol][tmpPossible2] == false)
|
---|
| 799 | {
|
---|
| 800 | if (debug(3))
|
---|
| 801 | {
|
---|
| 802 | fprintf(DEBUGPLACE,
|
---|
| 803 | "SOL 3b DEBUG [%i,%i] failed at %i\n",
|
---|
| 804 | tmpRowNumber, tmpCol,tmpPossible2+1);
|
---|
| 805 | }
|
---|
| 806 | result = false;
|
---|
| 807 | break;
|
---|
| 808 | }
|
---|
| 809 | }
|
---|
| 810 | if (result == true)
|
---|
| 811 | {
|
---|
| 812 | if (debug(3)) { fprintf(DEBUGPLACE,
|
---|
| 813 | "SOL 3b DEBUG [%i,%i] will increase\n",
|
---|
| 814 | tmpRowNumber, tmpCol);
|
---|
| 815 | }
|
---|
| 816 | for (tmpPossible2 = 0; tmpPossible2 < MAX_XYZ; tmpPossible2++)
|
---|
| 817 | {
|
---|
| 818 | if (_possible[tmpRowNumber][tmpCol][tmpPossible2] == true)
|
---|
| 819 | {
|
---|
| 820 | if (debug(3))
|
---|
| 821 | {
|
---|
| 822 | fprintf(DEBUGPLACE,
|
---|
| 823 | "SOL 3b DEBUG [%i,%i] will increase possible %i to %i\n",
|
---|
| 824 | tmpRowNumber, tmpCol, tmpPossible2 + 1,
|
---|
| 825 | tmpNumber[tmpPossible2] + 1);
|
---|
| 826 | }
|
---|
| 827 |
|
---|
| 828 | if (tmpNumber[tmpPossible2] == tmpAllNumbers)
|
---|
| 829 | {
|
---|
| 830 | goto rowCheckFailed;
|
---|
| 831 | }
|
---|
| 832 | else
|
---|
| 833 | {
|
---|
| 834 | tmpNumber[tmpPossible2]++;
|
---|
| 835 | }
|
---|
| 836 | }
|
---|
| 837 | }
|
---|
| 838 | }
|
---|
| 839 | }
|
---|
| 840 | }
|
---|
| 841 |
|
---|
| 842 | /* calculate if result found */
|
---|
| 843 | tmpAllNumbersFound = 1;
|
---|
| 844 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 845 | {
|
---|
| 846 | if (tmpNumber[tmpPossible] == tmpAllNumbers)
|
---|
| 847 | {
|
---|
| 848 | tmpAllNumbersFound++;
|
---|
| 849 | if (debug(3))
|
---|
| 850 | {
|
---|
| 851 | fprintf(DEBUGPLACE,
|
---|
| 852 | "SOL 3b DEBUG %i reduced tmpAllNumbers to %i\n",
|
---|
| 853 | tmpPossible + 1, tmpAllNumbers);
|
---|
| 854 | }
|
---|
| 855 | }
|
---|
| 856 | }
|
---|
| 857 |
|
---|
| 858 | if (tmpAllNumbersFound == tmpAllNumbers)
|
---|
| 859 | {
|
---|
| 860 | for (tmpPossible = 0; tmpPossible < MAX_XYZ; tmpPossible++)
|
---|
| 861 | {
|
---|
| 862 | if (tmpNumber[tmpPossible] == 1)
|
---|
| 863 | {
|
---|
| 864 | row = tmpRow;
|
---|
| 865 | col = tmpCol;
|
---|
| 866 | number = tmpPossible + 1;
|
---|
| 867 | return(true);
|
---|
| 868 | }
|
---|
| 869 | }
|
---|
| 870 | }
|
---|
| 871 | }
|
---|
| 872 | } //end if
|
---|
| 873 | rowCheckFailed:
|
---|
| 874 | if (debug(3)) { fprintf(DEBUGPLACE,"SOL 3b DEBUG no failed solution found\n"); }
|
---|
| 875 | }
|
---|
| 876 | }
|
---|
| 877 | return(false);
|
---|
| 878 | }
|
---|
| 879 | int Sudoku::solutionFinder()
|
---|
| 880 | {
|
---|
| 881 | #define NO_SOLUTION 0
|
---|
| 882 | #define SOLUTION_1 1
|
---|
| 883 | #define SOLUTION_2 2
|
---|
| 884 | #define SOLUTION_3a 3
|
---|
| 885 | #define SOLUTION_3b 4
|
---|
| 886 | #define SOLUTION_3c 5
|
---|
| 887 | int row;
|
---|
| 888 | int col;
|
---|
| 889 | int number;
|
---|
| 890 |
|
---|
| 891 | bool gameAnalcolzed;
|
---|
| 892 | int returnCode;
|
---|
| 893 | int solutionNumber;
|
---|
| 894 |
|
---|
| 895 | gameAnalcolzed = false;
|
---|
| 896 |
|
---|
| 897 | while( gameAnalcolzed == false )
|
---|
| 898 | {
|
---|
| 899 | solutionNumber = NO_SOLUTION;
|
---|
| 900 | if (_numbersFilled == MAX_XYZ * MAX_XYZ)
|
---|
| 901 | {
|
---|
| 902 | gameAnalcolzed = true;
|
---|
| 903 | returnCode = 0;
|
---|
| 904 | }
|
---|
| 905 | else
|
---|
| 906 | {
|
---|
| 907 | if (_solution1(row, col, number) == true)
|
---|
| 908 | {
|
---|
| 909 | solutionNumber = SOLUTION_1;
|
---|
| 910 | }
|
---|
| 911 | else if(_solution2(row, col, number) == true)
|
---|
| 912 | {
|
---|
| 913 | solutionNumber = SOLUTION_2;
|
---|
| 914 | }
|
---|
| 915 | else if(_solution3a(row, col, number) == true)
|
---|
| 916 | {
|
---|
| 917 | solutionNumber = SOLUTION_3a;
|
---|
| 918 | }
|
---|
| 919 | else if(_solution3b(row, col, number) == true)
|
---|
| 920 | {
|
---|
| 921 | solutionNumber = SOLUTION_3b;
|
---|
| 922 | }
|
---|
| 923 | else
|
---|
| 924 | {
|
---|
| 925 | gameAnalcolzed = true;
|
---|
| 926 | returnCode = 1;
|
---|
| 927 | }
|
---|
| 928 | }
|
---|
| 929 |
|
---|
| 930 | if (solutionNumber != NO_SOLUTION)
|
---|
| 931 | {
|
---|
| 932 | insert(row, col, number);
|
---|
| 933 | printf("Filled in %i at [%i,%i] found with finder %i\n", number, row, col, solutionNumber);
|
---|
| 934 | printf("Total Numbers filled %i\n", _numbersFilled);
|
---|
| 935 | printNice(row, col);
|
---|
| 936 | getchar();
|
---|
| 937 | }
|
---|
| 938 |
|
---|
| 939 | }
|
---|
| 940 | return(returnCode);
|
---|
| 941 | }
|
---|
| 942 |
|
---|
| 943 | int main(int argc, char *argv[])
|
---|
| 944 | {
|
---|
| 945 | Sudoku puzzel;
|
---|
| 946 | int timesFailed;
|
---|
| 947 | int returnCode;
|
---|
| 948 |
|
---|
| 949 | returnCode = 0;
|
---|
| 950 |
|
---|
| 951 | if (argc == 3 && strcmp(argv[1], "-f") == 0)
|
---|
| 952 | {
|
---|
| 953 | if (strcmp(argv[2], "-") == 0)
|
---|
| 954 | {
|
---|
| 955 | if (debug(1)) { fprintf(DEBUGPLACE, "Reading from 'stdin'\n"); }
|
---|
| 956 | puzzel.fromFile(stdin);
|
---|
| 957 | }
|
---|
| 958 | else
|
---|
| 959 | {
|
---|
| 960 | if (debug(1)) { fprintf(DEBUGPLACE, "Reading from %s\n",argv[2]); }
|
---|
| 961 | puzzel.fromFile(fopen(argv[2], "r"));
|
---|
| 962 | }
|
---|
| 963 | printf("I have read this puzzle\n");
|
---|
| 964 | puzzel.printNice();
|
---|
| 965 | returnCode = puzzel.solutionFinder();
|
---|
| 966 | if (returnCode == 0)
|
---|
| 967 | {
|
---|
| 968 | printf("I Guess this will be the final solution\n");
|
---|
| 969 | puzzel.printNice();
|
---|
| 970 | }
|
---|
| 971 | else
|
---|
| 972 | {
|
---|
| 973 | printf("Finding Solution failed, error code: %i\n", returnCode);
|
---|
| 974 | printf("Failed at puzzle\n");
|
---|
| 975 | puzzel.printNice();
|
---|
| 976 | puzzel.printPossible();
|
---|
| 977 | }
|
---|
| 978 | }
|
---|
| 979 | else if (argc == 3 && strcmp(argv[1], "-c") == 0)
|
---|
| 980 | {
|
---|
| 981 | fprintf(DEBUGPLACE,"Please wait will generating puzzle");
|
---|
| 982 | timesFailed = 0;
|
---|
| 983 | while (puzzel.randomNumbers(strtod(argv[2], NULL)) == 1 )
|
---|
| 984 | {
|
---|
| 985 | timesFailed++;
|
---|
| 986 | if (debug(1))
|
---|
| 987 | {
|
---|
| 988 | fprintf(DEBUGPLACE, "Failed to created the puzzel at the %i round\n", timesFailed);
|
---|
| 989 | }
|
---|
| 990 | else
|
---|
| 991 | {
|
---|
| 992 | fprintf(DEBUGPLACE,".");
|
---|
| 993 | }
|
---|
| 994 | puzzel.reset();
|
---|
| 995 | }
|
---|
| 996 | fprintf(DEBUGPLACE, "\nResult, (NOTE(!): puzzle might not be solveble)\n");
|
---|
| 997 | puzzel.printRaw();
|
---|
| 998 | }
|
---|
| 999 | else
|
---|
| 1000 | {
|
---|
| 1001 | printf("Usage %s -f <filename>\n",argv[0]);
|
---|
| 1002 | printf("NOTE 1: No error checking done, valid input puzzel will be ");
|
---|
| 1003 | printf("generated the -c flags\n");
|
---|
| 1004 | printf("NOTE 2: if <filename> = -, stdin will be used as input");
|
---|
| 1005 | printf("Usage %s -c <percent filled> To create a new puzzle\n",argv[0]);
|
---|
| 1006 | printf("NOTE 1: Above 60%% it will be a bit hard to create ");
|
---|
| 1007 | printf("a puzzle\n");
|
---|
| 1008 | printf("NOTE 2: Puzzle generated will not always be solveble\n");
|
---|
| 1009 | returnCode = 128;
|
---|
| 1010 | }
|
---|
| 1011 | return(returnCode);
|
---|
| 1012 | }
|
---|
| 1013 |
|
---|
| 1014 |
|
---|
| 1015 | \end{verbatim}
|
---|
| 1016 | \end{small}
|
---|
| 1017 |
|
---|
| 1018 | \newpage
|
---|
| 1019 | \section*{Appendix B: sudoku.cpp}
|
---|
| 1020 | Sample of 17-clue puzzles found at Minimum Sudoku\cite{gordon}. Input Row based.
|
---|
| 1021 |
|
---|
| 1022 | \begin{small}
|
---|
| 1023 | \begin{verbatim}
|
---|
| 1024 | 000000010400000000020000000000050407008000300001090000300400200050100000000806000
|
---|
| 1025 | 000000010400000000020000000000050604008000300001090000300400200050100000000807000
|
---|
| 1026 | 000000012000035000000600070700000300000400800100000000000120000080000040050000600
|
---|
| 1027 | 000000012003600000000007000410020000000500300700000600280000040000300500000000000
|
---|
| 1028 | 000000012008030000000000040120500000000004700060000000507000300000620000000100000
|
---|
| 1029 | 000000012040050000000009000070600400000100000000000050000087500601000300200000000
|
---|
| 1030 | 000000012050400000000000030700600400001000000000080000920000800000510700000003000
|
---|
| 1031 | 000000012300000060000040000900000500000001070020000000000350400001400800060000000
|
---|
| 1032 | 000000012400090000000000050070200000600000400000108000018000000000030700502000000
|
---|
| 1033 | 000000012500008000000700000600120000700000450000030000030000800000500700020000000
|
---|
| 1034 | 000000012700060000000000050080200000600000400000109000019000000000030800502000000
|
---|
| 1035 | 000000012800040000000000060090200000700000400000501000015000000000030900602000000
|
---|
| 1036 | 000000013000500070000802000000400900107000000000000200890000050040000600000010000
|
---|
| 1037 | 000000013000700060000508000000400800106000000000000200740000050020000400000010000
|
---|
| 1038 | 000000013000700060000509000000400900106000000000000200740000050080000400000010000
|
---|
| 1039 | 000000013000800070000502000000400900107000000000000200890000050040000600000010000
|
---|
| 1040 | 000000013020500000000000000103000070000802000004000000000340500670000200000010000
|
---|
| 1041 | 000000013040000080200060000609000400000800000000300000030100500000040706000000000
|
---|
| 1042 | 000000013040000080200060000906000400000800000000300000030100500000040706000000000
|
---|
| 1043 | 000000013040000090200070000607000400000300000000900000030100500000060807000000000
|
---|
| 1044 | ...
|
---|
| 1045 | \end{verbatim}
|
---|
| 1046 | \end{small}
|
---|
| 1047 |
|
---|
| 1048 | \newpage
|
---|
| 1049 | \section*{Appendix C: sudoku.cpp}
|
---|
| 1050 | The following Shell code has been used to generate the test results
|
---|
| 1051 |
|
---|
| 1052 | \begin{small}
|
---|
| 1053 | \begin{verbatim}
|
---|
| 1054 | #!/bin/sh
|
---|
| 1055 | # file: testcase.sh
|
---|
| 1056 | # author: Rick van der Zwet, 0433373
|
---|
| 1057 | # University Leiden, LIACS
|
---|
| 1058 | timesPlayed=0
|
---|
| 1059 | timesWon=0
|
---|
| 1060 | timesLost=0
|
---|
| 1061 | if [ "x$1" == "x" ]; then
|
---|
| 1062 | totalNumber=100
|
---|
| 1063 | else
|
---|
| 1064 | totalNumber=$1
|
---|
| 1065 | fi
|
---|
| 1066 |
|
---|
| 1067 | for puzzle in `cat puzzles17`
|
---|
| 1068 | do
|
---|
| 1069 | let "timesPlayed+=1"
|
---|
| 1070 | echo "${puzzle}" | ./sudoku -f - >/dev/null
|
---|
| 1071 | if [ "x$?" == "x0" ]; then
|
---|
| 1072 | let "timesWon+=1"
|
---|
| 1073 | else
|
---|
| 1074 | let "timesLost+=1"
|
---|
| 1075 | fi
|
---|
| 1076 | echo "Played: ${timesPlayed}"
|
---|
| 1077 | echo "won : ${timesWon}"
|
---|
| 1078 | echo "lost : ${timesLost}"
|
---|
| 1079 | if [ "x${timesPlayed}" == "x${totalNumber}" ]; then
|
---|
| 1080 | break
|
---|
| 1081 | fi
|
---|
| 1082 | done
|
---|
| 1083 | \end{verbatim}
|
---|
| 1084 | \end{small}
|
---|
| 1085 |
|
---|
| 1086 | \end{document}
|
---|