邓心一 vor 6 Jahren
Ursprung
Commit
b134480af9
1 geänderte Dateien mit 95 neuen und 37 gelöschten Zeilen
  1. 95 37
      hard/37.go

+ 95 - 37
hard/37.go

@@ -1,57 +1,101 @@
 package main
 
-// IntMap ...
-type IntMap []int
+// Slice ...
+type Slice []interface{}
 
-func (im IntMap) set(id, num int) {
-	im[id] |= 1 << uint(num)
+// Pop ...
+func (s *Slice) Pop() interface{} {
+	l := len(*s)
+	top := (*s)[l-1]
+	*s = (*s)[:l-1]
+	return top
 }
 
-func (im IntMap) get(id, num int) bool {
-	return im[id]&(1<<uint(num)) == 1
+// Empty ...
+func (s Slice) Empty() bool {
+	return len(s) == 0
 }
 
-func getAnswer(occur int) (ans byte, ok bool) {
-	cnt := 0
-	for i, bit := 1, 1; i <= 9; i++ {
-		if occur&bit == 0 {
-			cnt++
-			ans = byte(i + '0')
-		}
-		bit <<= 1
+// Grid ...
+type Grid struct {
+	X   int
+	Y   int
+	Val int
+}
+
+// SudokuMap ...
+type SudokuMap [][]int
+
+// NewSudokuMap ...
+func NewSudokuMap() (m SudokuMap) {
+	m = make([][]int, 3) // 0 for col, 1 for row and 2 for block id
+	for i := range m {
+		m[i] = make([]int, 9)
 	}
-	return ans, cnt == 1
+	return
+}
+
+var mask = [...]int{1, 2, 4, 8, 16, 32, 64, 128, 256, 512}
+
+// Put ...
+func (m SudokuMap) Put(x, y, val int) {
+	m[0][x] |= mask[val]
+	m[1][y] |= mask[val]
+	m[2][y/3*3+x/3] |= mask[val]
+}
+
+// Get ...
+func (m SudokuMap) Get(x, y, val int) bool {
+	return (m[0][x]|m[1][y]|m[2][y/3*3+x/3])&mask[val] != 0
+}
+
+// Del ...
+func (m SudokuMap) Del(x, y, val int) {
+	mask := mask[val] ^ 0x3FF
+	m[0][x] &= mask
+	m[1][y] &= mask
+	m[2][y/3*3+x/3] &= mask
 }
 
 func solveSudoku(board [][]byte) {
-	var rowMap, colMap, blockMap IntMap
-	rowMap = make([]int, 9)
-	colMap = make([]int, 9)
-	blockMap = make([]int, 9)
-	for y, row := range board {
-		for x, col := range row {
-			if col == '.' {
-				continue
+	// Init sudoku and count blank grid
+	m := NewSudokuMap()
+	blank := 0
+	for y := range board {
+		for x := range board[y] {
+			if board[y][x] == '.' {
+				blank++
+			} else {
+				m.Put(x, y, int(board[y][x]-'0'))
 			}
-			num := int(col - '0')
-			rowMap.set(y, num)
-			colMap.set(x, num)
-			blockMap.set(y/3*3+x/3, num)
 		}
 	}
-	for y, row := range board {
-		for x, col := range row {
-			if col != '.' {
-				continue
-			}
-			blockID := y/3*3 + x/3
-			occur := rowMap[y] & colMap[x] & blockMap[blockID]
-			ans, ok := getAnswer(occur)
-			if ok {
-				board[y][x] = ans
+	var stack Slice = make([]interface{}, 0)
+	for len(stack) != blank { // Assume that all quetion is solvable
+		for y := 0; y < 9; y++ {
+			for x, i := 0, 1; x < 9; x++ {
+				if board[y][x] == '.' { // Never use 'copy' or 'range' when backtracking in golang!!!
+					for ; i <= 9; i++ {
+						if !m.Get(x, y, i) { // Is valid
+							m.Put(x, y, i)
+							stack = append(stack, Grid{x, y, i})
+							i = 1 // Reset next val
+							break
+						}
+					}
+					if i == 10 { // Not valid
+						top := stack.Pop().(Grid)
+						m.Del(top.X, top.Y, top.Val)
+						x, y, i = top.X-1, top.Y, top.Val+1 // Try next val of last step
+					}
+				}
 			}
 		}
 	}
+	for !stack.Empty() {
+		top := stack.Pop().(Grid)
+		board[top.Y][top.X] = byte(top.Val + '0')
+	}
 }
 
 func main() {
@@ -67,4 +111,18 @@ func main() {
 		{'.', '.', '.', '.', '8', '.', '.', '7', '9'}}
 	solveSudoku(b1)
 	printBoard(b1)
+
+	println()
+	b2 := [][]byte{
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'},
+		{'.', '.', '.', '.', '.', '.', '.', '.', '.'}}
+	solveSudoku(b2)
+	printBoard(b2)
 }