-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathiteration.go
164 lines (147 loc) · 4.02 KB
/
iteration.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
package sudoku
// iteration is a single iteration of a puzzle.
type iteration struct {
// index is the cell index that this iteration will effect
index int
// minValue is the min value this iteration used when effecting the cell
minValue int
puzzleSize int
sectionSize int
cells group
rows [][]int
columns [][]int
sections [][]int
}
// newIteration returns a new iteration with the given items.
func newIteration(items []int, puzzleSize int, sectionSize int) *iteration {
rows := make([][]int, puzzleSize)
columns := make([][]int, puzzleSize)
sections := make([][]int, puzzleSize)
it := &iteration{
puzzleSize: puzzleSize,
sectionSize: sectionSize,
cells: make(group, len(items)),
rows: rows,
columns: columns,
sections: sections,
}
for i, item := range items {
c := cell{
fixed: item > 0,
value: item,
index: i,
}
it.cells[i] = &c
rowIndex := getRowFromIndex(c.index, it.puzzleSize)
if it.rows[rowIndex] == nil {
it.rows[rowIndex] = make([]int, 0, it.puzzleSize)
}
it.rows[rowIndex] = append(it.rows[rowIndex], c.index)
columnIndex := getColumnFromIndex(c.index, it.puzzleSize)
if it.columns[columnIndex] == nil {
it.columns[columnIndex] = make([]int, 0, it.puzzleSize)
}
it.columns[columnIndex] = append(it.columns[columnIndex], c.index)
sectionIndex := getSectionFromIndex(c.index, it.puzzleSize, it.sectionSize)
if it.sections[sectionIndex] == nil {
it.sections[sectionIndex] = make([]int, 0, it.puzzleSize)
}
it.sections[sectionIndex] = append(it.sections[sectionIndex], c.index)
}
return it
}
// items returns all of the items in the iteration.
func (i *iteration) items() []int {
res := make([]int, len(i.cells))
for i, c := range i.cells {
res[i] = c.value
}
return res
}
// iterate returns a iterate of the iteration.
func (i *iteration) iterate() *iteration {
it := &iteration{
puzzleSize: i.puzzleSize,
sectionSize: i.sectionSize,
cells: make(group, len(i.cells)),
rows: i.rows,
columns: i.columns,
sections: i.sections,
minValue: 1,
index: i.index + 1,
}
for i, item := range i.cells {
it.cells[i] = item.copy()
}
return it
}
// finished returns true if there are no zero values left in the iteration.
func (i *iteration) finished() bool {
for _, c := range i.cells {
if c.value == 0 {
return false
}
}
return true
}
// completionRate returns the number of completed non-fixed cells in the iteration.
func (i *iteration) completionRate() *CompletionRate {
res := new(CompletionRate)
res.CellIndex = i.index
res.MinValueAtCell = i.minValue
for _, c := range i.cells {
res.TotalCells++
if c.fixed {
res.FixedCells++
}
if c.value > 0 {
res.FilledCells++
}
}
return res
}
// solve attempts to solve the current iteration.
func (i *iteration) solve() error {
for cellIndex := i.index; ; cellIndex++ {
cell := i.cells[cellIndex]
if cell.fixed {
continue
}
i.index = cellIndex
nextValue, err := i.findNextValue(cell, i.minValue)
if err != nil {
return err
}
i.minValue = nextValue
cell.value = nextValue
return nil
}
}
func (i *iteration) findNextValue(cell *cell, minValue int) (int, error) {
usedMap := map[int]bool{}
for _, cellIndex := range i.rows[getRowFromIndex(cell.index, i.puzzleSize)] {
if usedMap[i.cells[cellIndex].value] || i.cells[cellIndex].value < minValue {
continue
}
usedMap[i.cells[cellIndex].value] = true
}
for _, cellIndex := range i.columns[getColumnFromIndex(cell.index, i.puzzleSize)] {
if usedMap[i.cells[cellIndex].value] || i.cells[cellIndex].value < minValue {
continue
}
usedMap[i.cells[cellIndex].value] = true
}
for _, cellIndex := range i.sections[getSectionFromIndex(cell.index, i.puzzleSize, i.sectionSize)] {
if usedMap[i.cells[cellIndex].value] || i.cells[cellIndex].value < minValue {
continue
}
usedMap[i.cells[cellIndex].value] = true
}
for value := minValue; value <= i.puzzleSize; value++ {
if usedMap[value] {
continue
}
return value, nil
}
return 0, ErrNoMoreMoves
}