sudoku - uniquesum.go
1 package sudoku
2
3 // UniqueSum is a Constraint that requires all numbers to be unique and total a specific amount.
4 type UniqueSum struct {
5 positions []int
6 total int
7 }
8
9 // Constrain implements the Constraint interface.
10 func (u UniqueSum) Constrain(s *Sudoku, pos int, marked []bool) bool {
11 if slicePos(u.positions, pos) == -1 {
12 return true
13 }
14 total := 0
15 myMark := make([]bool, s.Chars()+1)
16 empty := 0
17 for _, p := range u.positions {
18 if mp := s.Pos(p); mp == 0 {
19 empty++
20 } else {
21 if myMark[mp] {
22 return false
23 }
24 myMark[mp] = true
25 marked[mp] = true
26 total += mp
27 }
28 }
29 remaining := u.total - total
30 if remaining < 0 {
31 return false
32 }
33 myNums := make([]int, 0, s.Chars())
34 for n, b := range myMark[1:] {
35 if !b {
36 myNums = append(myNums, n+1)
37 }
38 }
39 data := make([]int, 0, empty)
40 marks := make([]bool, s.chars+1)
41 if !getCombinations(myNums, data, 0, remaining, marks) {
42 return false
43 }
44 r := false
45 for n, m := range marks {
46 if !m {
47 marked[n] = true
48 } else if !r && !marked[n] {
49 r = true
50 }
51 }
52 return r
53 }
54
55 func getCombinations(nums, data []int, pos, remaining int, marks []bool) bool {
56 if len(data) == cap(data) {
57 if remaining == 0 {
58 for _, n := range data {
59 marks[n] = true
60 }
61 return true
62 }
63 return false
64 }
65 toRet := false
66 o := data
67 for i := pos; i < len(nums); i++ {
68 if nums[i] > remaining {
69 continue
70 }
71 data = append(data, nums[i])
72 if getCombinations(nums, data, i+1, remaining-nums[i], marks) {
73 toRet = true
74 }
75 data = o
76 }
77 return toRet
78 }