-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathsudoku.go
215 lines (186 loc) · 4.88 KB
/
sudoku.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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
// gosudoku is a tiny package for resolving Sudoku games
package gosudoku
import (
"fmt"
"math"
)
type Sudoku struct {
Numbers [9][9]int
}
// Prints sudoku to console
func (s *Sudoku) Print() {
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
// Printing group of 3 numbers
fmt.Print(s.Numbers[i][j], " ")
// Inserting space after each 3 columns
if (j+1)%3 == 0 {
fmt.Print(" ")
}
}
// Inserting line break after each 3 rows
fmt.Println()
if (i+1)%3 == 0 {
fmt.Println()
}
}
}
// Adds number to the Sudoku's cell
func (s *Sudoku) AddNumber(rowIndex int, colIndex int, number int) {
if areIndexesCorrect(rowIndex, colIndex) && isNumberCorrect(number) {
s.Numbers[rowIndex][colIndex] = number
}
}
// Resolves Sudoku
func (s *Sudoku) Resolve() bool {
// Do next step if game is not over
if s.getUnresolvedCellAmount() > 0 {
count, cell := s.getMostNormalizedCell()
index := 0
result := false
values := s.getPossibleNumbers(cell)
// Looping until putting correct number
for !result {
// Something went wrong. Cleaning cell and returning false
if index == count {
s.Numbers[cell.rowIndex][cell.colIndex] = 0
return false
}
number := values[index]
index++
s.Numbers[cell.rowIndex][cell.colIndex] = number
// Trying to do next step
result = s.Resolve()
}
}
return true
}
// Returns amount of cells equal to zero
func (s *Sudoku) getUnresolvedCellAmount() int {
result := 0
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
if s.Numbers[i][j] == 0 {
result++
}
}
}
return result
}
// Gets column by it's index
func (s *Sudoku) getColumn(index int) line {
column := line{}
current := 0
for i := 0; i < 9; i++ {
column.numbers[current] = s.Numbers[i][index]
current++
}
return column
}
// Gets row by it's index
func (s *Sudoku) getRow(index int) line {
row := line{}
row.numbers = s.Numbers[index]
return row
}
// Gets square by it's index
func (s *Sudoku) getSquare(index int) square {
sqr := square{}
// Row and Column indexes on sudoku field to start copying from
rowIndex := int(math.Floor(float64(index)/3.0)) * 3
colIndex := (index - rowIndex) * 3
x := 0
y := 0
// Copying values from sudoku field to square
for i := rowIndex; i < rowIndex+3; i++ {
for j := colIndex; j < colIndex+3; j++ {
sqr.numbers[y][x] = s.Numbers[i][j]
x++
}
y++
x = 0
}
return sqr
}
// Returns true if number can be put inside the cell and be still unique
// inside the row / column / square
func (s *Sudoku) canBePut(rowIndex int, colIndex int, number int) bool {
if s.Numbers[rowIndex][colIndex] != 0 {
return false
}
// Creating a copy of sudoku
tempSudoku := Sudoku{Numbers: s.Numbers}
tempSudoku.AddNumber(rowIndex, colIndex, number)
// Getting row, column and square that will be checked
row := tempSudoku.getRow(rowIndex)
col := tempSudoku.getColumn(colIndex)
sqrIndex := getSquareIndex(rowIndex, colIndex)
sqr := tempSudoku.getSquare(sqrIndex)
// Checking row, column and square of the sudoku's copy
if row.isUnique() && col.isUnique() && sqr.isUnique() {
return true
}
return false
}
// Returns cell with minimal possible number amount to put
func (s *Sudoku) getMostNormalizedCell() (int, cell) {
minPossibilities := 10
rowIndex := -1
colIndex := -1
// Finding the cell with minimal possible number amount to put
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
// Only if cell is currently empty
if s.Numbers[i][j] == 0 {
amount := s.getPossibleNumberAmount(i, j)
// If new minimal amount found, replacing result and indexes
if amount < minPossibilities {
minPossibilities = amount
rowIndex = i
colIndex = j
}
}
}
}
return minPossibilities, cell{rowIndex, colIndex}
}
// Returns possible amount of numbers for the cell with indexes
func (s *Sudoku) getPossibleNumberAmount(rowIndex int, colIndex int) int {
count := 0
// How much numbers can be put inside the cell
for i := 1; i <= 9; i++ {
if s.canBePut(rowIndex, colIndex, i) {
count++
}
}
return count
}
// Returns list of possible numbers for the cell
func (s *Sudoku) getPossibleNumbers(c cell) []int {
possibleNumbers := []int{}
// The list of numbers can be put inside the cell currently
for i := 1; i <= 9; i++ {
if s.canBePut(c.rowIndex, c.colIndex, i) {
possibleNumbers = append(possibleNumbers, i)
}
}
return possibleNumbers
}
// Column and row indexes must be in diaposone 0..8
func areIndexesCorrect(colIndex int, rowIndex int) bool {
if colIndex < 0 || colIndex > 8 || rowIndex < 0 || rowIndex > 8 {
return false
}
return true
}
// The number must be in diaposone 1..9
func isNumberCorrect(number int) bool {
if number < 1 || number > 9 {
return false
}
return true
}
// Gets square index by cell indexes
func getSquareIndex(rowIndex int, colIndex int) (sqrIndex int) {
return 3*int((math.Floor(float64(rowIndex)/3.0))) + int((math.Floor(float64(colIndex) / 3.0)))
}