diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..30f37c8 --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +sudokuloeser: input.o input_nstd.o main.o output.o output_nstd.o output_std.o solver.o solver_nstd.o solver_std.o + gcc -lrt -o sudokuloeser input.o input_nstd.o main.o output.o output_nstd.o output_std.o solver.o solver_nstd.o solver_std.o + +input.o: input.c + gcc -Wall -pedantic -c input.c +input_nstd.o: input_nstd.c + gcc -Wall -pedantic -c input_nstd.c +main.o: main.c + gcc -Wall -pedantic -c main.c +output.o: output.c + gcc -Wall -pedantic -c output.c +output_nstd.o: output_nstd.c + gcc -Wall -pedantic -c output_nstd.c +output_std.o: output_std.c + gcc -Wall -pedantic -c output_std.c +solver.o: solver.c + gcc -Wall -pedantic -c solver.c +solver_nstd.o: solver_nstd.c + gcc -Wall -pedantic -c solver_nstd.c +solver_std.o: solver_std.c + gcc -Wall -pedantic -c solver_std.c + +clean: + rm -vf *.o sudokuloeser \ No newline at end of file diff --git a/README.md b/README.md index 7245eef..c4f9701 100644 --- a/README.md +++ b/README.md @@ -23,12 +23,13 @@ For better usage the Output is colored. # Usage - Usage: - sudokuloeser [options] - Options - -U Use Unicode - -h This help - -o Output file - -c no colors - -n just print, do not solve - +age: + ./sudokuloeser [options] +Options + -U Unicode borders + -h This help + -o Output-File + -O Overlay for non-standard files -c No colors + -p Plaintext + -n Dont solve, just print + -s silent diff --git a/input.c b/input.c new file mode 100644 index 0000000..0da9e16 --- /dev/null +++ b/input.c @@ -0,0 +1,63 @@ +#include "types.h" +#include "input.h" +#include +#include +#ifdef linux + #include +#endif + +int s_einlesen(char * path, sudoku * sf, options * o) { + int k; + FILE * fp = fopen(path,"r"); + char ch; + char tmp[50] = ""; + char line[150] = ""; + int z=0,sp=0; +#ifdef linux + regmatch_t m[1]; + regex_t reg; +#endif + if(fp == NULL) return 0; +#ifdef linux + while(fgets(tmp,100,fp)) { + if(strlen(line)+strlen(tmp) >= 150) { + fprintf(stderr,"Datei ist zu lang!\n"); + return 0; + } + strcat(line,tmp); + } + if(regcomp(®,"([ 0-9]{0,9}\r?\n){8}[ 0-9]{0,9}\r?\n?$",REG_EXTENDED) == 0 && regexec(®,line,1,m,REG_EXTENDED) == 0 && m[0].rm_so == 0) { + regfree(®); + }else{ + fprintf(stderr,"Kein Sudoku gefunden!\n"); + regfree(®); + return 0; + } + rewind(fp); +#endif + while(fgets(line,100,fp)) { + k=0; + for(sp=0;sp<9;sp++) { + ch = line[sp]; + if(k == 1 || ch == '\0' || ch == '\n' || ch == '\r') { + k = 1; + ch = 0; + }else{ + ch-=48; + } + if(0test(sf,z,sp,ch) == 0) return -1; + sf->feld[z][sp] = (ch<0||ch>9)?0:ch; + if(sf->feld[z][sp] > 0) { + o->set_num(sf,sf->feld[z][sp],z,sp); + } + sf->vorgabe[z][sp] = (ch<1||ch>9)?0:1; + sf->notnull--; + } + } + if(++z >= 9) break; + } + fclose(fp); + if(z<9) return 0; + return 1; +} \ No newline at end of file diff --git a/input.h b/input.h new file mode 100644 index 0000000..1dc2982 --- /dev/null +++ b/input.h @@ -0,0 +1,12 @@ +#ifndef input_h__ +#define input_h__ + +/** + * Reads the Sudoku from file + * @param path The File to read from + * @param sf The struct where to write the Data + * @param o The options with the functions to use + */ +int s_einlesen(char * path, sudoku * sf, options * o); + +#endif /* input_h__ */ \ No newline at end of file diff --git a/input_nstd.c b/input_nstd.c new file mode 100644 index 0000000..82fa701 --- /dev/null +++ b/input_nstd.c @@ -0,0 +1,60 @@ +#include "types.h" +#include "input.h" +#include +#include +#ifdef linux + #include +#endif + +int s_b_einlesen(char * path, sudoku * sf) { + int k; + FILE * fp = fopen(path,"r"); + char ch; + char tmp[50] = ""; + char line[150] = ""; + int z=0,sp=0; +#ifdef linux + regmatch_t m[1]; + regex_t reg; +#endif + if(fp == NULL) { + fprintf(stderr,"File not Found\n"); + return 0; + } +#ifdef linux + while(fgets(tmp,100,fp)) { + if(strlen(line)+strlen(tmp) >= 150) { + fprintf(stderr,"Datei ist zu lang!\n"); + return 0; + } + strcat(line,tmp); + } + if(regcomp(®,"([1-9]{9}\r?\n){8}[1-9]{9}\r?\n?$",REG_EXTENDED) == 0 && regexec(®,line,1,m,REG_EXTENDED) == 0 && m[0].rm_so == 0) { + regfree(®); + }else{ + fprintf(stderr,"Kein Sudoku gefunden!\n"); + regfree(®); + return 0; + } + rewind(fp); +#endif + while(fgets(line,100,fp)) { + k=0; + for(sp=0;sp<9;sp++) { + ch = line[sp]; + if(k == 1 || ch == '\0' || ch == '\n' || ch == '\r') { + k = 1; + ch = 0; + }else{ + ch-=48; + } + if(0belegung[z][sp] = (ch<0||ch>9)?0:ch; + } + } + if(++z >= 9) break; + } + fclose(fp); + if(z<9) return 0; + return 1; +} \ No newline at end of file diff --git a/input_nstd.h b/input_nstd.h new file mode 100644 index 0000000..a8d61f4 --- /dev/null +++ b/input_nstd.h @@ -0,0 +1,11 @@ +#ifndef imput_nstd_h__ +#define imput_nstd_h__ + +/** + * Reads the Sudoku from file + * @param path The File to read from + * @param sf The struct where to write the Data + */ +int s_b_einlesen(char * path, sudoku * sf); + +#endif /* imput_nstd_h__ */ \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..5c209fa --- /dev/null +++ b/main.c @@ -0,0 +1,248 @@ +/* + * main.c + * + * Copyright 2012 Thomas Battermann + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "types.h" +#include "main.h" +#include "input.h" +#include "input_nstd.h" +#include "solver.h" +#include "solver_std.h" +#include "solver_nstd.h" +#include "output.h" +#include "output_std.h" +#include "output_nstd.h" +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) { +#ifdef linux + options o = {0,1,0,0,0,1,NULL,NULL,NULL,NULL,NULL,NULL}; +#else + options o = {0,0,0,0,0,1,NULL,NULL,NULL,NULL,NULL,NULL}; +#endif + sudoku s={ {{0}}, {{0}}, {{0}}, {{{1}}}, 81 }; + char st=0,ret=0; +#ifdef linux + struct timespec ts,te,l_ts,l_te; + long double t; + clock_gettime(CLOCK_REALTIME, &ts); +#endif + /* Read the command line parameters */ + readOptions(argc,argv,&o); + /* feed the functions */ + if(o.outfile == NULL) { + printf("default\n"); + newStandard(&o); + }else{ + newNonStandard(&o); + } + /* die belegung der zellen einlesen */ + if( o.overlay != NULL) { + if( s_b_einlesen(o.overlay,&s) == 0 ) { + fprintf(stderr,"Ungueltiges Dateiformat (Overlay)!\n"); + return 2; + } + } + /* Aus Datei einlesen und Fehler auswerten */ + st = s_einlesen(o.infile,&s,&o); + if(st == 0) { + fprintf(stderr,"Ungueltiges Dateiformat!\n"); + if(o.outfile != NULL) s_write_error( o.outfile ,0 ); + return 2; + }else if(st == -1) { + if(o.color) + fprintf(stderr,"\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n\n"); + else + fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n\n"); + if(o.outfile != NULL) s_write_error( o.outfile ,1 ); + return 1; + } + /* falls nicht gelöst werden soll: */ + if(o.solve == 0) { + o.ausgabe(&s,o.color); + return 0; + } + /* Sudoku Loesen, Loseung ausgeben und in Datei schreiben */ + if(!o.silent) printf("Suche...\nProbiere es mit Logik... "); +#ifdef linux + clock_gettime(CLOCK_REALTIME, &l_ts); +#endif + st = sl_loes(&s,&o); + if( st != 1 ) { + if(!o.silent) printf("FAIL\nNun mit Backtracking... "); + st = s_loes_track(&s,0,&o); + if(!o.silent) printf("%s\n",(st != 1 ? "FAIL" : "OK" )); + }else{ + if(!o.silent) printf("OK\n"); + } +#ifdef linux + clock_gettime(CLOCK_REALTIME, &l_te); +#endif + if(st == 0) { + if(o.color) + fprintf(stderr,"\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n"); + else + fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n"); + if(o.outfile != NULL) s_write_error( o.outfile , 2 ); + ret = 1; + }else{ + if(o.color) { + if(!o.silent) printf("\033[32;1mLoesung gefunden:\033[0m\n\n"); + }else{ + if(!o.silent) printf("Loesung gefunden:\n\n"); + } + o.ausgabe(&s,o.color); + if(o.outfile != NULL) s_write( o.outfile ,&s ); + } +#ifdef linux + if(!o.silent) { + clock_gettime(CLOCK_REALTIME, &te); + t = (l_te.tv_sec + l_te.tv_nsec*0.000000001)-(l_ts.tv_sec + l_ts.tv_nsec*0.000000001); + printf("\nBenoetigte Zeit (loesen): %Lfs\n",t); + t = (te.tv_sec + te.tv_nsec*0.000000001)-(ts.tv_sec + ts.tv_nsec*0.000000001); + printf("Benoetigte Zeit (gesamt): %Lfs\n",t); + } +#endif + return ret; +} + +/* + * Read the given options and save them + */ +void readOptions(int argc, char **argv, options * o) { + char c; + while ((c = getopt (argc, argv, "chHo:O:uUnsp")) != -1) { + switch(c) { + case 'h': + print_help(argc,argv); + exit(0); + break; + case 'u': + case 'U': + o->unicode = 1; + break; + case 'H': + o->html = 1; + break; + case 'c': + o->color = 0; + break; + case 'O': + if(o->overlay == NULL && strcmp(optarg,"") != 0) + o->overlay = optarg; + break; + case 'o': + if(o->outfile == NULL && strcmp(optarg,"") != 0) + o->outfile = optarg; + break; + case 'n': + o->solve = 0; + break; + case 's': + o->silent = 1; + break; + case 'p': + o->plaintext = 1; + break; + case '?': + if (optopt == 'c') + fprintf (stderr, "Option -%c requires an argument.\n", optopt); + else if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt); + exit(1); + break; + } + } + if((argc-optind) != 1) { + print_help(argc,argv); + exit(0); + } + o->infile = argv[optind]; +} +void newStandard(options * o) { + o->check_nums = solver_check_nums; + o->set_num = solver_set_num; + o->test = solver_test; + /* Check which out put to use */ + if(o->unicode) { + o->ausgabe = std_ausgabe_unicode; + }else if(o->plaintext) { + o->ausgabe = s_plain; + }else{ + o->ausgabe = std_ausgabe; + } +} +void newNonStandard(options * o) { + o->check_nums = solver_nstd_check_nums; + o->set_num = solver_nstd_set_num; + o->test = solver_nstd_test; + /* Check which out put to use */ + if(o->unicode) { + o->ausgabe = nstd_ausgabe_unicode; + }else if(o->plaintext) { + o->ausgabe = s_plain; + }else{ + o->ausgabe = nstd_ausgabe; + } +} + +void print_help(int argc, char **argv) { +#ifdef linux + printf("\033[0;1mUsage:\033[0m\n"); + printf(" %s [options] \n",argv[0]); + printf("\033[0;1mOptions\033[0m\n"); + printf(" -U Unicode borders\n"); + printf(" -h This help\n"); + printf(" -o Output-File\n"); + printf(" -O Overlay for non-standard files\n"); + printf(" -c No colors\n"); + printf(" -p Plaintext\n"); + printf(" -n Dont solve, just print\n"); + printf(" -s silent\n"); + printf("\033[0;1mOutput:\033[0m\n"); + printf(" \033[32;1mgreen:\033[0m Given values\n"); + printf(" \033[33;1myellow:\033[0m Values find by logic\n"); + printf(" white: Values find by backtracking\n\n"); + printf("By Thomas Battermann\n"); +#else +printf("\033[0;1mUsage:\033[0m\n"); + printf(" %s [options] \n",argv[0]); + printf("\033[0;1mOptions\033[0m\n"); + printf(" -U Unicode borders\n"); + printf(" -h This help\n"); + printf(" -o Output-File\n"); + printf(" -O Overlay for non-standard files\n"); + printf(" -p Plaintext\n"); + printf(" -n Dont solve, just print\n"); + printf(" -s silent\n"); + printf("\033[0;1mOutput:\033[0m\n"); + printf(" \033[32;1mgreen:\033[0m Given values\n"); + printf(" \033[33;1myellow:\033[0m Values find by logic\n"); + printf(" white: Values find by backtracking\n\n"); + printf("By Thomas Battermann\n"); +#endif +} diff --git a/main.h b/main.h new file mode 100644 index 0000000..d49aec8 --- /dev/null +++ b/main.h @@ -0,0 +1,10 @@ +#ifndef main_h__ +#define main_h__ + +int main(int argc, char **argv); +void readOptions(int argc, char **argv, options * o); +void newStandard(options * o); +void newNonStandard(options * o); +void print_help(int argc, char **argv); + +#endif /* main_h__ */ \ No newline at end of file diff --git a/makefile b/makefile deleted file mode 100644 index a284f4a..0000000 --- a/makefile +++ /dev/null @@ -1,14 +0,0 @@ -sudokuloeser: sudokuloeser.c sudokuloeser_nstd.c - gcc -Wall -pedantic -O3 -lrt sudokuloeser.c -o sudokuloeser - gcc -Wall -pedantic -O3 -lrt sudokuloeser_nstd.c -o sudokuloeser_nstd - -windows: sudokuloeser.c - sh -c '[ -x /usr/bin/i486-mingw32-gcc ] && i486-mingw32-gcc -Wall -pedantic sudokuloeser.c -o sudokuloeser.exe || [ -x /usr/bin/i586-mingw32msvc-gcc ] && i586-mingw32msvc-gcc -Wall -pedantic sudokuloeser.c -o sudokuloeser.exe || echo "Compiler not found"' - sh -c '[ -x /usr/bin/i486-mingw32-gcc ] && i486-mingw32-gcc -Wall -pedantic sudokuloeser_nstd.c -o sudokuloeser_nstd.exe || [ -x /usr/bin/i586-mingw32msvc-gcc ] && i586-mingw32msvc-gcc -Wall -pedantic sudokuloeser_nstd.c -o sudokuloeser_nstd.exe || echo "Compiler not found"' - -install: sudokuloeser - install -vDm755 sudokuloeser /usr/bin/sudokuloeser - install -vDm755 sudokuloeser /usr/bin/sudokuloeser_nstd - -uninstall: - rm /usr/bin/sudokuloeser diff --git a/output.c b/output.c new file mode 100644 index 0000000..7f51368 --- /dev/null +++ b/output.c @@ -0,0 +1,51 @@ +#include "types.h" +#include "output.h" +#include + +int s_write(char* fn,sudoku* s) { + /* Sudoku in Datei schreiben */ + int i,j; + FILE * fp = fopen(fn,"w"); + if(fp == NULL) return 0; + printf("Schreibe in Datei `%s'...\n",fn); + for(i=0;i<9;i++) { + for(j=0;j<9;j++) { + fputc(s->feld[i][j]+48,fp); + } + fputc( 10, fp); + } + fclose(fp); + return 1; +} + +int s_write_error(char* fn,int err) { + /* Fehler in Datei schreiben */ + FILE * fp = fopen(fn,"w+"); + if(fp == NULL) return 0; + printf("Schreibe Fehler in Datei `%s'...\n",fn); + switch(err) { + case 0: + fputs("Eingabefehler\nEingabedatei ist Fehlerhaft!\n",fp); + break; + case 1: + fputs("Eingabefehler\nSudoku ist nicht Loesbar! (Kein Loeseversuch)\n",fp); + break; + case 2: + fputs("Eingabefehler\nSudoku ist nicht Loesbar!\n",fp); + break; + default: + fputs("Eingabefehler\n",fp); + } + fclose(fp); + return 1; +} + +void s_plain(sudoku* s, int color) { + int i,j; + for(i=0;i<9;i++) { + for(j=0;j<9;j++) { + printf("%d",s->feld[i][j]); + } + printf("\n"); + } +} \ No newline at end of file diff --git a/output.h b/output.h new file mode 100644 index 0000000..56958a2 --- /dev/null +++ b/output.h @@ -0,0 +1,27 @@ +#ifndef output_h__ +#define output_h__ + +#include "main.h" + +/** + * Write the sudoku to a file + * @param fn The Filename + * @param s The Sudoku to write + */ +int s_write(char* fn,sudoku* s); + +/** + * Write error-message in output-file + * @param fn The Filename + * @param err The Error-Code + */ +int s_write_error(char* fn,int err); + +/** + * Prints the plain sudoku + * @param s The Sudoku + * @param color Takes no effect + */ +void s_plain(sudoku* s, int color); + +#endif /* output_h__ */ \ No newline at end of file diff --git a/output_nstd.c b/output_nstd.c new file mode 100644 index 0000000..3fdeb42 --- /dev/null +++ b/output_nstd.c @@ -0,0 +1,110 @@ +#include "types.h" +#include "output_nstd.h" +#include + +char* rahmen(char v) { + /* 1 = oben; 2 = rechts; 4 = unten; 8 = links */ + switch(v) { + case 0: return "┼───"; + case 1: return "╀───"; + case 2: return "┾━━━"; + case 3: return "╄━━━"; + case 4: return "╁───"; + case 5: return "╂───"; + case 6: return "╆━━━"; + case 7: return "╊━━━"; + case 8: return "┽───"; + case 9: return "╃───"; + case 10: return "┿━━━"; + case 11: return "╇━━━"; + case 12: return "╅───"; + case 13: return "╉───"; + case 14: return "╈━━━"; + case 15: return "╋━━━"; + } + return "+---"; +} + +void nstd_ausgabe_unicode(sudoku* s,int color) { + int i,j; + /* Rahmen oben */ + printf("┏━━━"); + for(i = 0; i < 8 ; i++) { + printf("%s━━━",(s->belegung[0][i] == s->belegung[0][i+1]) ? "┯" : "┳" ); + } + printf("┓\n"); + /* Die Zeilen ausgeben */ + for(i = 0; i < 9; i++) { + /* Zeile*/ + printf("┃"); + for(j = 0; j<9; j++) { + if(color) { + printf(" %s%c\033[0m %s", + (s->vorgabe[i][j] == 1) ? "\033[32;1m" : ( (s->vorgabe[i][j] == 2) ? "\033[33;1m" : "") , + (s->feld[i][j] == 0) ? ' ' : s->feld[i][j]+48, + (j == 8 || s->belegung[i][j] != s->belegung[i][j+1]) ? "┃" : "│" ); + }else{ + printf(" %c %s", + (s->feld[i][j] == 0) ? ' ' : s->feld[i][j]+48, + (j == 8 || s->belegung[i][j] != s->belegung[i][j+1]) ? "┃" : "│" ); + } + } + printf("\n"); + /* trenner für i != 8 */ + if(i<8) { + printf("%s", (s->belegung[ i ][ j ] == s->belegung[i+1][ j ]) ? "┠───" : "┣━━━" ); + for(j = 0; j < 8; j++) { + printf("%s", rahmen( + (s->belegung[ i ][ j ] != s->belegung[ i ][j+1]) * 1 + + (s->belegung[ i ][j+1] != s->belegung[i+1][j+1]) * 2 + + (s->belegung[i+1][ j ] != s->belegung[i+1][j+1]) * 4 + + (s->belegung[ i ][ j ] != s->belegung[i+1][ j ]) * 8 + ) + ); + } + printf("%s", (s->belegung[ i ][ j ] == s->belegung[i+1][ j ]) ? "┨" : "┫" ); + printf("\n"); + } + } + + /* Rahmen unten */ + printf("┗━━━"); + for(i = 0; i < 8 ; i++) { + printf("%s━━━",(s->belegung[8][i] == s->belegung[8][i+1]) ? "┷" : "┻" ); + } + printf("┛\n"); +} + +char* colors(char val) { + switch(val) { + case 1: return "\033[48;5;16m"; + case 2: return "\033[48;5;105m"; + case 3: return "\033[48;5;19m"; + case 4: return "\033[48;5;28m"; + case 5: return "\033[48;5;52m"; + case 6: return "\033[48;5;55m"; + case 7: return "\033[48;5;100m"; + case 8: return "\033[48;5;172m"; + case 9: return "\033[48;5;129m"; + case 0: return "\033[48;5;129m"; + } + return ""; +} + +void nstd_ausgabe(sudoku* s,int color) { + int i,j; + for(i=0;i<9;i++) { + if(i%3==0 && !color) printf("+-------+-------+-------+\n"); + for(j=0;j<9;j++) { + if(j%3==0 && !color) printf("| "); + if(color) { + printf("%s%d \033[0m",colors(s->belegung[i][j]),s->feld[i][j]); + }else + printf("%d ",s->feld[i][j]); + + } + if(!color) printf("|"); + printf("\n"); + } + if(!color) printf("+-------+-------+-------+\n"); +} \ No newline at end of file diff --git a/output_nstd.h b/output_nstd.h new file mode 100644 index 0000000..3cac742 --- /dev/null +++ b/output_nstd.h @@ -0,0 +1,30 @@ +#ifndef output_nstd_h__ +#define output_nstd_h__ + +/** + * Print the Sudoku on stdout using unicode borders + * @param s The Sudoku + * @param color Use colors or not + */ +void nstd_ausgabe_unicode(sudoku* s,int color); + +/** + * Print the Sudoku on stdout using ascii + * @param s The Sudoku + * @param color Use colors or not + */ +void nstd_ausgabe(sudoku* s,int color); + +/** + * Choose border-elements + * @param v which elemnt to return + */ +char* rahmen(char v); + +/** + * Choose color by value + * @param val which color + */ +char* colors(char val); + +#endif /* output_nstd_h__ */ \ No newline at end of file diff --git a/output_std.c b/output_std.c new file mode 100644 index 0000000..718d1df --- /dev/null +++ b/output_std.c @@ -0,0 +1,61 @@ +#include "types.h" +#include "output_std.h" +#include + +void std_ausgabe_unicode(sudoku* s,int color) { + int i,j; + printf("┏━━━┯━━━┯━━━┳━━━┯━━━┯━━━┳━━━┯━━━┯━━━┓\n"); + for(i=0;i<9;i++) { + if(i%3==0 && i!=0) printf("┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫\n"); + else if (i!=0) printf("┠───┼───┼───╂───┼───┼───╂───┼───┼───┨\n"); + for(j=0;j<9;j++) { + if(j%3==0) printf("┃ "); + else printf("│ "); + if(color) { + if(s->feld[i][j] == 0) { + /* printf("\033[30;1m?\033[0m "); */ + printf(" "); + }else if(s->vorgabe[i][j] == 1){ + printf("\033[32;1m%d\033[0m ",s->feld[i][j]); + }else if(s->vorgabe[i][j] == 2){ + printf("\033[33;1m%d\033[0m ",s->feld[i][j]); + }else{ + printf("%d ",s->feld[i][j]); + } + }else{ + if(s->feld[i][j] == 0) { + printf(" "); + }else{ + printf("%d ",s->feld[i][j]); + } + } + + } + printf("┃\n"); + } + printf("┗━━━┷━━━┷━━━┻━━━┷━━━┷━━━┻━━━┷━━━┷━━━┛\n"); +} + +void std_ausgabe(sudoku* s,int color) { + int i,j; + for(i=0;i<9;i++) { + if(i%3==0) printf("+-------+-------+-------+\n"); + for(j=0;j<9;j++) { + if(j%3==0) printf("| "); + if(color) { + if(s->feld[i][j] == 0) { + printf("\033[30;1m?\033[0m "); + }else if(s->vorgabe[i][j] == 1){ + printf("\033[32;1m%d\033[0m ",s->feld[i][j]); + }else if(s->vorgabe[i][j] == 2){ + printf("\033[33;1m%d\033[0m ",s->feld[i][j]); + }else{ + printf("%d ",s->feld[i][j]); + } + }else + printf("%d ",s->feld[i][j]); + } + printf("|\n"); + } + printf("+-------+-------+-------+\n"); +} \ No newline at end of file diff --git a/output_std.h b/output_std.h new file mode 100644 index 0000000..815810b --- /dev/null +++ b/output_std.h @@ -0,0 +1,18 @@ +#ifndef output_std_h__ +#define output_std_h__ + +/** + * Print the Sudoku on stdout using unicode borders + * @param s The Sudoku + * @param color Use colors or not + */ +void std_ausgabe_unicode(sudoku* s,int color); + +/** + * Print the Sudoku on stdout using ascii + * @param s The Sudoku + * @param color Use colors or not + */ +void std_ausgabe(sudoku* s,int color); + +#endif /* output_std_h__ */ \ No newline at end of file diff --git a/solver.c b/solver.c new file mode 100644 index 0000000..ee01034 --- /dev/null +++ b/solver.c @@ -0,0 +1,43 @@ +#include "types.h" +#include "solver.h" + +int sl_loes(sudoku* s, options * o) { + int z,sp,repl=1,zahl; + while(repl) { + repl = 0; + for(z=0;z<9;z++) { + for(sp=0;sp<9;sp++) { + for(zahl=1;zahl<=9;zahl++) { + if(s->mgl[z][sp][zahl-1] != 1 && s->vorgabe[z][sp] == 0 && s->feld[z][sp] == 0 && o->check_nums(s,zahl,z,sp) == 1) { + s->feld[z][sp] = zahl; + s->vorgabe[z][sp] = 2; + o->set_num(s,zahl,z,sp); + s->notnull--; + repl = 1; + } + } + } + } + } + if(s->notnull != 0) return 0; + return 1; +} + +int s_loes_track(sudoku * s, int pos, options * o) { + int i,x=pos/9,y=pos%9; + if(pos == 81) return 1; + if(s->feld[x][y] != 0) { + return s_loes_track(s,pos+1,o); + }else{ + for(i=1;i<=9;i++) { + if(s->mgl[x][y][i-1] != 1 && o->test(s,x,y,i) == 1) { + s->feld[x][y] = i; + if(s_loes_track(s,pos+1,o) == 1) { + return 1; + } + } + } + } + s->feld[x][y] = 0; + return 0; +} \ No newline at end of file diff --git a/solver.h b/solver.h new file mode 100644 index 0000000..6fe81e8 --- /dev/null +++ b/solver.h @@ -0,0 +1,17 @@ +#ifndef solver_h__ +#define solver_h__ + +/** + * Tries to solve the Sudoku with logic + * @param s the sudokue to solve + */ +int sl_loes(sudoku* s, options * o); + +/** + * Tries to solve a sudoku with backtracking (bruteforce) + * @param s the sudokue to solve + * @param pos the actual position, usualy start with 0 + */ +int s_loes_track(sudoku * s, int pos, options * o); + +#endif /* solver_h__ */ \ No newline at end of file diff --git a/solver_nstd.c b/solver_nstd.c new file mode 100644 index 0000000..d811266 --- /dev/null +++ b/solver_nstd.c @@ -0,0 +1,59 @@ +#include "types.h" +#include "solver_nstd.h" + +int solver_nstd_check_nums(sudoku* s,int zahl,int z, int sp) { + int l = s->belegung[z][sp] , i, j, sum=0; + zahl--; + if(s->mgl[z][sp][zahl] == 1) return 0; + /* Spalte pruefen */ + for(i=0;i<9;i++) + if(s->mgl[z][i][zahl] != 1 && i!=sp) { sum=1; break; } + if(sum==0) return 1; + /* Zeile pruefen */ + sum = 0; + for(i=0;i<9;i++) + if(s->mgl[i][sp][zahl] != 1 && i!=z) { sum=1; break; } + if(sum==0) return 1; + /* Block pruefen */ + sum=0; + for(i=0;i<9;i++) + for(j=0;j<9;j++) + if( s->belegung[i][j] == l && s->mgl[i][j][zahl] != 1 && !(i == z && j == sp)) { + sum=1; break; + } + if(sum==0) return 1; + return 0; +} + +void solver_nstd_set_num(sudoku* s,int zahl,int z, int sp) { + int l = s->belegung[z][sp] , i, j; + zahl--; + for(i=0;i<9;i++) { + s->mgl[z][sp][i] = 1; /* Zelle sperren */ + s->mgl[z][i][zahl] = 1; /* Spalte austragen */ + s->mgl[i][sp][zahl] = 1; /* Zeile austragen */ + } + /* Block austragen */ + for(i=0;i<9;i++) + for(j=0;j<9;j++) + if(s->belegung[i][j] == l) + s->mgl[i][j][zahl] = 1; +} + +int solver_nstd_test(sudoku *s, int z, int sp, int zahl) { + /* prueft, ob eine zahlen stimmt _kann_ */ + int l = s->belegung[z][sp] , i, j; + /* Spalte und Reihe */ + for(i=0;i<9;i++) { + if(s->feld[z][i] == zahl || s->feld[i][sp] == zahl) return 0; + } + /* Passendes Feld */ + for(i=0;i<9;i++) { + for(j=0;j<9;j++) { + if( s->belegung[i][j] == l && s->feld[i][j] == zahl ) { + return 0; + } + } + } + return 1; +} \ No newline at end of file diff --git a/solver_nstd.h b/solver_nstd.h new file mode 100644 index 0000000..3813f25 --- /dev/null +++ b/solver_nstd.h @@ -0,0 +1,31 @@ +#ifndef solver_nstd_h__ +#define solver_nstd_h__ + +/** + * Checks if there are other posibilities for the number if not return 1 + * @param s The sudoku struct + * @param zahl The number to check + * @param z row + * @param sp column + */ +int solver_nstd_check_nums(sudoku* s,int zahl,int z, int sp); + +/** + * Stroke out the number (Logic Solver) + * @param s The sudoku struct + * @param zahl The number to check + * @param z row + * @param sp column + */ +void solver_nstd_set_num(sudoku* s,int zahl,int z, int sp); + +/** + * Checks if the number fits + * @param s The sudoku struct + * @param z row + * @param sp column + * @param zahl The number to check + */ +int solver_nstd_test(sudoku *s, int z, int sp, int zahl); + +#endif /* solver_nstd_h__ */ \ No newline at end of file diff --git a/solver_std.c b/solver_std.c new file mode 100644 index 0000000..0c29c2e --- /dev/null +++ b/solver_std.c @@ -0,0 +1,51 @@ +#include "types.h" +#include "solver_std.h" + +int solver_check_nums(sudoku* s,int zahl,int z, int sp) { + int x=z-(z%3) , y=sp-(sp%3) , i, j, sum=0; + zahl--; + if(s->mgl[z][sp][zahl] == 1) return 0; + /* Spalte pruefen */ + for(i=0;i<9;i++) + if(s->mgl[z][i][zahl] != 1 && i!=sp) { sum=1; break; } + if(sum==0) return 1; + /* Zeile pruefen */ + sum = 0; + for(i=0;i<9;i++) + if(s->mgl[i][sp][zahl] != 1 && i!=z) { sum=1; break; } + if(sum==0) return 1; + /* Block pruefen */ + sum=0; + for(i=0;i<3;i++) + for(j=0;j<3;j++) + if(s->mgl[x+i][y+j][zahl] != 1 && !((x+i) == z && (y+j) == sp)) { sum=1; break; } + if(sum==0) return 1; + return 0; +} + +void solver_set_num(sudoku* s,int zahl,int z, int sp) { + int x=z-(z%3) , y=sp-(sp%3) , i, j; + zahl--; + + for(i=0;i<9;i++) { + s->mgl[z][sp][i] = 1; /* Zelle sperren */ + s->mgl[z][i][zahl] = 1; /* Spalte austragen */ + s->mgl[i][sp][zahl] = 1; /* Zeile austragen */ + } + /* Block austragen */ + for(i=0;i<3;i++) + for(j=0;j<3;j++) + s->mgl[x+i][y+j][zahl] = 1; +} + +int solver_test(sudoku *s, int z, int sp, int zahl) { + /* prueft, ob eine zahlen stimmt _kann_ */ + int x=z-(z%3) , y=sp-(sp%3) , i, j; + for(i=0;i<9;i++) { + if(s->feld[z][i] == zahl || s->feld[i][sp] == zahl) return 0; + } + for(i=0;i<3;i++) + for(j=0;j<3;j++) + if(s->feld[x+i][y+j] == zahl) return 0; + return 1; +} \ No newline at end of file diff --git a/solver_std.h b/solver_std.h new file mode 100644 index 0000000..436c443 --- /dev/null +++ b/solver_std.h @@ -0,0 +1,31 @@ +#ifndef solver_std_h__ +#define solver_std_h__ + +/** + * Checks if there are other posibilities for the number if not return 1 + * @param s The sudoku struct + * @param zahl The number to check + * @param z row + * @param sp column + */ +int solver_check_nums(sudoku* s,int zahl,int z, int sp); + +/** + * Stroke out the number (Logic Solver) + * @param s The sudoku struct + * @param zahl The number to check + * @param z row + * @param sp column + */ +void solver_set_num(sudoku* s,int zahl,int z, int sp); + +/** + * Checks if the number fits + * @param s The sudoku struct + * @param z row + * @param sp column + * @param zahl The number to check + */ +int solver_test(sudoku *s, int z, int sp, int zahl); + +#endif /* solver_std_h__ */ \ No newline at end of file diff --git a/sudokuloeser.c b/sudokuloeser.c deleted file mode 100644 index 0eb2c19..0000000 --- a/sudokuloeser.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * sudokuloeser.c - * - * Copyright 2010 Thomas Battermann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#ifdef linux - #include -#endif - -typedef struct sudoku { - char feld[9][9]; /* Feld mit den Zahlen */ - char vorgabe[9][9]; /* Fuer Farbige Ausgabe auf der Linuxkonsole benoetigt */ - char mgl[9][9][9]; /* Moegliche Zahlen (fuer Logik); 0=moeglich; 1=nicht moeglich; !! */ - char notnull; /* Anzahl der verbleibenden leeren zellen, nur fuer logik */ -} sudoku; - -/* Allgemeine Funktionen */ - int s_einlesen(char*, sudoku*); /* Einlesen aus Datei */ - void s_ausgabe(sudoku*,int); /* Auf dem bildschirm ausgeben */ - void s_ausgabe_unicode(sudoku*,int); /* Auf dem bildschirm ausgeben, Unicode Rahmenelemente */ - void s_plain(sudoku*); /* Plaintext (wie eingabe-datei) */ - void print_help(int,char**); /* "Hilfe" ausgeben */ -/* Loeserfunktionen */ - /* Funktion fuer Backtracking */ - int s_loes_track(sudoku*,int); /* Funktion zum loesen des Sudokus mithilfe von Backtracking */ - int s_test(sudoku*,int,int,int); /* Testen ob eine Zahl in ein "Feld" passt */ - /* Funktionen fuer Logik */ - int sl_loes(sudoku*); /* Versuch das Sudoku auf logischem wege zu loesen */ - void sl_set_num(sudoku*,int,int,int); /* Setzt eine Zahl, wenn diese via logik gefunden wurde. */ - int sl_check_nums(sudoku*,int,int,int); /* prueft ob eine zahl alleine in einem block... ist*/ -/* Ausgabe in Datei */ - int s_write(char*,sudoku*); /* Ausgabe in Datei schreiben */ - int s_write_error(char*,int); /* Bei Fehler in Datei schreiben */ - -#ifdef linux -const int OUTPUT_COLOR=1; -#else -const int OUTPUT_COLOR=0; -#endif - -/* Ausgabe unterdrücken */ -int silent = 0; - -int main(int argc, char **argv) { - sudoku s={ {{0}}, {{0}}, {{{1}}}, 81 }; - char* outfile = NULL; - int st=0,sl=0,ret=0,plain=0; - int c,unicode=0,color=0,outfilev=0,solve=1; -#ifdef linux - struct timespec ts,te,l_ts,l_te; - long double t; - clock_gettime(CLOCK_REALTIME, &ts); - color = 1; -#endif - /* Argumente auslesen */ - while ((c = getopt (argc, argv, "cho:uUnsp")) != -1) - switch(c) { - case 'h': - print_help(argc,argv); - exit(0); - break; - case 'u': - case 'U': - unicode = 1; - break; - case 'c': - color = 0; - break; - case 'o': - if(outfilev==0) outfile = ((strcmp(optarg,"") == 0) ? "sudoku_geloest.txt" : optarg); - outfilev = 1; - break; - case 'n': - solve = 0; - break; - case 's': - silent = 1; - break; - case 'p': - plain = 1; - break; - case '?': - if (optopt == 'c') - fprintf (stderr, "Option -%c requires an argument.\n", optopt); - else if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt); - exit(1); - break; - } - /* Aus Datei einlesen und Fehler auswerten */ - st = s_einlesen(argv[optind],&s); - if(st == 0) { - fprintf(stderr,"Ungueltiges Dateiformat!\n"); - if(outfilev) s_write_error( outfile ,0 ); - return 2; - }else if(st == -1) { - if(color) - fprintf(stderr,"\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n\n"); - else - fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n\n"); - if(outfilev) s_write_error( outfile ,1 ); - return 1; - } - /* falls nicht gelöst werden soll: */ - if(solve == 0) { - if(unicode == 1) { - s_ausgabe_unicode(&s,color); - }else if(plain == 1) { - s_plain(&s); - }else{ - s_ausgabe(&s,color); - } - exit(0); - } - /* Sudoku Loesen, Loseung ausgeben und in Datei schreiben */ - if(!silent) printf("Suche...\nProbiere es mit Logik... "); -#ifdef linux - clock_gettime(CLOCK_REALTIME, &l_ts); -#endif - sl = sl_loes(&s); - if(sl != 1) { - if(!silent) printf("FAIL\nNun mit Backtracking... "); - sl = s_loes_track(&s,0); - if(!silent) printf("%s\n",(sl != 1 ? "FAIL" : "OK" )); - }else{ - if(!silent) printf("OK\n"); - } -#ifdef linux - clock_gettime(CLOCK_REALTIME, &l_te); -#endif - if(sl == 0) { - if(color) - fprintf(stderr,"\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n"); - else - fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n"); - if(outfilev) s_write_error( outfile , 2 ); - ret = 1; - }else{ - if(color) { - if(!silent) printf("\033[32;1mLoesung gefunden:\033[0m\n\n"); - }else{ - if(!silent) printf("Loesung gefunden:\n\n"); - } - if(unicode == 1) { - s_ausgabe_unicode(&s,color); - }else if(plain == 1) { - s_plain(&s); - }else{ - s_ausgabe(&s,color); - } - if(outfilev) s_write( outfile ,&s ); - } -#ifdef linux - if(!silent) { - clock_gettime(CLOCK_REALTIME, &te); - t = (l_te.tv_sec + l_te.tv_nsec*0.000000001)-(l_ts.tv_sec + l_ts.tv_nsec*0.000000001); - printf("\nBenoetigte Zeit (loesen): %Lfs\n",t); - t = (te.tv_sec + te.tv_nsec*0.000000001)-(ts.tv_sec + ts.tv_nsec*0.000000001); - printf("Benoetigte Zeit (gesamt): %Lfs\n",t); - } -#endif - return ret; -} - -int s_einlesen(char * path, sudoku * sf) { - int k; - FILE * fp = fopen(path,"r"); - char ch; - char tmp[50] = ""; - char line[150] = ""; - int z=0,sp=0; -#ifdef linux - regmatch_t m[1]; - regex_t reg; -#endif - if(fp == NULL) return 0; -#ifdef linux - while(fgets(tmp,100,fp)) { - if(strlen(line)+strlen(tmp) >= 150) { - fprintf(stderr,"Datei ist zu lang!\n"); - return 0; - } - strcat(line,tmp); - } - if(regcomp(®,"([ 0-9]{0,9}\r?\n){8}[ 0-9]{0,9}\r?\n?$",REG_EXTENDED) == 0 && regexec(®,line,1,m,REG_EXTENDED) == 0 && m[0].rm_so == 0) { - regfree(®); - }else{ - fprintf(stderr,"Kein Sudoku gefunden!\n"); - regfree(®); - return 0; - } - rewind(fp); -#endif - while(fgets(line,100,fp)) { - k=0; - for(sp=0;sp<9;sp++) { - ch = line[sp]; - if(k == 1 || ch == '\0' || ch == '\n' || ch == '\r') { - k = 1; - ch = 0; - }else{ - ch-=48; - } - if(0feld[z][sp] = (ch<0||ch>9)?0:ch; - if(sf->feld[z][sp] > 0) { - sl_set_num(sf,sf->feld[z][sp],z,sp); - } - sf->vorgabe[z][sp] = (ch<1||ch>9)?0:1; - sf->notnull--; - } - } - if(++z >= 9) break; - } - fclose(fp); - if(z<9) return 0; - return 1; -} - -void s_plain(sudoku* s) { - int i,j; - for(i=0;i<9;i++) { - for(j=0;j<9;j++) { - printf("%d",s->feld[i][j]); - } - printf("\n"); - } -} - -void s_ausgabe(sudoku* s,int color) { - int i,j; - for(i=0;i<9;i++) { - if(i%3==0) printf("+-------+-------+-------+\n"); - for(j=0;j<9;j++) { - if(j%3==0) printf("| "); - if(color) { - if(s->feld[i][j] == 0) { - printf("\033[30;1m?\033[0m "); - }else if(s->vorgabe[i][j] == 1){ - printf("\033[32;1m%d\033[0m ",s->feld[i][j]); - }else if(s->vorgabe[i][j] == 2){ - printf("\033[33;1m%d\033[0m ",s->feld[i][j]); - }else{ - printf("%d ",s->feld[i][j]); - } - }else - printf("%d ",s->feld[i][j]); - - } - printf("|\n"); - } - printf("+-------+-------+-------+\n"); -} - -void s_ausgabe_unicode(sudoku* s,int color) { - int i,j; - printf("┏━━━┯━━━┯━━━┳━━━┯━━━┯━━━┳━━━┯━━━┯━━━┓\n"); - for(i=0;i<9;i++) { - if(i%3==0 && i!=0) printf("┣━━━┿━━━┿━━━╋━━━┿━━━┿━━━╋━━━┿━━━┿━━━┫\n"); - else if (i!=0) printf("┠───┼───┼───╂───┼───┼───╂───┼───┼───┨\n"); - for(j=0;j<9;j++) { - if(j%3==0) printf("┃ "); - else printf("│ "); - if(color) { - if(s->feld[i][j] == 0) { - /* printf("\033[30;1m?\033[0m "); */ - printf(" "); - }else if(s->vorgabe[i][j] == 1){ - printf("\033[32;1m%d\033[0m ",s->feld[i][j]); - }else if(s->vorgabe[i][j] == 2){ - printf("\033[33;1m%d\033[0m ",s->feld[i][j]); - }else{ - printf("%d ",s->feld[i][j]); - } - }else{ - if(s->feld[i][j] == 0) { - printf(" "); - }else{ - printf("%d ",s->feld[i][j]); - } - } - - } - printf("┃\n"); - } - printf("┗━━━┷━━━┷━━━┻━━━┷━━━┷━━━┻━━━┷━━━┷━━━┛\n"); -} - - -void print_help(int argc, char **argv) { -#ifdef linux - printf("\033[0;1mUsage:\033[0m\n"); - printf(" %s [optionen] \n",argv[0]); - printf("\033[0;1mOptionen\033[0m\n"); - printf(" -U Unicode Rahmenelemente\n"); - printf(" -h Diese Hilfe\n"); - printf(" -o Ausgabedatei\n"); - printf(" -c Keine Farbe\n"); - printf(" -p Plaintext\n"); - printf(" -n Nicht loesen, nur ausgeben\n"); - printf(" -s Nur die Lösung ausgeben\n"); - printf("\033[0;1mAusgabe:\033[0m\n"); - printf(" \033[32;1mgruen:\033[0m Vorgegebene Werte\n"); - printf(" \033[33;1mgelb:\033[0m Mit Logik gefundene Werte\n"); - printf(" weis: Per Backtracking gefundene Werte\n\n"); - printf("By Thomas Battermann\n"); -#else - printf("Usage:\n"); - printf(" %s [optionen] \n",argv[0]); - printf("Optionen:\n"); - printf(" -U Unicode Rahmenelemente (Probleme unter Windows!)\n"); - printf(" -h Diese Hilfe\n"); - printf(" -o Ausgabedatei\n"); - printf(" -p Plaintext\n"); - printf(" -s Nur die Lösung ausgeben\n"); - printf(" -n Nicht loesen, nur ausgeben\n"); - printf("By Thomas Battermann\n"); - -#endif -} - -int s_test(sudoku *s, int z, int sp, int zahl) { - /* prueft, ob eine zahlen stimmt _kann_ */ - int x=z-(z%3) , y=sp-(sp%3) , i, j; - for(i=0;i<9;i++) { - if(s->feld[z][i] == zahl || s->feld[i][sp] == zahl) return 0; - } - for(i=0;i<3;i++) - for(j=0;j<3;j++) - if(s->feld[x+i][y+j] == zahl) return 0; - return 1; -} - -int s_loes_track(sudoku * s, int pos) { - int i,x=pos/9,y=pos%9; - if(pos == 81) return 1; - if(s->feld[x][y] != 0) { - return s_loes_track(s,pos+1); - }else{ - for(i=1;i<=9;i++) { - if(s->mgl[x][y][i-1] != 1 && s_test(s,x,y,i) == 1) { - s->feld[x][y] = i; - if(s_loes_track(s,pos+1) == 1) { - return 1; - } - } - } - } - s->feld[x][y] = 0; - return 0; -} - -int s_write(char* fn,sudoku* s) { - /* Sudoku in Datei schreiben */ - int i,j; - FILE * fp = fopen(fn,"w"); - if(fp == NULL) return 0; - printf("Schreibe in Datei `%s'...\n",fn); - for(i=0;i<9;i++) { - for(j=0;j<9;j++) { - fputc(s->feld[i][j]+48,fp); - } - fputc( 10, fp); - } - fclose(fp); - return 1; -} - -int s_write_error(char* fn,int err) { - /* Fehler in Datei schreiben */ - FILE * fp = fopen(fn,"w+"); - if(fp == NULL) return 0; - printf("Schreibe Fehler in Datei `%s'...\n",fn); - switch(err) { - case 0: - fputs("Eingabefehler\nEingabedatei ist Fehlerhaft!\n",fp); - break; - case 1: - fputs("Eingabefehler\nSudoku ist nicht Loesbar! (Kein Loeseversuch)\n",fp); - break; - case 2: - fputs("Eingabefehler\nSudoku ist nicht Loesbar!\n",fp); - break; - default: - fputs("Eingabefehler\n",fp); - } - fclose(fp); - return 1; -} - -void sl_set_num(sudoku* s,int zahl,int z, int sp) { - int x=z-(z%3) , y=sp-(sp%3) , i, j; - zahl--; - - for(i=0;i<9;i++) { - s->mgl[z][sp][i] = 1; /* Zelle sperren */ - s->mgl[z][i][zahl] = 1; /* Spalte austragen */ - s->mgl[i][sp][zahl] = 1; /* Zeile austragen */ - } - /* Block austragen */ - for(i=0;i<3;i++) - for(j=0;j<3;j++) - s->mgl[x+i][y+j][zahl] = 1; -} - -int sl_check_nums(sudoku* s,int zahl,int z, int sp) { - int x=z-(z%3) , y=sp-(sp%3) , i, j, sum=0; - zahl--; - if(s->mgl[z][sp][zahl] == 1) return 0; - /* Spalte pruefen */ - for(i=0;i<9;i++) - if(s->mgl[z][i][zahl] != 1 && i!=sp) { sum=1; break; } - if(sum==0) return 1; - /* Zeile pruefen */ - sum = 0; - for(i=0;i<9;i++) - if(s->mgl[i][sp][zahl] != 1 && i!=z) { sum=1; break; } - if(sum==0) return 1; - /* Block pruefen */ - sum=0; - for(i=0;i<3;i++) - for(j=0;j<3;j++) - if(s->mgl[x+i][y+j][zahl] != 1 && !((x+i) == z && (y+j) == sp)) { sum=1; break; } - if(sum==0) return 1; - return 0; -} - -int sl_loes(sudoku* s) { - int z,sp,repl=1,zahl; - while(repl) { - repl = 0; - for(z=0;z<9;z++) { - for(sp=0;sp<9;sp++) { - for(zahl=1;zahl<=9;zahl++) { - if(s->mgl[z][sp][zahl-1] != 1 && s->vorgabe[z][sp] == 0 && s->feld[z][sp] == 0 && sl_check_nums(s,zahl,z,sp) == 1) { - s->feld[z][sp] = zahl; - s->vorgabe[z][sp] = 2; - sl_set_num(s,zahl,z,sp); - s->notnull--; - repl = 1; - } - } - } - } - } - if(s->notnull != 0) return 0; - return 1; -} diff --git a/sudokuloeser_nstd.c b/sudokuloeser_nstd.c deleted file mode 100644 index 242a34c..0000000 --- a/sudokuloeser_nstd.c +++ /dev/null @@ -1,606 +0,0 @@ -/* - * sudokuloeser.c - * - * Copyright 2010 Thomas Battermann - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#ifdef linux - #include -#endif - -typedef struct sudoku { - char feld[9][9]; /* Feld mit den Zahlen */ - char vorgabe[9][9]; /* Fuer Farbige Ausgabe auf der Linuxkonsole benoetigt */ - char belegung[9][9]; /* Die Vorgegebenen Felder */ - char mgl[9][9][9]; /* Moegliche Zahlen (fuer Logik); 0=moeglich; 1=nicht moeglich; !! */ - char notnull; /* Anzahl der verbleibenden leeren zellen, nur fuer logik */ -} sudoku; - -/* Allgemeine Funktionen */ - int s_einlesen(char*, sudoku*); /* Einlesen aus Datei */ - int s_b_einlesen(char*, sudoku*); /* Belegung aus Datei einlesen */ - void s_ausgabe(sudoku*,int); /* Auf dem bildschirm ausgeben */ - void s_ausgabe_unicode(sudoku*,int); /* Auf dem bildschirm ausgeben, Unicode Rahmenelemente */ - void s_plain(sudoku*); /* Plaintext (wie eingabe-datei) */ - char* colors(char); - char* border(char); - void print_help(int,char**); /* "Hilfe" ausgeben */ -/* Loeserfunktionen */ - /* Funktion fuer Backtracking */ - int s_loes_track(sudoku*,int); /* Funktion zum loesen des Sudokus mithilfe von Backtracking */ - int s_test(sudoku*,int,int,int); /* Testen ob eine Zahl in ein "Feld" passt */ - /* Funktionen fuer Logik */ - int sl_loes(sudoku*); /* Versuch das Sudoku auf logischem wege zu loesen */ - void sl_set_num(sudoku*,int,int,int); /* Setzt eine Zahl, wenn diese via logik gefunden wurde. */ - int sl_check_nums(sudoku*,int,int,int); /* prueft ob eine zahl alleine in einem block... ist*/ -/* Ausgabe in Datei */ - int s_write(char*,sudoku*); /* Ausgabe in Datei schreiben */ - int s_write_error(char*,int); /* Bei Fehler in Datei schreiben */ - -#ifdef linux -const int OUTPUT_COLOR=1; -#else -const int OUTPUT_COLOR=0; -#endif - -/* Ausgabe unterdrücken */ -int silent = 0; - -int main(int argc, char **argv) { - sudoku s={ {{0}}, {{0}}, {{0}}, {{{1}}}, 81 }; - char* outfile = NULL; - int st=0,sl=0,ret=0,sb=0,plain=0; - int c,unicode=0,color=0,outfilev=0,solve=1; -#ifdef linux - struct timespec ts,te,l_ts,l_te; - long double t; - clock_gettime(CLOCK_REALTIME, &ts); - color = 1; -#endif - /* Argumente auslesen */ - while ((c = getopt (argc, argv, "cho:uUnsp")) != -1) - switch(c) { - case 'h': - print_help(argc,argv); - exit(0); - break; - case 'u': - case 'U': - unicode = 1; - break; - case 'c': - color = 0; - break; - case 'o': - if(outfilev==0) outfile = ((strcmp(optarg,"") == 0) ? "sudoku_geloest.txt" : optarg); - outfilev = 1; - break; - case 'n': - solve = 0; - break; - case 's': - silent = 1; - break; - case 'p': - plain = 1; - break; - case '?': - if (optopt == 'c') - fprintf (stderr, "Option -%c requires an argument.\n", optopt); - else if (isprint (optopt)) - fprintf (stderr, "Unknown option `-%c'.\n", optopt); - else - fprintf (stderr,"Unknown option character `\\x%x'.\n",optopt); - exit(1); - break; - } - /* die belegung der zellen einlesen */ - sb = s_b_einlesen(argv[optind+1],&s); - if(sb == 0) { - fprintf(stderr,"Ungueltiges Dateiformat (Overlay)!\n"); - return sb; - } - /* Aus Datei einlesen und Fehler auswerten */ - st = s_einlesen(argv[optind],&s); - if(st == 0) { - fprintf(stderr,"Ungueltiges Dateiformat!\n"); - if(outfilev) s_write_error( outfile ,0 ); - return 2; - }else if(st == -1) { - if(color) - fprintf(stderr,"\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n\n"); - else - fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n\n"); - if(outfilev) s_write_error( outfile ,1 ); - return 1; - } - /* falls nicht gelöst werden soll: */ - if(solve == 0) { - if(unicode == 1) { - s_ausgabe_unicode(&s,color); - }else if(plain == 1) { - s_plain(&s); - }else{ - s_ausgabe(&s,color); - } - exit(0); - } - /* Sudoku Loesen, Loseung ausgeben und in Datei schreiben */ - if(!silent) printf("Suche...\nProbiere es mit Logik... "); -#ifdef linux - clock_gettime(CLOCK_REALTIME, &l_ts); -#endif - sl = sl_loes(&s); - if(sl != 1) { - if(!silent) printf("FAIL\nNun mit Backtracking... "); - sl = s_loes_track(&s,0); - if(!silent) printf("%s\n",(sl != 1 ? "FAIL" : "OK" )); - }else{ - if(!silent) printf("OK\n"); - } -#ifdef linux - clock_gettime(CLOCK_REALTIME, &l_te); -#endif - if(sl == 0) { - if(color) - fprintf(stderr,"\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n"); - else - fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n"); - if(outfilev) s_write_error( outfile , 2 ); - ret = 1; - }else{ - if(color) { - if(!silent) printf("\033[32;1mLoesung gefunden:\033[0m\n\n"); - }else{ - if(!silent) printf("Loesung gefunden:\n\n"); - } - if(unicode == 1) { - s_ausgabe_unicode(&s,color); - }else if(plain == 1) { - s_plain(&s); - }else{ - s_ausgabe(&s,color); - } - if(outfilev) s_write( outfile ,&s ); - } -#ifdef linux - if(!silent) { - clock_gettime(CLOCK_REALTIME, &te); - t = (l_te.tv_sec + l_te.tv_nsec*0.000000001)-(l_ts.tv_sec + l_ts.tv_nsec*0.000000001); - printf("\nBenoetigte Zeit (loesen): %Lfs\n",t); - t = (te.tv_sec + te.tv_nsec*0.000000001)-(ts.tv_sec + ts.tv_nsec*0.000000001); - printf("Benoetigte Zeit (gesamt): %Lfs\n",t); - } -#endif - return ret; -} - -int s_einlesen(char * path, sudoku * sf) { - int k; - FILE * fp = fopen(path,"r"); - char ch; - char tmp[50] = ""; - char line[150] = ""; - int z=0,sp=0; -#ifdef linux - regmatch_t m[1]; - regex_t reg; -#endif - if(fp == NULL) { - fprintf(stderr,"File not Found!"); - return 0; - } -#ifdef linux - while(fgets(tmp,100,fp)) { - if(strlen(line)+strlen(tmp) >= 150) { - fprintf(stderr,"Datei ist zu lang!\n"); - return 0; - } - strcat(line,tmp); - } - if(regcomp(®,"([ 0-9]{0,9}\r?\n){8}[ 0-9]{0,9}\r?\n?$",REG_EXTENDED) == 0 && regexec(®,line,1,m,REG_EXTENDED) == 0 && m[0].rm_so == 0) { - regfree(®); - }else{ - fprintf(stderr,"Kein Sudoku gefunden!\n"); - regfree(®); - return 0; - } - rewind(fp); -#endif - while(fgets(line,100,fp)) { - k=0; - for(sp=0;sp<9;sp++) { - ch = line[sp]; - if(k == 1 || ch == '\0' || ch == '\n' || ch == '\r') { - k = 1; - ch = 0; - }else{ - ch-=48; - } - if(0feld[z][sp] = (ch<0||ch>9)?0:ch; - if(sf->feld[z][sp] > 0) { - sl_set_num(sf,sf->feld[z][sp],z,sp); - } - sf->vorgabe[z][sp] = (ch<1||ch>9)?0:1; - sf->notnull--; - } - } - if(++z >= 9) break; - } - fclose(fp); - if(z<9) return 0; - return 1; -} - -int s_b_einlesen(char * path, sudoku * sf) { - int k; - FILE * fp = fopen(path,"r"); - char ch; - char tmp[50] = ""; - char line[150] = ""; - int z=0,sp=0; -#ifdef linux - regmatch_t m[1]; - regex_t reg; -#endif - if(fp == NULL) { - fprintf(stderr,"File not Found\n"); - return 0; - } -#ifdef linux - while(fgets(tmp,100,fp)) { - if(strlen(line)+strlen(tmp) >= 150) { - fprintf(stderr,"Datei ist zu lang!\n"); - return 0; - } - strcat(line,tmp); - } - if(regcomp(®,"([1-9]{9}\r?\n){8}[1-9]{9}\r?\n?$",REG_EXTENDED) == 0 && regexec(®,line,1,m,REG_EXTENDED) == 0 && m[0].rm_so == 0) { - regfree(®); - }else{ - fprintf(stderr,"Kein Sudoku gefunden!\n"); - regfree(®); - return 0; - } - rewind(fp); -#endif - while(fgets(line,100,fp)) { - k=0; - for(sp=0;sp<9;sp++) { - ch = line[sp]; - if(k == 1 || ch == '\0' || ch == '\n' || ch == '\r') { - k = 1; - ch = 0; - }else{ - ch-=48; - } - if(0belegung[z][sp] = (ch<0||ch>9)?0:ch; - } - } - if(++z >= 9) break; - } - fclose(fp); - if(z<9) return 0; - return 1; -} - -char* colors(char val) { - switch(val) { - case 1: return "\033[48;5;16m"; - case 2: return "\033[48;5;105m"; - case 3: return "\033[48;5;19m"; - case 4: return "\033[48;5;28m"; - case 5: return "\033[48;5;52m"; - case 6: return "\033[48;5;55m"; - case 7: return "\033[48;5;100m"; - case 8: return "\033[48;5;172m"; - case 9: return "\033[48;5;129m"; - case 0: return "\033[48;5;129m"; - } - return ""; -} - -void s_plain(sudoku* s) { - int i,j; - for(i=0;i<9;i++) { - for(j=0;j<9;j++) { - printf("%d",s->feld[i][j]); - } - printf("\n"); - } -} - -void s_ausgabe(sudoku* s,int color) { - int i,j; - for(i=0;i<9;i++) { - if(i%3==0 && !color) printf("+-------+-------+-------+\n"); - for(j=0;j<9;j++) { - if(j%3==0 && !color) printf("| "); - if(color) { - printf("%s%d \033[0m",colors(s->belegung[i][j]),s->feld[i][j]); - /*if(s->feld[i][j] == 0) { - printf("\033[30;1m?\033[0m "); - }else if(s->vorgabe[i][j] == 1){ - printf("\033[32;1m%d\033[0m ",s->feld[i][j]); - }else if(s->vorgabe[i][j] == 2){ - printf("\033[33;1m%d\033[0m ",s->feld[i][j]); - }else{ - printf("%d ",s->feld[i][j]); - }*/ - }else - printf("%d ",s->feld[i][j]); - - } - if(!color) printf("|"); - printf("\n"); - } - if(!color) printf("+-------+-------+-------+\n"); -} - -char* rahmen(char v) { - /* 1 = oben; 2 = rechts; 4 = unten; 8 = links */ - switch(v) { - case 0: return "┼───"; - case 1: return "╀───"; - case 2: return "┾━━━"; - case 3: return "╄━━━"; - case 4: return "╁───"; - case 5: return "╂───"; - case 6: return "╆━━━"; - case 7: return "╊━━━"; - case 8: return "┽───"; - case 9: return "╃───"; - case 10: return "┿━━━"; - case 11: return "╇━━━"; - case 12: return "╅───"; - case 13: return "╉───"; - case 14: return "╈━━━"; - case 15: return "╋━━━"; - } - return "+---"; -} - -void s_ausgabe_unicode(sudoku* s,int color) { - int i,j; - /* Rahmen oben */ - printf("┏━━━"); - for(i = 0; i < 8 ; i++) { - printf("%s━━━",(s->belegung[0][i] == s->belegung[0][i+1]) ? "┯" : "┳" ); - } - printf("┓\n"); - /* Die Zeilen ausgeben */ - for(i = 0; i < 9; i++) { - /* Zeile*/ - printf("┃"); - for(j = 0; j<9; j++) { - if(color) { - printf(" %s%c\033[0m %s", - (s->vorgabe[i][j] == 1) ? "\033[32;1m" : ( (s->vorgabe[i][j] == 2) ? "\033[33;1m" : "") , - (s->feld[i][j] == 0) ? ' ' : s->feld[i][j]+48, - (j == 8 || s->belegung[i][j] != s->belegung[i][j+1]) ? "┃" : "│" ); - }else{ - printf(" %c %s", - (s->feld[i][j] == 0) ? ' ' : s->feld[i][j]+48, - (j == 8 || s->belegung[i][j] != s->belegung[i][j+1]) ? "┃" : "│" ); - } - } - printf("\n"); - /* trenner für i != 8 */ - if(i<8) { - printf("%s", (s->belegung[ i ][ j ] == s->belegung[i+1][ j ]) ? "┠───" : "┣━━━" ); - for(j = 0; j < 8; j++) { - printf("%s", rahmen( - (s->belegung[ i ][ j ] != s->belegung[ i ][j+1]) * 1 - + (s->belegung[ i ][j+1] != s->belegung[i+1][j+1]) * 2 - + (s->belegung[i+1][ j ] != s->belegung[i+1][j+1]) * 4 - + (s->belegung[ i ][ j ] != s->belegung[i+1][ j ]) * 8 - ) - ); - } - printf("%s", (s->belegung[ i ][ j ] == s->belegung[i+1][ j ]) ? "┨" : "┫" ); - printf("\n"); - } - } - - /* Rahmen unten */ - printf("┗━━━"); - for(i = 0; i < 8 ; i++) { - printf("%s━━━",(s->belegung[8][i] == s->belegung[8][i+1]) ? "┷" : "┻" ); - } - printf("┛\n"); -} - - -void print_help(int argc, char **argv) { -#ifdef linux - printf("\033[0;1mUsage:\033[0m\n"); - printf(" %s [optionen] \n",argv[0]); - printf("\033[0;1mOptionen\033[0m\n"); - printf(" -U Unicode Rahmenelemente\n"); - printf(" -h Diese Hilfe\n"); - printf(" -o Ausgabedatei\n"); - printf(" -c Keine Farbe\n"); - printf(" -p Plaintext\n"); - printf(" -n Nicht loesen, nur ausgeben\n"); - printf(" -s Nur die Lösung ausgeben\n"); - printf("\033[0;1mAusgabe:\033[0m\n"); - printf(" \033[32;1mgruen:\033[0m Vorgegebene Werte\n"); - printf(" \033[33;1mgelb:\033[0m Mit Logik gefundene Werte\n"); - printf(" weis: Per Backtracking gefundene Werte\n\n"); - printf("By Thomas Battermann\n"); -#else - printf("Usage:\n"); - printf(" %s [optionen] \n",argv[0]); - printf("Optionen:\n"); - printf(" -U Unicode Rahmenelemente (Probleme unter Windows!)\n"); - printf(" -h Diese Hilfe\n"); - printf(" -o Ausgabedatei\n"); - printf(" -p Plaintext\n"); - printf(" -s Nur die Lösung ausgeben\n"); - printf(" -n Nicht loesen, nur ausgeben\n"); - printf("By Thomas Battermann\n"); - -#endif -} - -int s_test(sudoku *s, int z, int sp, int zahl) { - /* prueft, ob eine zahlen stimmt _kann_ */ - int l = s->belegung[z][sp] , i, j; - /* Spalte und Reihe */ - for(i=0;i<9;i++) { - if(s->feld[z][i] == zahl || s->feld[i][sp] == zahl) return 0; - } - /* Passendes Feld */ - for(i=0;i<9;i++) { - for(j=0;j<9;j++) { - if( s->belegung[i][j] == l && s->feld[i][j] == zahl ) { - fprintf(stderr,"Tried z=%d, sp=%d, zahl=%d, l=%d, i=%d, j=%d but it failed!\n",z,sp,zahl,l,i,j); - return 0; - } - } - } - return 1; -} - -int s_loes_track(sudoku * s, int pos) { - int i,x=pos/9,y=pos%9; - if(pos == 81) return 1; - if(s->feld[x][y] != 0) { - return s_loes_track(s,pos+1); - }else{ - for(i=1;i<=9;i++) { - if(s->mgl[x][y][i-1] != 1 && s_test(s,x,y,i) == 1) { - s->feld[x][y] = i; - if(s_loes_track(s,pos+1) == 1) { - return 1; - } - } - } - } - s->feld[x][y] = 0; - return 0; -} - -int s_write(char* fn,sudoku* s) { - /* Sudoku in Datei schreiben */ - int i,j; - FILE * fp = fopen(fn,"w"); - if(fp == NULL) return 0; - printf("Schreibe in Datei `%s'...\n",fn); - for(i=0;i<9;i++) { - for(j=0;j<9;j++) { - fputc(s->feld[i][j]+48,fp); - } - fputc( 10, fp); - } - fclose(fp); - return 1; -} - -int s_write_error(char* fn,int err) { - /* Fehler in Datei schreiben */ - FILE * fp = fopen(fn,"w+"); - if(fp == NULL) return 0; - printf("Schreibe Fehler in Datei `%s'...\n",fn); - switch(err) { - case 0: - fputs("Eingabefehler\nEingabedatei ist Fehlerhaft!\n",fp); - break; - case 1: - fputs("Eingabefehler\nSudoku ist nicht Loesbar! (Kein Loeseversuch)\n",fp); - break; - case 2: - fputs("Eingabefehler\nSudoku ist nicht Loesbar!\n",fp); - break; - default: - fputs("Eingabefehler\n",fp); - } - fclose(fp); - return 1; -} - -void sl_set_num(sudoku* s,int zahl,int z, int sp) { - int l = s->belegung[z][sp] , i, j; - zahl--; - for(i=0;i<9;i++) { - s->mgl[z][sp][i] = 1; /* Zelle sperren */ - s->mgl[z][i][zahl] = 1; /* Spalte austragen */ - s->mgl[i][sp][zahl] = 1; /* Zeile austragen */ - } - /* Block austragen */ - for(i=0;i<9;i++) - for(j=0;j<9;j++) - if(s->belegung[i][j] == l) - s->mgl[i][j][zahl] = 1; -} - -int sl_check_nums(sudoku* s,int zahl,int z, int sp) { - int l = s->belegung[z][sp] , i, j, sum=0; - zahl--; - if(s->mgl[z][sp][zahl] == 1) return 0; - /* Spalte pruefen */ - for(i=0;i<9;i++) - if(s->mgl[z][i][zahl] != 1 && i!=sp) { sum=1; break; } - if(sum==0) return 1; - /* Zeile pruefen */ - sum = 0; - for(i=0;i<9;i++) - if(s->mgl[i][sp][zahl] != 1 && i!=z) { sum=1; break; } - if(sum==0) return 1; - /* Block pruefen */ - sum=0; - for(i=0;i<9;i++) - for(j=0;j<9;j++) - if( s->belegung[i][j] == l && s->mgl[i][j][zahl] != 1 && !(i == z && j == sp)) { - sum=1; break; - } - if(sum==0) return 1; - return 0; -} - -int sl_loes(sudoku* s) { - int z,sp,repl=1,zahl; - while(repl) { - repl = 0; - for(z=0;z<9;z++) { - for(sp=0;sp<9;sp++) { - for(zahl=1;zahl<=9;zahl++) { - if(s->mgl[z][sp][zahl-1] != 1 && s->vorgabe[z][sp] == 0 && s->feld[z][sp] == 0 && sl_check_nums(s,zahl,z,sp) == 1) { - s->feld[z][sp] = zahl; - s->vorgabe[z][sp] = 2; - sl_set_num(s,zahl,z,sp); - s->notnull--; - repl = 1; - } - } - } - } - } - if(s->notnull != 0) return 0; - return 1; -} diff --git a/todo.txt b/todo.txt new file mode 100644 index 0000000..1b4bf12 --- /dev/null +++ b/todo.txt @@ -0,0 +1 @@ +- HTML-Output diff --git a/types.h b/types.h new file mode 100644 index 0000000..9a53870 --- /dev/null +++ b/types.h @@ -0,0 +1,28 @@ +#ifndef types_h__ +#define types_h__ + +typedef struct sudoku { + char feld[9][9]; /* Feld mit den Zahlen */ + char vorgabe[9][9]; /* Fuer Farbige Ausgabe auf der Linuxkonsole benoetigt */ + char belegung[9][9]; /* Die Vorgegebenen Felder */ + char mgl[9][9][9]; /* Moegliche Zahlen (fuer Logik); 0=moeglich; 1=nicht moeglich; !! */ + char notnull; /* Anzahl der verbleibenden leeren zellen, nur fuer logik */ +} sudoku; + +typedef struct options { + char unicode; /* Unicode output */ + char color; /* Show colors */ + char plaintext; /* Same format as the input */ + char silent; /* just output the result */ + char html; /* output html (implies silent) */ + char solve; /* solve it or not */ + char* outfile; /* outfile NULL if none */ + char* overlay; /* overlay NULL if none */ + char* infile; /* input file with the sudoku */ + int (*check_nums)(sudoku*,int,int,int); + void (*set_num)(sudoku*,int,int,int); + int (*test)(sudoku*,int,int,int); + void (*ausgabe)(sudoku*,int); +} options; + +#endif /* types_h__ */ \ No newline at end of file