Saturday, July 21, 2012

I was bored, so I wrote a Sudoku Solver

My Dad wrote a Sudoku solver that works in Excel . It's slow. I was discussing with him how he built it and I starting thinking how I would build one.

So I did. And it's messy. But it works!


It's messy, it's not a release, and the comments suck... but it works! (now, someone give me a puzzle that breaks it!

ToDo:
1: Better Input System
2: Better Debug Logging
3: Suggestions?


http://www.mediafire.com/?mg9elrhbwkb63om

1:  #include <iostream>  
2:  #include "math.h"  
3:  #include <string>  
4:  using namespace std;  
5:  bool Debug = 0;  
6:  char abs(char x) //GCC is missing a char abs(char) function... wrote this as an after thought.  
7:  {  
8:    if( x < 0)  
9:    {  
10:      return (0-x);  
11:    }  
12:    else return x;  
13:  }  
14:  class puzzle  
15:  {  
16:       char PuzzleValues[9][9];  
17:       unsigned short sets[3][9];  
18:  public:  
19:       int updateSets() //returns number of changes. return system could be faster if integrated into  
20:       {  
21:            puzzle temp = *this;  
22:            //horizontal sets  
23:            for(int y = 0; y < 9 ; y++)  
24:            {  
25:                 sets[0][y] = 0;  
26:                 for(int x = 0; x < 9 ; x++)  
27:                 {  
28:                      if( GetValue(y,x) != 0 )  
29:                      {  
30:                           sets[0][y] += ((1 << (abs(GetValue(y,x))-1)) );  
31:                      }  
32:                 }  
33:            }  
34:            //vertical sets  
35:            for(int x = 0; x < 9 ; x++)  
36:            {  
37:                 sets[1][x] = 0;  
38:                 for(int y = 0; y < 9 ; y++)  
39:                 {  
40:                      if( GetValue(y,x) != 0 )  
41:                      {  
42:                           sets[1][x] += ( (1 << (abs(GetValue(y,x))-1)) );  
43:                      }  
44:                 }  
45:            }  
46:            //box sets  
47:            for(int group = 0; group < 9 ; group++)  
48:            {  
49:                 sets[2][group] = 0;  
50:                 for(int cell = 0; cell < 9; cell++)  
51:                 {  
52:                      int x = (3*(group%3)+cell%3);  
53:                      int y = (3*(group/3)+cell/3);  
54:                      if( GetValue(y,x) != 0 )  
55:                      {  
56:                           sets[2][group] += ( (1 << (abs(GetValue(y,x))-1)) );  
57:                      }  
58:                 }  
59:            }  
60:            int changes = 0;  
61:            for(int loop = 0; loop < 27 ; loop++ )  
62:            {  
63:                 if( sets[loop/9][loop%9] != temp.sets[loop/9][loop%9] )  
64:                 {  
65:                      changes++;  
66:                 }  
67:            }  
68:            return changes;  
69:       }  
70:       /*Objects of pointers are set to CELL Sets and Ranks, returns 0 for success, 1 or 3 for failed Set Pointer, 2 or 3 for failed RankPointer*/  
71:       short cellSet( int y , int x , short* Rank )  
72:       {  
73:            if( !PuzzleValues[y][x] )  
74:            {  
75:                 short Set = 0;  
76:                 short Temp;  
77:                 Temp = ( (short)  
78:                      0x1ff - //4: then take 1 1111 1111 and subtract the row ORs from that  
79:                      (  
80:                      sets[0][y] | //1: check first row  
81:                      sets[1][x] | //2: OR that with 2nd row  
82:                      sets[2][(x/3)+(y - (y % 3 ))] //3: OR that with 3rd row to for the list of numbers that are close to a number  
83:                 )  
84:                      );  
85:                 Set = Temp;  
86:                 if(Rank != NULL )  
87:                 {  
88:                      short count = 0 ;  
89:                      while (Temp) //count the number of 1s in Temp  
90:                      {  
91:                           count++;  
92:                           Temp &= (Temp - 1) ;  
93:                      }  
94:                      *Rank = count;  
95:                 }  
96:                 return Set;  
97:            }  
98:            else  
99:            {  
100:                 if(Rank != NULL)  
101:                 {  
102:                      *Rank = 0;  
103:                 }  
104:                 return 0;  
105:            }  
106:       }  
107:       //returns value at point, negitive for orignal puzzle  
108:       char GetValue( int y, int x )  
109:       {  
110:            return PuzzleValues[y][x];  
111:       }  
112:       //pass negitive VALUE for orignal puzzle  
113:       int SetValue( int y, int x, char VALUE /*-9 to 9*/ )  
114:       {  
115:            if( -9 <= VALUE && VALUE <= 9 )  
116:            {  
117:                 PuzzleValues[y][x] = VALUE;  
118:                 return 1;  
119:            }  
120:            else return 0;  
121:       }  
122:       //display the table. build a better table with ascii lines  
123:       string Display()  
124:       {  
125:            string OUTPUT;  
126:            for( int y = 0 ; y < 9 ; y++)  
127:            {  
128:                 if( !(y%3))  
129:                 {  
130:                      OUTPUT += "+---------+---------+---------+\n";  
131:                 }  
132:                 for( int x = 0 ; x < 9 ; x++)  
133:                 {  
134:                      if( !(x%3) )  
135:                      {  
136:                           OUTPUT += "|";  
137:                      }  
138:                      if( 1 <= GetValue(y,x) && GetValue(y,x) <= 9 )  
139:                      {  
140:                           OUTPUT += ' ';  
141:                           OUTPUT += (GetValue(y,x) + 48);  
142:                           OUTPUT += ' ';  
143:                      }  
144:                      else if( -9 <= GetValue(y,x) && GetValue(y,x) <= -1 )  
145:                      {  
146:                           OUTPUT += '{';  
147:                           OUTPUT += (( 0 - GetValue(y,x) ) + 48 );  
148:                           OUTPUT += '}';  
149:                      }  
150:                      else  
151:                      {  
152:                           OUTPUT += "  ";  
153:                      }  
154:                 }  
155:                 OUTPUT += "|\n";  
156:            }  
157:            OUTPUT += "+---------+---------+---------+\n";  
158:            return OUTPUT;  
159:       }  
160:       //fills cells currently at rank1 that aren't full. returns number of changes  
161:       int fillCells()  
162:       {  
163:            int changes = 0;  
164:            //int CellInfluance[9][9];  
165:            for ( int x = 0; x < 9 ; x++ )  
166:            {  
167:                 for ( int y = 0; y < 9 ; y++ )  
168:                 {  
169:                      //////should be replaced with the new fuction that does this for you.  
170:                      //finds the binary list of 1 to 9 that are there.  
171:                      int q = 0x1ff - ( //4: then take 1 1111 1111 and subtract the row ORs from that  
172:                           sets[0][y] | //1: check first row  
173:                           sets[1][x] | //2: OR that with 2nd row  
174:                           sets[2][(x/3)+(y - (y % 3 ))] //3: OR that with 3rd row to for the list of numbers that are close to a number  
175:                      );  
176:                      //if power of 2, then return  
177:                      for ( int p = 0 ; p < 9 ; p++ )  
178:                      {  
179:                           //reworked with previusly mentioned relacement  
180:                           if(q == (1 << p) && GetValue( y , x ) == 0)  
181:                           {  
182:                                SetValue( y , x , (p+1) );  
183:                                changes++;  
184:                           }  
185:                      }  
186:                 }  
187:            }  
188:            return changes;  
189:       }  
190:       int Solved()  
191:       {  
192:            for(int x = 0 ; x < 81 ; x++)  
193:            {  
194:                 if( !GetValue( x/9 , x%9 ) )  
195:                      return 0;  
196:            }  
197:            return 1;  
198:       }  
199:       int unSolveable() //returns 0 if puzzle is unsolveable, 1 if it might be solveable  
200:       {  
201:            for(int x = 0 ; x < 81 ; x++)  
202:            {  
203:                 if( !GetValue( x/9 , x%9 ) && !cellSet( x/9 , x%9 , NULL ) )  
204:                 {  
205:                      return 1;  
206:                 }  
207:            }  
208:            return 0;  
209:       }  
210:  };  
211:  int Solve(puzzle *inPuzzle)  
212:  {  
213:       puzzle WCopy = *inPuzzle;  
214:       do  
215:       {  
216:            if( Debug == 1){  
217:                 cout << WCopy.Display();  
218:            }  
219:            WCopy.updateSets();  
220:       } while( WCopy.fillCells() );  
221:       if( Debug == 1){  
222:            cout << WCopy.Display();  
223:       }  
224:       if( !WCopy.Solved() )  
225:       {  
226:            if( !WCopy.unSolveable() )  
227:            {  
228:                 if( Debug == 1){  
229:                      cout << WCopy.Display();  
230:                 }  
231:                 short LowestRank = 10;  
232:                 short LowestSet;  
233:                 char LowestRankX;  
234:                 char LowestRankY;  
235:                 //for loop that finds first lowest rank  
236:                 for(char y = 0 ; y < 9 ; y++ )  
237:                 {  
238:                      for (char x = 0; x < 9 ; x++ )  
239:                      {  
240:                           short RANK = 0;  
241:                           short SET = WCopy.cellSet( y , x , &RANK );  
242:                           if( RANK != 0 && RANK < LowestRank && !WCopy.GetValue(y, x))  
243:                           {  
244:                                LowestRank = RANK;  
245:                                LowestSet = SET;  
246:                                LowestRankX = x;  
247:                                LowestRankY = y;  
248:                           }  
249:                      }  
250:                 }  
251:                 //loop that guesses values out of that xy rank  
252:                 for( short Guess = 0 ; Guess < 9 ; Guess++ )  
253:                 {  
254:                      if( (1 << Guess) & LowestSet )  
255:                      {  
256:                           puzzle GuessCopy = WCopy; //make a copy  
257:                           GuessCopy.SetValue( LowestRankY , LowestRankX , Guess + 1 ); //dump guess into the copy  
258:                           if( Debug == 1){  
259:                                cout << WCopy.Display();  
260:                           }  
261:                           if( Solve( &GuessCopy ) )  
262:                           {  
263:                                if( Debug == 1){  
264:                                     cout << WCopy.Display();  
265:                                }  
266:                                *inPuzzle = WCopy = GuessCopy;  
267:                                return 1;  
268:                           }  
269:                      }  
270:                 }  
271:                 return 0;  
272:                 //if one guess wins, "*inPuzzle = WCopy;" and return 1  
273:                 //if a guess fails, try next  
274:                 //if all guesses fail, return 0;  
275:            }  
276:            else  
277:                 return 0;  
278:       }  
279:       else  
280:       {  
281:            if( inPuzzle != NULL )  
282:                 *inPuzzle = WCopy;  
283:            return 1;  
284:       }  
285:  }  
286:  int main(int argc, char *argv[])  
287:  {  
288:       string Input;  
289:       if(argc <= 1)  
290:       {  
291:            cout << "ERROR!, you're doing it wrong... Imma put more detal here later... \n" <<  
292:                 "OR I could just solve a puzzle for you! How's that sound!?\n" <<  
293:                 "how about this hard one! =D\n";  
294:            Input = "86..2.......7...59.............6.8...4.........53....7..........2....6....75.9..."; //hard puzzle  
295:            Debug = 0;  
296:       }  
297:       if(argc > 1)  
298:       {  
299:            Input = argv[1];  
300:       }  
301:       if(argc > 2)  
302:       {  
303:  //          char test =  
304:            Debug = ( *argv[2] - '0');  
305:       }  
306:       //system("mode con cols=82");  
307:       puzzle MainPuzzle;  
308:       //     Input = "86..2.......7...59.............6.8...4.........53....7..........2....6....75.9..."; //hard puzzle  
309:       //     Input = ".931.564.7.......55.12.93.72.......3.369.752.9.......13.24.81.96.......4.473.285."; //easy puzzle  
310:       //     Input = ".3..........28.1.7.78.6.4.....8.2.7..82...54..9.5.4.....1.7.25.8.6.21..........8."; //mid puzzle  
311:       cout << "starting input:\n" << Input << "\nstarting puzzle:\n";  
312:       for(int y = 0; y < 9 ; y++ )  
313:       {  
314:            for(int x = 0; x < 9 ; x++ )  
315:            {  
316:                 cout << Input[y*9 + x];  
317:                 char q = Input[ 9 * y + x ];  
318:                 if( q != '.' )  
319:                 {  
320:                      MainPuzzle.SetValue( y , x , 0 - (q - 48) );  
321:                 }  
322:                 else  
323:                 {  
324:                      MainPuzzle.SetValue( y , x , 0 );  
325:                 }  
326:            }  
327:            cout << '\n';  
328:       }  
329:       cout << MainPuzzle.Display();  
330:       Solve( &MainPuzzle );  
331:       cout << "\n\nDERP!\n\n";  
332:       cout << MainPuzzle.Display();  
333:       //MainPuzzle.updateSets();  
334:       //short CellSets[2][9][9];  
335:       //bool run = true;  
336:       //while( run )  
337:       //{  
338:       //     MainPuzzle.updateSets();  
339:       //     while(MainPuzzle.fillCells() )  
340:       //     {  
341:       //          MainPuzzle.updateSets();  
342:       //          cout << '\n' << MainPuzzle.Display();  
343:       //     }  
344:       //     for( int x = 0; x < 81 ; x++)  
345:       //     {  
346:       //          short q; //rack  
347:       //          short p; //sets  
348:       //          p = MainPuzzle.cellSet( x%9 , x/9 , &q );  
349:       //          CellSets[0][x/9][x%9] = q;  
350:       //          CellSets[1][x/9][x%9] = p;  
351:       //     }  
352:       //     run = true;  
353:       //  
354:       //}  
355:  //     system( "pause" ); //works only Visual Studio compiler.  
356:  }