(Feat): Initial Commit, Termdoku
This commit is contained in:
149
internal/game/board.go
Normal file
149
internal/game/board.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type Grid [9][9]uint8
|
||||
|
||||
type Move struct {
|
||||
Row int
|
||||
Col int
|
||||
Prev uint8
|
||||
Next uint8
|
||||
At time.Time
|
||||
}
|
||||
|
||||
type Board struct {
|
||||
Given [9][9]bool
|
||||
Values Grid
|
||||
}
|
||||
|
||||
func NewBoardFromPuzzle(p Grid) Board {
|
||||
var b Board
|
||||
for r := 0; r < 9; r++ {
|
||||
for c := 0; c < 9; c++ {
|
||||
v := p[r][c]
|
||||
if v != 0 {
|
||||
b.Given[r][c] = true
|
||||
}
|
||||
b.Values[r][c] = v
|
||||
}
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *Board) IsGiven(row, col int) bool { return b.Given[row][col] }
|
||||
|
||||
func (b *Board) SetValue(row, col int, v uint8) (prev uint8, ok bool) {
|
||||
if b.Given[row][col] {
|
||||
return b.Values[row][col], false
|
||||
}
|
||||
prev = b.Values[row][col]
|
||||
b.Values[row][col] = v
|
||||
return prev, true
|
||||
}
|
||||
|
||||
func InBounds(row, col int) bool { return row >= 0 && row < 9 && col >= 0 && col < 9 }
|
||||
|
||||
// DuplicateMap marks cells that duplicate the selected cell's value across row/col/box.
|
||||
func DuplicateMap(g Grid, selRow, selCol int) [9][9]bool {
|
||||
var dup [9][9]bool
|
||||
v := g[selRow][selCol]
|
||||
if v == 0 {
|
||||
return dup
|
||||
}
|
||||
for i := 0; i < 9; i++ {
|
||||
if g[selRow][i] == v && i != selCol {
|
||||
dup[selRow][i] = true
|
||||
}
|
||||
if g[i][selCol] == v && i != selRow {
|
||||
dup[i][selCol] = true
|
||||
}
|
||||
}
|
||||
r0 := (selRow / 3) * 3
|
||||
c0 := (selCol / 3) * 3
|
||||
for r := r0; r < r0+3; r++ {
|
||||
for c := c0; c < c0+3; c++ {
|
||||
if (r != selRow || c != selCol) && g[r][c] == v {
|
||||
dup[r][c] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return dup
|
||||
}
|
||||
|
||||
// DuplicateMapAll marks any duplicates in rows, columns, or 3x3 blocks across the entire grid.
|
||||
func DuplicateMapAll(g Grid) [9][9]bool {
|
||||
var dup [9][9]bool
|
||||
// rows
|
||||
for r := 0; r < 9; r++ {
|
||||
count := map[uint8]int{}
|
||||
for c := 0; c < 9; c++ {
|
||||
v := g[r][c]
|
||||
if v != 0 {
|
||||
count[v]++
|
||||
}
|
||||
}
|
||||
for c := 0; c < 9; c++ {
|
||||
v := g[r][c]
|
||||
if v != 0 && count[v] > 1 {
|
||||
dup[r][c] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// cols
|
||||
for c := 0; c < 9; c++ {
|
||||
count := map[uint8]int{}
|
||||
for r := 0; r < 9; r++ {
|
||||
v := g[r][c]
|
||||
if v != 0 {
|
||||
count[v]++
|
||||
}
|
||||
}
|
||||
for r := 0; r < 9; r++ {
|
||||
v := g[r][c]
|
||||
if v != 0 && count[v] > 1 {
|
||||
dup[r][c] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
// blocks
|
||||
for br := 0; br < 3; br++ {
|
||||
for bc := 0; bc < 3; bc++ {
|
||||
count := map[uint8]int{}
|
||||
for r := br * 3; r < br*3+3; r++ {
|
||||
for c := bc * 3; c < bc*3+3; c++ {
|
||||
v := g[r][c]
|
||||
if v != 0 {
|
||||
count[v]++
|
||||
}
|
||||
}
|
||||
}
|
||||
for r := br * 3; r < br*3+3; r++ {
|
||||
for c := bc * 3; c < bc*3+3; c++ {
|
||||
v := g[r][c]
|
||||
if v != 0 && count[v] > 1 {
|
||||
dup[r][c] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return dup
|
||||
}
|
||||
|
||||
// ConflictMap marks cells that violate Sudoku constraints (duplicates), excluding givens.
|
||||
func ConflictMap(values Grid, given [9][9]bool) [9][9]bool {
|
||||
all := DuplicateMapAll(values)
|
||||
var bad [9][9]bool
|
||||
for r := 0; r < 9; r++ {
|
||||
for c := 0; c < 9; c++ {
|
||||
if given[r][c] {
|
||||
continue
|
||||
}
|
||||
bad[r][c] = all[r][c]
|
||||
}
|
||||
}
|
||||
return bad
|
||||
}
|
||||
Reference in New Issue
Block a user