* ------------------------------------------------------------------------ * Create the array and make each element contain the string "123456789" * GBArray = Game Board Array * ------------------------------------------------------------------------ clear dimension GBArray(9, 9) GBArray = "123456789" * ------------------------------------------------------------------------ * Now we'll place the known numbers in the array. Position 1,1 is at the * upper left and position 9,9 is at the lower right. This is done manually, * but could be done visually on a form without much difficulty. * See the code at the bottom of this file for another puzzle. * ------------------------------------------------------------------------ GBArray(1, 3) = "1" GBArray(2, 2) = "5" GBArray(3, 1) = "2" GBArray(4, 3) = "7" GBArray(5, 2) = "4" GBArray(6, 3) = "2" GBArray(7, 1) = "1" GBArray(8, 2) = "2" GBArray(9, 3) = "8" *---- GBArray(2, 5) = "6" GBArray(3, 4) = "8" GBArray(3, 6) = "5" GBArray(4, 5) = "8" GBArray(5, 4) = "6" GBArray(5, 6) = "1" GBArray(6, 5) = "7" GBArray(7, 4) = "7" GBArray(7, 6) = "2" GBArray(8, 5) = "9" *--- GBArray(1, 7) = "9" GBArray(2, 8) = "2" GBArray(3, 9) = "3" GBArray(4, 7) = "4" GBArray(5, 8) = "7" GBArray(6, 7) = "8" GBArray(7, 9) = "5" GBArray(8, 8) = "6" GBArray(9, 7) = "2" * ------------------------------------------------------------------------ * This first loop will remove the starting numbers within each 3x3 block * from the list of possible numbers in each of the remaining positions * in that block. The outer 1 to 7 loops help us find the upper left corner * of each 3x3 grid. rb = row base, cb = column base. * ------------------------------------------------------------------------ for rb = 1 to 7 step 3 for cb = 1 to 7 step 3 DisallowedStr = "" * ------------------------------------------------------------------ * This section processes a 3x3 grid, determining which numbers are * prefilled and adding them to the DisallowedStr variable. * ------------------------------------------------------------------ for i = 0 to 2 for j = 0 to 2 r = rb + i c = cb + j * ------------------------------------------------------------ * When the length of the contents of the element is one, then * know we have a prefilled in starting number. We'll add this * number to the DisallowedStr variable. * ------------------------------------------------------------ if len(GBArray(r, c)) = 1 DisallowedStr = DisallowedStr + GBArray(r, c) endif endfor endfor * ------------------------------------------------------------------ * This section processes the same 3x3 grid just processed above and * removes any number in the DisallowedStr and replaces it with and "x" * You may want to read the VFP help text on CHRTRAN, it's not something * I use too much, but it is helpful here. * ------------------------------------------------------------------ for i = 0 to 2 for j = 0 to 2 r = rb + i c = cb + j * ------------------------------------------------------------ * When the length of the contents of the element greater than * one, then know we have an empty cell (represented by a string * of numbers that could possibly be placed into that cell). * We have to remove disallowed number (numbers that are already * placed on the board). * ------------------------------------------------------------ if len(GBArray(r, c)) > 1 GBArray(r, c) = chrtran(GBArray(r, c), DisallowedStr, replicate("x", len(DisallowedStr))) endif endfor endfor endfor endfor * ------------------------------------------------------------------------ * This loop will look at each row and remove the starting numbers in that * row from the list of possible numbers in each of the remaining positions * in that row. * ------------------------------------------------------------------------ for r = 1 to 9 DisallowedStr = "" for c = 1 to 9 if len(GBArray(r, c)) = 1 DisallowedStr = DisallowedStr + GBArray(r, c) endif endfor for c = 1 to 9 if len(GBArray(r, c)) > 1 GBArray(r, c) = chrtran(GBArray(r, c), DisallowedStr, replicate("x", len(DisallowedStr))) endif endfor endfor * ------------------------------------------------------------------------ * This loop will look at each column and remove the starting numbers in that * column from the list of possible numbers in each of the remaining positions * in that column. * ------------------------------------------------------------------------ for c = 1 to 9 DisallowedStr = "" for r = 1 to 9 if len(GBArray(r, c)) = 1 DisallowedStr = DisallowedStr + GBArray(r, c) endif endfor for r = 1 to 9 if len(GBArray(r, c)) > 1 GBArray(r, c) = chrtran(GBArray(r, c), DisallowedStr, replicate("x", len(DisallowedStr))) endif endfor endfor * ------------------------------------------------------------------------ * This loop puts a "Z" in front of the initial numbers so we know they were * initial numbers. * ------------------------------------------------------------------------ for r = 1 to 9 for c = 1 to 9 if len(GBArray(r, c)) = 1 GBArray(r, c) = "Z" + GBArray(r, c) endif endfor endfor Done = .f. do while not Done ChgdCount = 0 * --------------------------------------------------------------------- * Find squares with only one number still in the allowed numbers list and * convert that square to that number. We'll stay in the loop as long as * we've done at least one conversion. * --------------------------------------------------------------------- for r = 1 to 9 for c = 1 to 9 * --------------------------------------------------------------- * If "x" occurs 8 times in the array element, then we've narrowed * this cell down to only one possible choice. We'll replace it * with a "Z" plus whatever the number is. So "xx3xxxxxx" would be * changed to "Z3" (as in the car!). * --------------------------------------------------------------- if occurs("x", GBArray(r, c)) = 8 Num = chrtran(GBArray(r, c), "x", "") GBArray(r, c) = "Z" + Num * ------------------------------------------------------------ * We've just determined that element r,c had just one * choice left (meaning that choice must go in cell r,c). * Now we need to process each column of the current row and * see if Num was a possibility in that column of the current * row (if it was, it isn't anymore and we have to remove it). * ------------------------------------------------------------ for x = 1 to 9 if between(occurs("x", GBArray(r, x)), 1, 7) GBArray(r, x) = chrtran(GBArray(r, x), Num, "x") ChgdCount = ChgdCount + 1 endif endfor * ------------------------------------------------------------ * Now we process each row of the current column and see if * Num was a possibility in that row of the current column. * Again, if it was, it isn't anymore and we have to remove it. * ------------------------------------------------------------ for x = 1 to 9 if between(occurs("x", GBArray(x, c)), 1, 7) GBArray(x, c) = chrtran(GBArray(x, c), Num, "x") ChgdCount = ChgdCount + 1 endif endfor endif endfor endfor * --------------------------------------------------------------------- * Check rows for squares with only one possibility. * --------------------------------------------------------------------- for r = 1 to 9 TempStr = replicate("0", 9) for c = 1 to 9 * --------------------------------------------------------------- * We now need to see if any particular number is a choice in only * one cell. Each cell contains a string such as "xx34xx7x9". * This means that in that cell, 3, 4, 7, and 9 are still possible * solutions. We run through each cell and see how many times a * number appears. Any number that appears only once is the solution * for that cell. For instance, if a cell contains "xx34xx7x9" and * another contains "xxx4xx7x9", then "3" is used only once and must * be the solution for that cell (this is simplified, we're actually * comparing 9 cells). The resulting string would be something like * "023040013" which would mean 2 is used twice, 3 is used three times * 5 is used four times, 8 is used once, and nine is used three times. * So 8 is the solution for the cell it resides in. * --------------------------------------------------------------- if "x" $ GBArray(r, c) for x = 1 to 9 if substr(GBArray(r, c), x, 1) <> "x" TempStr = stuff(TempStr, x, 1, transform(val(substr(TempStr, x, 1)) + 1)) endif endfor endif endfor * ------------------------------------------------------------------ * Get the number that is used in only one cell, meaning it is a solution * for the cell it's used in. * ------------------------------------------------------------------ Num = at("1", TempStr) if Num > 0 Num = transform(Num) * --------------------------------------------------------------- * Now let's find the cell that the number was used in. Since it * is used in just one cell, the first cell we find it in is the * only cell it will appear in. * --------------------------------------------------------------- for x = 1 to 9 if Num $ GBArray(r, x) c = x GBArray(r, x) = "Z" + Num * --------------------------------------------------------- * Since the solution was made for a cell, it can't be used * anywhere else in the current column, so we'll have to * remove it as a possible choice in all the other cells * of the column. * --------------------------------------------------------- for x = 1 to 9 if between(occurs("x", GBArray(x, c)), 1, 7) GBArray(x, c) = chrtran(GBArray(x, c), Num, "x") ChgdCount = ChgdCount + 1 endif endfor exit && And now we bail out, since the solution was placed into the cell. endif endfor endif endfor * ------------------------------------------------------------------------ * Check columns for squares with only one possibility. * This is very similar to the code above, but it's just done for the * columns instead of the cells. * ------------------------------------------------------------------------ for c = 1 to 9 TempStr = replicate("0", 9) for r = 1 to 9 if "x" $ GBArray(r, c) for x = 1 to 9 if substr(GBArray(r, c), x, 1) <> "x" TempStr = stuff(TempStr, x, 1, transform(val(substr(TempStr, x, 1)) + 1)) endif endfor endif endfor Num = at("1", TempStr) if Num > 0 Num = transform(Num) for x = 1 to 9 if Num $ GBArray(x, c) r = x GBArray(x, c) = "Z" + Num for x = 1 to 9 if between(occurs("x", GBArray(r, x)), 1, 7) GBArray(r, x) = chrtran(GBArray(r, x), Num, "x") ChgdCount = ChgdCount + 1 endif endfor exit endif endfor endif endfor set step on * ------------------------------------------------------------------------ * This section of code will examine each 3x3 subsection of the sudoku * board, look for cells that have already been solved, and put those * numbers in a list (a string). It will then look at all the cells * that have have not been solved and remove the already used numbers * from the list of numbers that may possibly solve an unsolved cell. * ------------------------------------------------------------------------ for rb = 1 to 7 step 3 for cb = 1 to 7 step 3 TempStr = replicate("0", 9) UsedNums = "" for i = 0 to 2 for j = 0 to 2 r = rb + i c = cb + j if "Z" $ GBArray(r, c) UsedNums = UsedNums + right(GBArray(r, c), 1) endif endfor endfor LenUsedNums = len(UsedNums) if LenUsedNums > 0 for i = 0 to 2 for j = 0 to 2 r = rb + i c = cb + j if "x" $ GBArray(r, c) OrigVal = GBArray(r, c) GBArray(r, c) = chrtran(GBArray(r, c), UsedNums, replicate("x", LenUsedNums)) if GBArray(r, c) <> OrigVal ChgdCount = ChgdCount + 1 endif endif endfor endfor endif endfor endfor Done = ChgdCount = 0 enddo CompletedCount = 0 * ------------------------------------------------------------------------ * Draw the game board on the screen * ------------------------------------------------------------------------ for r = 1 to 9 for c = 1 to 9 ?? padr(substr(GBArray(r, c), 2), 10) if "Z" $ GBArray(r, c) CompletedCount = CompletedCount + 1 endif endfor ? endfor ? ? "CompletedCount = " + transform(CompletedCount) * ------------------------------------------------------------------------ * This is the puzzle from page C1 of the today's AJC (10/1/2005). * It's level of difficulty is low. Use it to replace the code at the * top of the program in order to try another puzzle. * ------------------------------------------------------------------------ *!* GBArray(1, 2) = "4" *!* GBArray(1, 3) = "7" *!* GBArray(2, 2) = "5" *!* GBArray(3, 3) = "8" *!* GBArray(4, 1) = "1" *!* GBArray(4, 2) = "2" *!* GBArray(5, 1) = "7" *!* GBArray(5, 3) = "5" *!* GBArray(6, 1) = "3" *!* GBArray(7, 2) = "1" *!* GBArray(7, 3) = "2" *!* GBArray(8, 3) = "9" *!* GBArray(9, 1) = "4" *!* *---- *!* GBArray(1, 4) = "3" *!* GBArray(1, 5) = "5" *!* GBArray(2, 4) = "8" *!* GBArray(2, 6) = "9" *!* GBArray(3, 4) = "4" *!* GBArray(4, 4) = "5" *!* GBArray(4, 5) = "7" *!* GBArray(6, 5) = "8" *!* GBArray(6, 6) = "2" *!* GBArray(7, 6) = "5" *!* GBArray(8, 4) = "2" *!* GBArray(8, 6) = "6" *!* GBArray(9, 5) = "1" *!* GBArray(9, 6) = "8" *!* *--- *!* GBArray(1, 9) = "9" *!* GBArray(2, 7) = "3" *!* GBArray(3, 7) = "1" *!* GBArray(3, 8) = "2" *!* GBArray(4, 9) = "8" *!* GBArray(5, 7) = "2" *!* GBArray(5, 9) = "6" *!* GBArray(6, 8) = "1" *!* GBArray(6, 9) = "7" *!* GBArray(7, 7) = "9" *!* GBArray(8, 8) = "4" *!* GBArray(9, 7) = "7" *!* GBArray(9, 8) = "5"Now some explanatory text (note that some of the "diagrams" are not displaying properly here on the UT, even with the user of the PRE tag):
1 2 3 4 5 6 7 8 9 ------------------------------------- 1 | 1 | | 9 | 2 | 5 | 6 | 2 | 3 | 2 | 8 5 | 3 | ------------------------------------- 4 | 7 | 8 | 4 | 5 | 4 | 6 1 | 7 | 6 | 2 | 7 | 8 | ------------------------------------- 7 | 1 | 7 2 | 5 | 8 | 2 | 9 | 6 | 9 | 8 | | 2 | -------------------------------------I represented this via an array called GBArray (Game Board Array). To start out with, each element of the array contains string like this: "123456789"
1 2 3 1 123456789 123456789 123456789 2 123456789 123456789 123456789 3 123456789 123456789 123456789I'm only showing one 3x3 section, but the array is filled out to 9x9, of course. After this initial creation and population of the array, I immediately place the known values (the numbers that are filled in for us at the start of the game) in their proper locations, so the first 3x3 section now looks like this:
1 2 3 1 123456789 123456789 1 2 123456789 5 123456789 3 2 123456789 123456789This represents the possible numbers at each grid location. At row 1, column 3 (1,3) we know that 1 is the only value we can have and at 2,2 we know 5 is the only value we can have and at 3,1 we know 2 is the only value we can have. At the other locations our possible values are (at this point in the explanation at least) 1 through 9.
1 2 3 1 xx34x6789 xx34x6789 1 2 xx34x6789 5 xx34x6789 3 2 xx34x6789 xx34x6789This tells us that at the positions where we don't have a prefilled number, our choices of numbers to use are 3, 4, 6, 7, 8, or 9. As you can probably tell, I'm using a process of elimination to whittle our choices down until we have a solution. (Remember, the cells with "xx34x6789" in them are actually empty on the game board - "xx34x6789" represents that numbers that could go there.)
1 2 3 1 xx34x6789 xx3xx6789 1 2 xx34x6789 5 xx34x6789 3 2 xx3xx6789 xx34x6789Column three can be processed in the same manner, removing 7 and 8 as possibilities, and our grid would then look like this:
1 2 3 1 xx34x6789 xx3xx6789 1 2 xx34x6789 5 xx34x6xx9 3 2 xx3xx6789 xx34x6xx9You can find the code that processes the rows and columns (I actually did rows first, not columns) and continues to whittle down our choices for each of the empty cells). Hopefully, the comments in the code will help you figure out that code.