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  }