package main
import (
"container/list"
"fmt"
)
var (
ROWCOUNT = 9
)
//每一步的數據
type stepData struct {
x int
y int
data []int
backup int
}
//獲得數組的行列數據
func getRowColData(info [][]int, row, col int) []int {
returnArr := make([]int, 0, ROWCOUNT)
hasInfo := make(map[int]bool)
for i := 0; i < len(info[row]); i++ {
curDta := info[row][i]
if _, ok := hasInfo[curDta]; !ok {
returnArr = append(returnArr, curDta)
hasInfo[curDta] = true
}
}
for i := 0; i < len(info); i++ {
curDta := info[i][col]
if _, ok := hasInfo[curDta]; !ok {
returnArr = append(returnArr, curDta)
hasInfo[curDta] = true
}
}
return returnArr
}
//獲得前一個數組不在後一個數組中的元素
func getDiffInfo(refer []int, cur []int) []int {
hasInfo := make(map[int]bool)
for i := 0; i < len(refer); i++ {
hasInfo[refer[i]] = true
}
returnArr := make([]int, 0, len(cur))
for i := 0; i < len(cur); i++ {
if _, ok := hasInfo[cur[i]]; !ok {
returnArr = append(returnArr, cur[i])
}
}
return returnArr
}
//判斷元素是否符合數獨的規則
func isvalid(info [][]int, row, col, value int) bool {
for i := 0; i < len(info[row]); i++ {
if i == col {
continue
}
curDta := info[row][i]
if curDta == value {
return false
}
}
for i := 0; i < len(info); i++ {
if i == row {
continue
}
curDta := info[i][col]
if curDta == value {
return false
}
}
return true
}
//獲得x、y位置的step數據
func getStepData(dstValue [][]int, x, y int) *stepData {
curStep := &stepData{
x: x,
y: y,
data: make([]int, 0, ROWCOUNT),
backup: 0,
}
if dstValue[x][y] != 0 {
curStep.data = append(curStep.data, dstValue[x][y])
curStep.backup = dstValue[x][y]
} else {
for k := 0; k < 9; k++ {
curStep.data = append(curStep.data, k+1)
}
curStep.data = getDiffInfo(getRowColData(dstValue, x, y), curStep.data)
}
return curStep
}
//創建要求解的數獨
func buildSudoku() [][]int {
dstValue := make([][]int, ROWCOUNT, ROWCOUNT)
for i := 0; i < 9; i++ {
dstValue[i] = make([]int, ROWCOUNT, ROWCOUNT)
}
dstValue[0][5] = 5
dstValue[0][8] = 7
dstValue[1][1] = 6
dstValue[1][2] = 5
dstValue[1][3] = 3
dstValue[1][4] = 9
dstValue[1][6] = 1
dstValue[2][1] = 8
dstValue[2][4] = 6
dstValue[2][7] = 5
dstValue[3][0] = 6
dstValue[3][1] = 3
dstValue[3][2] = 2
dstValue[3][5] = 9
dstValue[3][7] = 7
dstValue[4][1] = 7
dstValue[4][3] = 4
dstValue[4][5] = 1
dstValue[4][7] = 6
dstValue[5][1] = 1
dstValue[5][3] = 2
dstValue[5][6] = 3
dstValue[5][7] = 9
dstValue[5][8] = 5
dstValue[6][1] = 9
dstValue[6][4] = 2
dstValue[6][7] = 8
dstValue[7][2] = 8
dstValue[7][4] = 1
dstValue[7][5] = 3
dstValue[7][6] = 7
dstValue[7][7] = 4
dstValue[8][0] = 7
dstValue[8][3] = 6
return dstValue
}
func main() {
dstValue := buildSudoku()
myList := list.New()
myList.PushFront(getStepData(dstValue, 0, 0))
var count int
for {
curStepData := myList.Front().Value.(*stepData)
if len(curStepData.data) < 1 {
dstValue[curStepData.x][curStepData.y] = curStepData.backup
myList.Remove(myList.Front())
if myList.Len() < 1 {
fmt.Println("list is null, ", curStepData.x, " : ", curStepData.y)
break
}
continue
}
for {
if len(curStepData.data) < 1 {
dstValue[curStepData.x][curStepData.y] = curStepData.backup
break
}
preStepData := curStepData.data[0]
curStepData.data = curStepData.data[1:]
if isvalid(dstValue, curStepData.x, curStepData.y, preStepData) {
dstValue[curStepData.x][curStepData.y] = preStepData
xPos := curStepData.x
yPos := curStepData.y
if curStepData.x == (ROWCOUNT-1) && curStepData.y == (ROWCOUNT-1) {
fmt.Println("success")
fmt.Println(dstValue)
count++
break
}
yPos += 1
if yPos >= ROWCOUNT {
yPos -= ROWCOUNT
xPos += 1
}
myList.PushFront(getStepData(dstValue, xPos, yPos))
break
}
}
}
fmt.Println("cout: ", count)
}