github.com/gopherd/gonum@v0.0.4/graph/coloring/sudoku_example_test.go (about) 1 // Copyright ©2021 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package coloring_test 6 7 import ( 8 "fmt" 9 "log" 10 11 "github.com/gopherd/gonum/graph/coloring" 12 "github.com/gopherd/gonum/graph/graphs/gen" 13 "github.com/gopherd/gonum/graph/simple" 14 ) 15 16 // A hard sudoku problem graded at a level of difficulty, "not fun". 17 // https://dingo.sbs.arizona.edu/~sandiway/sudoku/examples.html 18 var grid = [9][9]int{ 19 {0, 2, 0 /**/, 0, 0, 0 /**/, 0, 0, 0}, 20 {0, 0, 0 /**/, 6, 0, 0 /**/, 0, 0, 3}, 21 {0, 7, 4 /**/, 0, 8, 0 /**/, 0, 0, 0}, 22 23 {0, 0, 0 /**/, 0, 0, 3 /**/, 0, 0, 2}, 24 {0, 8, 0 /**/, 0, 4, 0 /**/, 0, 1, 0}, 25 {6, 0, 0 /**/, 5, 0, 0 /**/, 0, 0, 0}, 26 27 {0, 0, 0 /**/, 0, 1, 0 /**/, 7, 8, 0}, 28 {5, 0, 0 /**/, 0, 0, 9 /**/, 0, 0, 0}, 29 {0, 0, 0 /**/, 0, 0, 0 /**/, 0, 4, 0}, 30 } 31 32 func Example_sudoku() { 33 g := simple.NewUndirectedGraph() 34 35 // Build the sudoku board constraints. 36 for i := 0; i < 9; i++ { 37 gen.Complete(g, row(i)) 38 gen.Complete(g, col(i)) 39 } 40 for r := 0; r < 3; r++ { 41 for c := 0; c < 3; c++ { 42 gen.Complete(g, block{r, c}) 43 } 44 } 45 46 // Add constraints for the digits. 47 gen.Complete(g, gen.IDRange{First: -9, Last: -1}) 48 49 // Mark constraints onto the graph. 50 for r, row := range &grid { 51 for c, val := range &row { 52 if val == 0 { 53 continue 54 } 55 for i := 1; i <= 9; i++ { 56 if i != val { 57 g.SetEdge(simple.Edge{F: simple.Node(-i), T: simple.Node(id(r, c))}) 58 } 59 } 60 } 61 } 62 63 k, colors, err := coloring.DsaturExact(nil, g) 64 if err != nil { 65 log.Fatal(err) 66 } 67 if k != 9 { 68 log.Fatalln("could not solve problem", k) 69 } 70 sets := coloring.Sets(colors) 71 for r := 0; r < 9; r++ { 72 if r != 0 && r%3 == 0 { 73 fmt.Println() 74 } 75 for c := 0; c < 9; c++ { 76 if c != 0 { 77 fmt.Print(" ") 78 if c%3 == 0 { 79 fmt.Print(" ") 80 } 81 } 82 got := -int(sets[colors[id(r, c)]][0]) 83 if want := grid[r][c]; want != 0 && got != want { 84 log.Fatalf("mismatch at row=%d col=%d: %d != %d", r, c, got, want) 85 } 86 fmt.Print(got) 87 } 88 fmt.Println() 89 } 90 91 // Output: 92 // 93 // 1 2 6 4 3 7 9 5 8 94 // 8 9 5 6 2 1 4 7 3 95 // 3 7 4 9 8 5 1 2 6 96 // 97 // 4 5 7 1 9 3 8 6 2 98 // 9 8 3 2 4 6 5 1 7 99 // 6 1 2 5 7 8 3 9 4 100 // 101 // 2 6 9 3 1 4 7 8 5 102 // 5 4 8 7 6 9 2 3 1 103 // 7 3 1 8 5 2 6 4 9 104 } 105 106 // row is a gen.IDer that enumerates the IDs of graph 107 // nodes representing a row of cells of a sudoku board. 108 type row int 109 110 func (r row) Len() int { return 9 } 111 func (r row) ID(i int) int64 { return id(int(r), i) } 112 113 // col is a gen.IDer that enumerates the IDs of graph 114 // nodes representing a column of cells of a sudoku board. 115 type col int 116 117 func (c col) Len() int { return 9 } 118 func (c col) ID(i int) int64 { return id(i, int(c)) } 119 120 // block is a gen.IDer that enumerates the IDs of graph 121 // nodes representing a 3×3 block of cells of a sudoku board. 122 type block struct { 123 r, c int 124 } 125 126 func (b block) Len() int { return 9 } 127 func (b block) ID(i int) int64 { 128 return id(b.r*3, b.c*3) + int64(i%3) + int64(i/3)*9 129 } 130 131 // id returns the graph node ID of a cell in a sudoku board. 132 func id(row, col int) int64 { 133 return int64(row*9 + col) 134 }