Sudoku solver: Difference between revisions
Jump to navigation
Jump to search
(→Formula: new clearly better version that also works) |
(new version) |
||
Line 115: | Line 115: | ||
# Expand the missing index values of the Hypotheses table to create the full A. | # Expand the missing index values of the Hypotheses table to create the full A. | ||
# Take the sudoku data table and replace hypotheses with data, if available. | # Take the sudoku data table and replace hypotheses with data, if available. | ||
# Compare two | # Compare all two-cell pairs at once using matrices. | ||
## | ## Create matrices of all critical properties: SudRow, SudCol, SudArea, and Hypothesis. These are compared pairwise, two cells at a time. | ||
## Use rules to deduce if a pair is incompatible or not. | |||
## | ## Aggregate plausible hypotheses in the second cell across all plausible values in the first cell. This gives a set of hypotheses that are plausible in at least some conditions. | ||
## | ## Aggregate along the first cell: each second cell must be compatible with all other (first) cells. | ||
## Do not apply these rules if the first and second cells are the same. | |||
## | # Go through every row, column, and area and find hypotheses where there is exactly one cell where it is plausible. | ||
## Remove all other hypotheses from these cells. | |||
# Do steps 3 and 4 for five times, assuming that all hypotheses have been eliminated by then, if it is possible to eliminate them using these rules. | |||
# | # Take a user-defined list of cells for which a random sample from plausible hypotheses is taken. It would be elegant to do this stepwise, but for simplicity, let's do it at once. Therefore, the cells that the user selects is critical, and a wise user will not select cells where uncertainties are clearly interdependent. | ||
# | # Solve all sudokus that are created in the sampling. | ||
# | # If a sudoku results in cells with zero plausible hypotheses, remove that iteration. | ||
# | |||
# If a | |||
# Calculate the number of different solutions still plausible and print it. | # Calculate the number of different solutions still plausible and print it. | ||
# If the number is smaller than 100, print also the solutions. | # If the number is smaller than 100, print also the solutions. | ||
Line 187: | Line 185: | ||
<rcode variables="name:userdata|description:Enter sudoku as a string, with spaces in empty cells|type:text"> | <rcode variables="name:userdata|description:Enter sudoku as a string, with spaces in empty cells|type:text"> | ||
library(OpasnetUtils) | |||
hypotheses <- tidy(opbase.data("Op_en5817.hypotheses")) | |||
for(i in 1:3) { | |||
hypotheses[[i]] <- ifelse(hypotheses[[i]] == "", NA, as.integer(as.character(hypotheses[[i]]))) | |||
} | |||
hypotheses <- unique(fillna(hypotheses, marginals = c(1, 2, 3))) | |||
# Get the sudoku data | |||
# data <- tidy(opbase.data("Op_en5817.sudoku"), objname="data") | |||
# data$SudRow <- as.numeric(data$SudRow) | |||
# data$SudCol <- as.numeric(data$SudCol) | |||
# Maailman vaikein | # Maailman vaikein | ||
Line 252: | Line 265: | ||
" | " | ||
hypotheses <- data.frame( | hypotheses <- data.frame( | ||
Line 261: | Line 272: | ||
Result = TRUE | Result = TRUE | ||
) | ) | ||
SudMake <- function(hypotheses, data) { | SudMake <- function(hypotheses, data) { | ||
Line 299: | Line 295: | ||
} | } | ||
ykköskarsinta <- function(out2, condition) { | |||
valinta <- as.data.frame(as.table(tapply(out2$Result, out2[c("Hypothesis", condition)], sum) == 1)) # haetaan ehto-hypoteesikombinaatiot | valinta <- as.data.frame(as.table(tapply(out2$Result, out2[c("Hypothesis", condition)], sum) == 1)) # haetaan ehto-hypoteesikombinaatiot | ||
Line 307: | Line 301: | ||
valinta <- merge(valinta, out2) # yhdistetään SudCell-tietoon | valinta <- merge(valinta, out2) # yhdistetään SudCell-tietoon | ||
valinta <- valinta[valinta$Result , ] # poistetaan turhat | valinta <- valinta[valinta$Result , ] # poistetaan turhat | ||
#print(valinta$SudCell) | |||
out2[out2$SudCell %in% valinta$SudCell , ]$Result <- FALSE #hylätään aluksi kaikki hypoteesit ykkösruuduista | out2[out2$SudCell %in% valinta$SudCell , ]$Result <- FALSE #hylätään aluksi kaikki hypoteesit ykkösruuduista | ||
#print(paste(out2$Hypothesis, out2$SudCell) %in% paste(valinta$Hypothesis, valinta$SudCell)) | |||
out2[paste(out2$Hypothesis, out2$SudCell) %in% paste(valinta$Hypothesis, valinta$SudCell) , ]$Result <- TRUE # palautetaan oikea vastaus ykkösruutuihin | out2[paste(out2$Hypothesis, out2$SudCell) %in% paste(valinta$Hypothesis, valinta$SudCell) , ]$Result <- TRUE # palautetaan oikea vastaus ykkösruutuihin | ||
return(out2) | return(out2) | ||
} | } | ||
SudSolve <- function(sudoku, verbose = FALSE) { | |||
iteraatio <- 1 | |||
repeat{ | |||
if(verbose) {print(SudShow(sudoku))} | |||
samerow <- matrix(sudoku$SudRow, nrow = nrow(sudoku), ncol = nrow(sudoku)) | samerow <- matrix(sudoku$SudRow, nrow = nrow(sudoku), ncol = nrow(sudoku)) | ||
samerow <- samerow == t(samerow) | samerow <- samerow == t(samerow) | ||
Line 349: | Line 335: | ||
temp <- sudoku$Result & rule1 & rule2 & rule3 #& rule4 | temp <- sudoku$Result & rule1 & rule2 & rule3 #& rule4 | ||
temp <- ifelse(samecell, NA, temp) # Tämän säännön täytyy ajaa yli kaikkien muiden. | temp <- ifelse(samecell, NA, temp) # Tämän säännön täytyy ajaa yli kaikkien muiden. | ||
temp2 <- apply(temp, 2, function(x) tapply(x, sudoku$SudCell, any)) | temp2 <- apply(temp, 2, function(x) tapply(x, sudoku$SudCell, any)) | ||
temp3 <- apply(temp2, 2, function(x) { | temp3 <- apply(temp2, 2, function(x) { | ||
Line 366: | Line 342: | ||
return(all(x)) | return(all(x)) | ||
}) | }) | ||
sudoku <- ykköskarsinta( | sudtemp <- sudoku | ||
sudtemp$Result <- ifelse(sudtemp$Result, temp3, sudtemp$Result) | |||
if(any(tapply(sudtemp$Result, sudtemp["SudCell"], sum) == 0)) { | |||
if(verbose) {warning("Implausible solution\n")} | |||
return(sudtemp) | |||
} | |||
sudtemp <- ykköskarsinta(sudtemp, "SudCol") | |||
sudtemp <- ykköskarsinta(sudtemp, "SudRow") | |||
sudtemp <- ykköskarsinta(sudtemp, "SudArea") | |||
iteraatio <- iteraatio + 1 | |||
test <- all(sudtemp$Result == sudoku$Result) | |||
cat("Onko sama sudoku kierroksella ", iteraatio, "?", test, "\n") | |||
sudoku <- sudtemp | |||
if(test | iteraatio > 15) {break} | |||
} | } | ||
return(sudoku) | return(sudoku) | ||
} | } | ||
Line 379: | Line 365: | ||
SudShow <- function(sudoku) { | SudShow <- function(sudoku) { | ||
if(class(sudoku) == "data.frame") {sudoku <- list(sudoku)} | |||
for(i in 1:length(sudoku)) { | |||
out <- sudoku[[i]] | |||
out <- out[out$Result , ] | |||
out <- tapply(out$Hypothesis, out[c("SudRow", "SudCol")], function(x) paste(x, sep = "", collapse = "")) | |||
if(exists("oprint")) oprint(out) else print(out) | |||
} | |||
} | |||
SudGuess <- function(sudoku, cellguess, verbose = FALSE) { | |||
if(class(sudoku) == "data.frame") {sudokulist <- list(sudoku)} else {sudokulist <- sudoku} | |||
for(i in cellguess) { # Jokainen lisäruutu erikseen | |||
lap <- 0 | |||
templist <- list() | |||
for(j in 1:length(sudokulist)) { # Jokainen sudokuskenaario erikseen. | |||
sudo <- sudokulist[[j]] | |||
nscen <- nrow(sudo[sudo$SudCell %in% i & sudo$Result , ]) | |||
for(k in 1:nscen) { # Jokainen valitun ruudun mahdollinen vaihtoehto erikseen. | |||
faagi <- rep(FALSE, nscen) | |||
faagi[k] <- TRUE | |||
temp <- sudo | |||
temp[temp$SudCell %in% i & temp$Result, "Result"] <- faagi | |||
temp <- SudSolve(temp) | |||
if(verbose) {print(SudShow(temp))} | |||
if(!any(tapply(temp$Result, temp["SudCell"], sum) == 0)) {templist[[lap + k]] <- temp} | |||
} | |||
lap <- lap + k | |||
} | |||
templist <- templist[!sapply(templist, is.null)] | |||
sudokulist <- templist | |||
} | } | ||
if(length(sudokulist) == 1) {sudokulist <- sudokulist[[1]]} | |||
return(sudokulist) | |||
return( | |||
} | } | ||
</rcode> | </rcode> |
Revision as of 17:04, 5 May 2013
Moderator:Jouni (see all) |
This page is a stub. You may improve it into a full page. |
Upload data
|
Question
How to describe a sudoku and the sudoku rules in Opasnet so that it can be solved automatically?
Answer
You need the following tables.
Row | Column | Result | Description |
---|---|---|---|
All | All | 1,2,3,4,5,6,7,8,9 | For all row and column locations it applies that the plausible hypotheses are a single integer between 1 and 9 (unless more information is available). |
Row | Column | Area |
---|---|---|
1 | 1 | A |
1 | 2 | A |
1 | 3 | A |
1 | 4 | B |
… | ||
2 | 1 | A |
… | ||
4 | 1 | D |
… | ||
9 | 9 | I |
Property1 | Condition1 | Property2 | Condition2 | Rule | Description |
---|---|---|---|---|---|
Row | Same | Column | Different | Same integer not allowed | Two cells with the same row and different column are not allowed to have the same integer. |
Row | Different | Column | Same | Same integer not allowed | Two cells with the different row and same column are not allowed to have the same integer. |
Area | Same | Column | Different | Same integer not allowed | Two cells with the same area and different column are not allowed to have the same integer. |
Area | Same | Row | Different | Same integer not allowed | Two cells with the same area and different row are not allowed to have the same integer. |
Row | Column | ||||||||
---|---|---|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
1 | 8 | ||||||||
2 | 3 | 6 | |||||||
3 | 7 | 9 | 2 | ||||||
4 | 5 | 7 | |||||||
5 | 4 | 5 | 7 | ||||||
6 | 1 | 3 | |||||||
7 | 1 | 6 | 8 | ||||||
8 | 8 | 5 | 1 | ||||||
9 | 9 | 4 |
Procedure
The following terms are used:
- The possible space of solutions is described by a logical vector A, which contains all possible values given the current information. A is indexed by h, i, j, k, and l. A develops in time, when more information occurs or is processed. In the beginning, all hypotheses are considered as potentially TRUE.
- h = {1, 2, ..., 9}, i = {1, 2, ..., 9}, j = {1, 2, ..., 9}, k = {1, 2, ..., 9}, l = {1, 2, ..., 81} are indices for hypothesis, row, column, area, and cell, respectively. Note l is just another way to say (i,j), as l = i + (j-1)*9. Also, k is known if (i,j) is known, as k = ceiling(i/3) + (ceiling(j/3)-1)*3. However, k does not contain all information that (i,j) or l contains.
- ah and bh are sub-vectors of A in such a way that ah = Ah,m and bh = Ah,n, where m and n (m < n) are values from index l.
- Expand the missing index values of the Hypotheses table to create the full A.
- Take the sudoku data table and replace hypotheses with data, if available.
- Compare all two-cell pairs at once using matrices.
- Create matrices of all critical properties: SudRow, SudCol, SudArea, and Hypothesis. These are compared pairwise, two cells at a time.
- Use rules to deduce if a pair is incompatible or not.
- Aggregate plausible hypotheses in the second cell across all plausible values in the first cell. This gives a set of hypotheses that are plausible in at least some conditions.
- Aggregate along the first cell: each second cell must be compatible with all other (first) cells.
- Do not apply these rules if the first and second cells are the same.
- Go through every row, column, and area and find hypotheses where there is exactly one cell where it is plausible.
- Remove all other hypotheses from these cells.
- Do steps 3 and 4 for five times, assuming that all hypotheses have been eliminated by then, if it is possible to eliminate them using these rules.
- Take a user-defined list of cells for which a random sample from plausible hypotheses is taken. It would be elegant to do this stepwise, but for simplicity, let's do it at once. Therefore, the cells that the user selects is critical, and a wise user will not select cells where uncertainties are clearly interdependent.
- Solve all sudokus that are created in the sampling.
- If a sudoku results in cells with zero plausible hypotheses, remove that iteration.
- Calculate the number of different solutions still plausible and print it.
- If the number is smaller than 100, print also the solutions.
Rationale
Data
This table will be expanded by fillna to be a 9*9*9 array (formatted as data.frame). As default, each hypothesis is assumed to be true unless shown otherwise.
Obs | SudRow | SudCol | Hypothesis | Result |
---|---|---|---|---|
1 | 1 | TRUE | ||
2 | 2 | TRUE | ||
3 | 3 | TRUE | ||
4 | 4 | TRUE | ||
5 | 5 | TRUE | ||
6 | 6 | TRUE | ||
7 | 7 | TRUE | ||
8 | 8 | TRUE | ||
9 | 9 | TRUE | ||
10 | 1 | TRUE | ||
11 | 2 | TRUE | ||
12 | 3 | TRUE | ||
13 | 4 | TRUE | ||
14 | 5 | TRUE | ||
15 | 6 | TRUE | ||
16 | 7 | TRUE | ||
17 | 8 | TRUE | ||
18 | 9 | TRUE | ||
19 | 1 | TRUE | ||
20 | 2 | TRUE | ||
21 | 3 | TRUE | ||
22 | 4 | TRUE | ||
23 | 5 | TRUE | ||
24 | 6 | TRUE | ||
25 | 7 | TRUE | ||
26 | 8 | TRUE | ||
27 | 9 | TRUE |
- Sudoku data
Obs | SudRow | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
1 | 1 | 8 | ||||||||
2 | 2 | 3 | 6 | |||||||
3 | 3 | 7 | 9 | 2 | ||||||
4 | 4 | 5 | 7 | |||||||
5 | 5 | 4 | 5 | 7 | ||||||
6 | 6 | 1 | 3 | |||||||
7 | 7 | 1 | 6 | 8 | ||||||
8 | 8 | 8 | 5 | 1 | ||||||
9 | 9 | 9 | 4 |
Formula
See also
- file:Sudoku solver.ANA (a draft solver using Analytica)
Keywords
References
Related files
<mfanonymousfilelist></mfanonymousfilelist>