From f38c6142cf01daefe534474cace076136b8ac29f Mon Sep 17 00:00:00 2001 From: Thomas Battermann Date: Tue, 22 Mar 2011 08:12:53 +0100 Subject: [PATCH] Init --- example/sudoku_1.txt | 9 ++ example/sudoku_2.txt | 9 ++ example/sudoku_3.txt | 9 ++ makefile | 8 + sudokuloeser.c | 353 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 388 insertions(+) create mode 100644 example/sudoku_1.txt create mode 100644 example/sudoku_2.txt create mode 100644 example/sudoku_3.txt create mode 100644 makefile create mode 100644 sudokuloeser.c diff --git a/example/sudoku_1.txt b/example/sudoku_1.txt new file mode 100644 index 0000000..4099acd --- /dev/null +++ b/example/sudoku_1.txt @@ -0,0 +1,9 @@ +08010405 +700000012 +0036 +300450007 + +600039005 +0000052 +03080209 +170000008 \ No newline at end of file diff --git a/example/sudoku_2.txt b/example/sudoku_2.txt new file mode 100644 index 0000000..760a965 --- /dev/null +++ b/example/sudoku_2.txt @@ -0,0 +1,9 @@ +060000000 +700050010 +380000007 +000000700 +000000006 +005900000 +002000090 +000007004 +000036000 \ No newline at end of file diff --git a/example/sudoku_3.txt b/example/sudoku_3.txt new file mode 100644 index 0000000..c99399a --- /dev/null +++ b/example/sudoku_3.txt @@ -0,0 +1,9 @@ + 51 + 1 5 + 4 + 6 + 8 3 + 9 1 + 7 + 76 53 +1 49 6 \ No newline at end of file diff --git a/makefile b/makefile new file mode 100644 index 0000000..2f4e314 --- /dev/null +++ b/makefile @@ -0,0 +1,8 @@ +sudokuloeser: sudokuloeser.c + gcc -Wall -pedantic -lrt sudokuloeser.c -o sudokuloeser + +windows: sudokuloeser.c + i486-mingw32-gcc -Wall -pedantic sudokuloeser.c -o sudokuloeser.exe + +win: sudokuloeser.c + i586-mingw32msvc-gcc -Wall -pedantic sudokuloeser.c -o sudokuloeser.exe diff --git a/sudokuloeser.c b/sudokuloeser.c new file mode 100644 index 0000000..048b2cf --- /dev/null +++ b/sudokuloeser.c @@ -0,0 +1,353 @@ +/* + * 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 +#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*); /* Auf dem bildschirm ausgeben */ + 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 + +int main(int argc, char **argv) { + sudoku s={ {{0}}, {{0}}, {{{1}}}, 81 }; + int st=0,sl=0,ret=0; +#ifdef linux + struct timespec ts,te,l_ts,l_te; + long double t; + clock_gettime(CLOCK_REALTIME, &ts); +#endif + /* Hilfe ausgeben, wenn angefordert oder zuwenig Parameter */ + if(argc < 2 || strcmp(argv[1],"-h") == 0 || strcmp(argv[1],"--help") == 0) { + print_help(argc,argv); + exit(0); + } + /* Aus Datei einlesen und Fehler auswerten */ + st = s_einlesen(argv[1],&s); + if(st == 0) { + fprintf(stderr,"Ungueltiges Dateiformat!\n"); + s_write_error( (argc == 3) ? argv[2] : "sudoku_geloest.txt",0 ); + return 2; + }else if(st == -1) { + #ifdef linux + fprintf(stderr,"\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n\n"); + #else + fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n\n"); + #endif + s_write_error( (argc == 3) ? argv[2] : "sudoku_geloest.txt",1 ); + return 1; + } + /* Sudoku Loesen, Loseung ausgeben und in Datei schreiben */ + printf("Suche...\nProbiere es mit Logik... "); +#ifdef linux + clock_gettime(CLOCK_REALTIME, &l_ts); +#endif + sl = sl_loes(&s); + if(sl != 1) { + printf("FAIL\nNun mit Backtracking... "); + sl = s_loes_track(&s,0); + printf("%s\n",(sl != 1 ? "FAIL" : "OK" )); + }else{ + printf("OK\n"); + } +#ifdef linux + clock_gettime(CLOCK_REALTIME, &l_te); +#endif + if(sl == 0) { + #ifdef linux + printf("\033[31;1mDas Sudoku ist nicht loesbar!!\033[0m\n"); + #else + fprintf(stderr,"Das Sudoku ist nicht loesbar!!\n"); + #endif + s_write_error( (argc == 3) ? argv[2] : "sudoku_geloest.txt",2 ); + ret = 1; + }else{ + #ifdef linux + printf("\033[32;1mLoesung gefunden:\033[0m\n\n"); + #else + printf("Loesung gefunden:\n\n"); + #endif + s_ausgabe(&s); + s_write( (argc == 3) ? argv[2] : "sudoku_geloest.txt",&s ); + } +#ifdef linux + 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_ausgabe(sudoku* s) { + 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("| "); +#ifdef linux + 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]); +#endif + + } + printf("|\n"); + } + printf("+-------+-------+-------+\n"); +} + +void print_help(int argc, char **argv) { +#ifdef linux + printf("\033[0;1mUsage:\033[0m\n"); + printf(" %s []\n",argv[0]); + 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 []\n\n",argv[0]); + 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; + 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; + 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; +}