Refactor Sudoku solver architecture

This commit is contained in:
2026-09-10 23:11:34 +02:00
parent 7bf4a8d725
commit a5ec338277
21 changed files with 475 additions and 260 deletions
+6 -6
View File
@@ -1,7 +1,7 @@
package strategies
import (
"git.kleiax.de/homepage/board"
"git.kleiax.de/homepage/field"
)
// ────────────────────────────────────────────────────────────────────────────── //
@@ -13,20 +13,20 @@ type LastDigit struct {
}
func (ld *LastDigit) SearchProgressableCells() int {
ld.field.ForEachPart(func(part board.Part) {
ld.field.ForEachPart(func(part field.Part) {
missingNumbers := part.GetMissingNumbers()
if len(missingNumbers) == 1 {
var emptyCell *board.Cell
part.ForEachCell(func(cell *board.Cell) {
var emptyCell *field.Cell
part.ForEachCell(func(cell *field.Cell) {
if cell.GetNumber() == 0 {
emptyCell = cell
}
})
// fmt.Println(part)
// fmt.Printf("Gefundene Zelle: %d/%d - %d, missungNumber: %v, Typ: %T\n", emptyCell.Pos.GetRow(), emptyCell.Pos.GetColumn(), emptyCell.GetNumber(), missingNumbers, part)
change := board.ExternalChange{
change := field.ExternalChange{
Cell: emptyCell,
Action: board.ActionSetNumber,
Action: field.ActionSetNumber,
Value: missingNumbers[0],
From: emptyCell.GetNumber(),
TriggerdBy: ld.getName(),
+42
View File
@@ -1,5 +1,7 @@
package strategies
import "git.kleiax.de/homepage/field"
// ────────────────────────────────────────────────────────────────────────────── //
// HIDDEN_SINGLE STRUCTURE //
// ────────────────────────────────────────────────────────────────────────────── //
@@ -8,6 +10,46 @@ type HiddenSingle struct {
Base
}
func (hs *HiddenSingle) SearchProgressableCells() int {
hs.field.ForEachPart(func(part field.Part) {
m := make(map[int]int)
part.ForEachCell(func(cell *field.Cell) {
notes := cell.Notes.Get()
for note := range notes {
m[note]++
}
})
var hiddenSingles []int
for num, count := range m {
if count == 1 {
hiddenSingles = append(hiddenSingles, num)
}
}
for num := range hiddenSingles {
part.ForEachCell(func(cell *field.Cell) {
if cell.Notes.Has(num) {
change := field.ExternalChange{
Cell: cell,
Action: field.ActionSetNumber,
Value: num,
From: cell.GetNumber(),
TriggerdBy: hs.getName(),
}
hs.changes = append(hs.changes, change)
}
})
}
})
return len(hs.changes)
}
func (hs *HiddenSingle) getName() string {
return "Hidden Single"
}
// ────────────────────────────────────────────────────────────────────────────── //
// HIDDEN_PAIR STRUCTURE //
// ────────────────────────────────────────────────────────────────────────────── //
+5 -5
View File
@@ -1,6 +1,6 @@
package strategies
import "git.kleiax.de/homepage/board"
import "git.kleiax.de/homepage/field"
// ────────────────────────────────────────────────────────────────────────────── //
// NAKED_SINGLE STRUCTURE //
@@ -11,13 +11,13 @@ type NakedSingle struct {
}
func (ns *NakedSingle) SearchProgressableCells() int {
ns.field.ForEachPart(func(part board.Part) {
part.ForEachCell(func(cell *board.Cell) {
ns.field.ForEachPart(func(part field.Part) {
part.ForEachCell(func(cell *field.Cell) {
candidates := cell.Notes.Get()
if len(candidates) == 1 && cell.GetNumber() == 0 {
change := board.ExternalChange{
change := field.ExternalChange{
Cell: cell,
Action: board.ActionSetNumber,
Action: field.ActionSetNumber,
Value: candidates[0],
From: cell.GetNumber(),
TriggerdBy: ns.getName(),
+5 -5
View File
@@ -1,7 +1,7 @@
package strategies
import (
"git.kleiax.de/homepage/board"
"git.kleiax.de/homepage/field"
)
// ────────────────────────────────────────────────────────────────────────────── //
@@ -13,8 +13,8 @@ type Notes struct {
}
func (n *Notes) SearchProgressableCells() int {
n.field.ForEachRow(func(row *board.Row) {
row.ForEachCell(func(cell *board.Cell) {
n.field.ForEachRow(func(row *field.Row) {
row.ForEachCell(func(cell *field.Cell) {
column, _ := n.field.GetColumn(cell.Pos.GetColumn())
block, _ := n.field.GetBlock(cell.Pos.GetBlockRow(), cell.Pos.GetBlockColumn())
candidates := intersection3(row.GetMissingNumbers(), column.GetMissingNumbers(), block.GetMissingNumbers())
@@ -22,9 +22,9 @@ func (n *Notes) SearchProgressableCells() int {
if cell.Notes.Has(note) || cell.GetNumber() != 0 {
continue
}
ch := board.ExternalChange{
ch := field.ExternalChange{
Cell: cell,
Action: board.ActionSetNote,
Action: field.ActionSetNote,
Value: note,
TriggerdBy: n.getName(),
Marks: nil,
+12 -12
View File
@@ -3,7 +3,7 @@ package strategies
import (
"fmt"
"git.kleiax.de/homepage/board"
"git.kleiax.de/homepage/field"
)
// ────────────────────────────────────────────────────────────────────────────── //
@@ -11,9 +11,9 @@ import (
// ────────────────────────────────────────────────────────────────────────────── //
type Strategy interface {
Init(f *board.Field)
ApplyAll() []board.ExternalChange
ApplyNext() board.ExternalChange
Init(f *field.Field)
ApplyAll() []field.ExternalChange
ApplyNext() field.ExternalChange
Name() string
SearchProgressableCells() int
}
@@ -23,7 +23,7 @@ type Strategy interface {
// ────────────────────────────────────────────────────────────────────────────── //
type StrategyVisualization interface {
pointOut(f *board.Field) []board.Mark
pointOut(f *field.Field) []field.Mark
}
// ────────────────────────────────────────────────────────────────────────────── //
@@ -32,16 +32,16 @@ type StrategyVisualization interface {
type Base struct {
name string
field *board.Field
changes []board.ExternalChange
field *field.Field
changes []field.ExternalChange
}
func (b *Base) Init(f *board.Field) {
func (b *Base) Init(f *field.Field) {
b.field = f
}
func (b *Base) ApplyAll() []board.ExternalChange {
changesCopy := make([]board.ExternalChange, len(b.changes))
func (b *Base) ApplyAll() []field.ExternalChange {
changesCopy := make([]field.ExternalChange, len(b.changes))
copy(changesCopy, b.changes)
for _, change := range b.changes {
@@ -53,9 +53,9 @@ func (b *Base) ApplyAll() []board.ExternalChange {
return changesCopy
}
func (b *Base) ApplyNext() board.ExternalChange {
func (b *Base) ApplyNext() field.ExternalChange {
if len(b.changes) < 1 {
return board.ExternalChange{}
return field.ExternalChange{}
}
changeCopy := b.changes[0]