mirror of https://github.com/01-edu/public.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
3.3 KiB
167 lines
3.3 KiB
5 years ago
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
|
||
|
"github.com/01-edu/z01"
|
||
|
)
|
||
|
|
||
|
// Prints in standard output the sudoku board
|
||
|
func printBoard(board [][]rune) {
|
||
|
for _, row := range board {
|
||
|
for i, e := range row {
|
||
|
z01.PrintRune(e)
|
||
|
if i != len(row)-1 {
|
||
|
z01.PrintRune(' ')
|
||
|
}
|
||
|
}
|
||
|
z01.PrintRune('\n')
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Return true if the value 'value' is in the row 'y' of the board 'board'
|
||
|
func isInRow(board [][]rune, value rune, x, y int) bool {
|
||
|
for i, v := range board[y] {
|
||
|
if i != x && v == value {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// Returns true if the value 'value' is in the column 'x' of the board 'board'
|
||
|
func isInColumn(board [][]rune, value rune, x, y int) bool {
|
||
|
for i := 0; i < 9; i++ {
|
||
|
if i != y && board[i][x] == value {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// Receives an int 'x' and returns the beginning and the end
|
||
|
// of the interval of consecutive pairs of multiples of three 'x' is in.
|
||
|
// Ex. for x = 2, x is in (0, 3)
|
||
|
// for x = 4, x is in (3, 6)
|
||
|
func intervalThree(x int, max int) (int, int) {
|
||
|
var i int
|
||
|
for i = 0; i < max; i += 3 {
|
||
|
if x >= i && x < i+3 {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
endi := 3 + i
|
||
|
return i, endi
|
||
|
}
|
||
|
|
||
|
// Returns true if the value 'value' is allowed in the possition (x,y) of the board 'board'
|
||
|
func isAllowedInBox(board [][]rune, value rune, x, y int) bool {
|
||
|
n := len(board)
|
||
|
begi, endi := intervalThree(x, n)
|
||
|
begj, endj := intervalThree(y, n)
|
||
|
for j := begj; j < endj; j++ {
|
||
|
for i := begi; i < endi; i++ {
|
||
|
if (j != y || i != i) && board[j][i] == value {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// Returns true if the value 'val' is allowed in the position (x, y) of the board
|
||
|
func isAllowed(board [][]rune, val rune, x, y int) bool {
|
||
|
return !isInRow(board, val, x, y) &&
|
||
|
!isInColumn(board, val, x, y) &&
|
||
|
isAllowedInBox(board, val, x, y)
|
||
|
}
|
||
|
|
||
|
// Returns true if the position doesn't have any value defined
|
||
|
// That is, if the character is a dot '.'
|
||
|
func isEmpty(board [][]rune, x, y int) bool {
|
||
|
return board[y][x] == '.'
|
||
|
}
|
||
|
|
||
|
// Returns all the empty positions in the board
|
||
|
func availablePos(board [][]rune) [][]int {
|
||
|
var ava [][]int
|
||
|
for y, row := range board {
|
||
|
for x, e := range row {
|
||
|
if e == '.' {
|
||
|
ava = append(ava, []int{x, y})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return ava
|
||
|
}
|
||
|
|
||
|
func validBoard(board [][]rune) bool {
|
||
|
size := 9
|
||
|
if len(board) != size {
|
||
|
return false
|
||
|
}
|
||
|
for y, row := range board {
|
||
|
if len(row) != size {
|
||
|
return false
|
||
|
}
|
||
|
for x, e := range row {
|
||
|
if (e < '1' || e > '9') && e != '.' {
|
||
|
return false
|
||
|
}
|
||
|
if e != '.' && !isAllowed(board, e, x, y) {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
// Returns true if the sudoku has a solution
|
||
|
func sudokuH(board [][]rune, available [][]int, i int) bool {
|
||
|
n := len(available)
|
||
|
|
||
|
if i >= n {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
x := available[i][0]
|
||
|
y := available[i][1]
|
||
|
|
||
|
for c := '1'; c <= '9'; c++ {
|
||
|
if isAllowed(board, c, x, y) {
|
||
|
board[y][x] = c
|
||
|
if sudokuH(board, available, i+1) {
|
||
|
return true
|
||
|
}
|
||
|
board[y][x] = '.'
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// Receives a board and fills the empty positions with the correct
|
||
|
// value
|
||
|
func solveSudoku(board [][]rune) {
|
||
|
available := availablePos(board)
|
||
|
if sudokuH(board, available, 0) {
|
||
|
printBoard(board)
|
||
|
} else {
|
||
|
fmt.Println("Error")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
var board [][]rune
|
||
|
|
||
|
for _, v := range os.Args[1:] {
|
||
|
board = append(board, []rune(v))
|
||
|
}
|
||
|
|
||
|
if validBoard(board) {
|
||
|
solveSudoku(board)
|
||
|
} else {
|
||
|
fmt.Println("Error")
|
||
|
}
|
||
|
}
|