From 9a69d4610ccf58a822086275adbe30ed3f6a4430 Mon Sep 17 00:00:00 2001 From: Alexander Klein Date: Sun, 19 Jul 2026 11:18:16 +0200 Subject: [PATCH] refactore to new project structure --- board/cell.go | 10 ++++++++++ board/changes.go | 15 ++++++++++++++- board/field.go | 14 +++++++------- board/parser.go | 12 ++++++------ logic/solver.go | 17 ++++++++++------- logic/strategies/divers.go | 28 +++++++++++++++------------- logic/strategies/naked.go | 22 ++++++++++++---------- logic/strategies/strategy.go | 32 +++++++++++++++----------------- main.go | 15 +++++++++------ sudoku.go => sudoku/sudoku.go | 18 +++++++++--------- todo.md | 1 + visualization.go | 5 ----- 12 files changed, 108 insertions(+), 81 deletions(-) rename sudoku.go => sudoku/sudoku.go (58%) create mode 100644 todo.md delete mode 100644 visualization.go diff --git a/board/cell.go b/board/cell.go index 8d9496e..1275d5b 100644 --- a/board/cell.go +++ b/board/cell.go @@ -43,6 +43,12 @@ func (n *Notes) Remove(field *Field, cell *Cell, note int, trigger string, marks } } +func (n *Notes) Get() []int { + copySlice := make([]int, len(n.numbers)) + copy(copySlice, n.numbers) + return copySlice +} + // ────────────────────────────────────────────────────────────────────────────── // // CELL STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // @@ -98,3 +104,7 @@ func (c *Cell) RemoveNumber(field *Field, trigger string, marks []Mark) { c.number = 0 } + +func (c *Cell) GetNumber() int { + return c.number +} diff --git a/board/changes.go b/board/changes.go index f709c92..f42a9f7 100644 --- a/board/changes.go +++ b/board/changes.go @@ -17,7 +17,7 @@ func (m *Mark) GetColor() color.Color { } // ────────────────────────────────────────────────────────────────────────────── // -// CHANGE STRUCTURE // +// CHANGE_ACTION TYPE // // ────────────────────────────────────────────────────────────────────────────── // type ChangeAction int @@ -33,6 +33,19 @@ const ( // CHANGE STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // +type ExternalChange struct { + Cell *Cell + Marks []Mark + Action ChangeAction + Value int + From int + TriggerdBy string //strategy or manuell +} + +// ────────────────────────────────────────────────────────────────────────────── // +// CHANGE STRUCTURE // +// ────────────────────────────────────────────────────────────────────────────── // + type Change struct { Cell *Cell marks []Mark diff --git a/board/field.go b/board/field.go index 79416d8..78b3b64 100644 --- a/board/field.go +++ b/board/field.go @@ -145,14 +145,14 @@ func (f *Field) ForEachCell(fn func(cell *Cell)) { // MODIFIER // // ────────────────────────────────────────────────────────────────────────────── // -func (f *Field) AddChange(cell *Cell, action ChangeAction, value, from int, trigger string, marks []Mark) { +func (f *Field) AddChange(eChange *ExternalChange) { change := Change{ - Cell: cell, - marks: marks, - action: action, - value: value, - from: from, - triggerdBy: trigger, + Cell: eChange.Cell, + marks: eChange.Marks, + action: eChange.Action, + value: eChange.Value, + from: eChange.From, + triggerdBy: eChange.TriggerdBy, } change.do() diff --git a/board/parser.go b/board/parser.go index e8fa897..ccbfc08 100644 --- a/board/parser.go +++ b/board/parser.go @@ -8,23 +8,23 @@ import ( ) type Parser interface { - parse(data []byte) error - getField(i int) *Field - getAllFields() []Field + Parse(data []byte) error + GetField(i int) *Field + GetAllFields() []Field } type parserHelper struct { fields []Field } -func (ph *parserHelper) getField(i int) *Field { +func (ph *parserHelper) GetField(i int) *Field { if i < 0 || i >= len(ph.fields) { return &Field{} } return &ph.fields[i] } -func (ph *parserHelper) getAllFields() []Field { +func (ph *parserHelper) GetAllFields() []Field { if len(ph.fields) == 0 { return nil } @@ -36,7 +36,7 @@ type PuzzleBank struct { parserHelper } -func (pb *PuzzleBank) parse(data []byte) error { +func (pb *PuzzleBank) Parse(data []byte) error { lines := bytes.Split(data, []byte("\n")) for _, line := range lines { diff --git a/logic/solver.go b/logic/solver.go index e5ec633..007df64 100644 --- a/logic/solver.go +++ b/logic/solver.go @@ -1,30 +1,33 @@ package logic -import "git.kleiax.de/homepage/libs/sudoku/board" +import ( + "git.kleiax.de/homepage/board" + "git.kleiax.de/homepage/logic/strategies" +) // ────────────────────────────────────────────────────────────────────────────── // // SOLVER STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // type Solver struct { - strategies []Strategy + strategies []strategies.Strategy conf struct { all bool repeat bool } } -func (s *Solver) Add(strategy Strategy) { +func (s *Solver) Add(strategy strategies.Strategy) { s.strategies = append(s.strategies, strategy) } -func (s *Solver) initStragies(field *board.Field) { +func (s *Solver) InitStragies(field *board.Field) { for _, strategy := range s.strategies { strategy.Init(field) } } -func (s *Solver) run(i int) bool { +func (s *Solver) Run(i int) bool { //TODO: clean und Fehlerauffangen s.strategies[i].SearchProgressableCells() numberOfChanges := s.strategies[i].ApplyAll() @@ -34,10 +37,10 @@ func (s *Solver) run(i int) bool { return true } -func (s *Solver) search() { +func (s *Solver) Search() { } -func (s *Solver) getSolutionPath() []board.Change { +func (s *Solver) GetSolutionPath() []board.ExternalChange { return nil } diff --git a/logic/strategies/divers.go b/logic/strategies/divers.go index fed6726..3f7a0a3 100644 --- a/logic/strategies/divers.go +++ b/logic/strategies/divers.go @@ -1,6 +1,6 @@ package strategies -import "git.kleiax.de/homepage/libs/sudoku/board" +import "git.kleiax.de/homepage/board" // ────────────────────────────────────────────────────────────────────────────── // // LAST_DIGIT STRUCTURE // @@ -14,18 +14,20 @@ func (ld *LastDigit) SearchProgressableCells() int { ld.field.ForEachPart(func(part board.Part) { missingNumbers := part.GetMissingNumbers() if len(missingNumbers) == 1 { - // var emptyCell *Cell - // part.forEachCell(func(cell *Cell) { - // if cell.number == 0 { - // emptyCell = cell - // } - // }) - // change := Change{ - // cell: emptyCell, - // action: ActionSetNumber, - // value: missingNumbers[0], - // } - // ld.changes = append(ld.changes, change) + var emptyCell *board.Cell + part.ForEachCell(func(cell *board.Cell) { + if cell.GetNumber() == 0 { + emptyCell = cell + } + }) + change := board.ExternalChange{ + Cell: emptyCell, + Action: board.ActionSetNumber, + Value: missingNumbers[0], + From: emptyCell.GetNumber(), + TriggerdBy: ld.getName(), + } + ld.changes = append(ld.changes, change) } }) //fmt.Printf("LastDigit Changes %d", len(ld.changes)) diff --git a/logic/strategies/naked.go b/logic/strategies/naked.go index 524fce0..3bc1785 100644 --- a/logic/strategies/naked.go +++ b/logic/strategies/naked.go @@ -1,6 +1,6 @@ package strategies -import "git.kleiax.de/homepage/libs/sudoku/board" +import "git.kleiax.de/homepage/board" // ────────────────────────────────────────────────────────────────────────────── // // NAKED_SINGLE STRUCTURE // @@ -13,15 +13,17 @@ type NakedSingle struct { func (ns *NakedSingle) SearchProgressableCells() int { ns.field.ForEachPart(func(part board.Part) { part.ForEachCell(func(cell *board.Cell) { - // candidates := cell.notes.numbers - // if len(candidates) == 1 { - // change := Change{ - // cell: cell, - // action: ActionSetNumber, - // value: candidates[0], - // } - // ns.changes = append(ns.changes, change) - // } + candidates := cell.Notes.Get() + if len(candidates) == 1 { + change := board.ExternalChange{ + Cell: cell, + Action: board.ActionSetNumber, + Value: candidates[0], + From: cell.GetNumber(), + TriggerdBy: ns.getName(), + } + ns.changes = append(ns.changes, change) + } }) }) return len(ns.changes) diff --git a/logic/strategies/strategy.go b/logic/strategies/strategy.go index 9b9e001..58dbf40 100644 --- a/logic/strategies/strategy.go +++ b/logic/strategies/strategy.go @@ -3,7 +3,7 @@ package strategies import ( "fmt" - "git.kleiax.de/homepage/libs/sudoku/board" + "git.kleiax.de/homepage/board" ) // ────────────────────────────────────────────────────────────────────────────── // @@ -14,11 +14,18 @@ type Strategy interface { Init(f *board.Field) ApplyAll() int ApplyNext() bool - ApplyOne(n int) bool Name() string SearchProgressableCells() int } +// ────────────────────────────────────────────────────────────────────────────── // +// VISUALITION INTERFACE // +// ────────────────────────────────────────────────────────────────────────────── // + +type StrategyVisualization interface { + pointOut(f *board.Field) []board.Mark +} + // ────────────────────────────────────────────────────────────────────────────── // // BASE STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // @@ -26,7 +33,7 @@ type Strategy interface { type Base struct { name string field *board.Field - changes []board.Change //eigener Typ muss her + changes []board.ExternalChange } func (b *Base) Init(f *board.Field) { @@ -34,9 +41,9 @@ func (b *Base) Init(f *board.Field) { } func (b *Base) ApplyAll() int { - // for _, change := range sb.changes { - // //change.do() - // } + for _, change := range b.changes { + b.field.AddChange(&change) + } return len(b.changes) } @@ -44,24 +51,15 @@ func (b *Base) ApplyNext() bool { if len(b.changes) < 1 { return false } - //sb.changes[0].do() + b.field.AddChange(&b.changes[0]) b.changes = b.changes[1:] return true } -func (b *Base) ApplyOne(n int) bool { - if len(b.changes) <= n || n < 0 { - return false - } - //sb.changes[n].do() - b.changes = append(b.changes[:n], b.changes[n+1:]...) - return true -} - func (b *Base) getName() string { return "Unkown" } func (b *Base) Name() string { - return fmt.Sprintf("Die Strategie heißt: %s", b.getName()) + return fmt.Sprintf("Diese Strategie heißt: %s", b.getName()) } diff --git a/main.go b/main.go index 941b75a..cf16b3c 100644 --- a/main.go +++ b/main.go @@ -5,14 +5,17 @@ import ( "io" "os" - "git.kleiax.de/homepage/libs/sudoku" + "git.kleiax.de/homepage/board" + "git.kleiax.de/homepage/logic" + "git.kleiax.de/homepage/logic/strategies" + "git.kleiax.de/homepage/sudoku" ) func main() { - solver := sudoku.Solver{} - solver.Add(&sudoku.LastDigit{}) - solver.Add(&sudoku.NakedSingle{}) - game, err := sudoku.New(&sudoku.PuzzleBank{}, solver, openFile()) + solver := logic.Solver{} + solver.Add(&strategies.LastDigit{}) + solver.Add(&strategies.NakedSingle{}) + game, err := sudoku.New(&board.PuzzleBank{}, solver, openFile()) if err != nil { fmt.Println(err.Error()) os.Exit(1) @@ -31,7 +34,7 @@ func main() { } func openFile() []byte { - file, err := os.Open("libs/sudoku/data/sudoku-exchange-puzzle-bank/easy3.txt") + file, err := os.Open("data/sudoku-exchange-puzzle-bank/easy3.txt") if err != nil { fmt.Println("Kann datei nicht öffnen") os.Exit(3) diff --git a/sudoku.go b/sudoku/sudoku.go similarity index 58% rename from sudoku.go rename to sudoku/sudoku.go index 44b3f10..be3dca1 100644 --- a/sudoku.go +++ b/sudoku/sudoku.go @@ -4,8 +4,8 @@ import ( "errors" "fmt" - "git.kleiax.de/homepage/libs/sudoku/board" - "git.kleiax.de/homepage/libs/sudoku/logic" + "git.kleiax.de/homepage/board" + "git.kleiax.de/homepage/logic" ) type Game struct { @@ -13,16 +13,16 @@ type Game struct { solver logic.Solver } -func New(parser Parser, solver Solver, data []byte) (*Game, error) { - err := parser.parse(data) +func New(parser board.Parser, solver logic.Solver, data []byte) (*Game, error) { + err := parser.Parse(data) if err != nil { return &Game{}, fmt.Errorf("can not create game: %w", err) } - return &Game{solver: solver, field: parser.getField(0)}, nil + return &Game{solver: solver, field: parser.GetField(0)}, nil } func (g *Game) Solve() error { - g.solver.initStragies(g.field) + g.solver.InitStragies(g.field) for !g.isFinished() { if !g.nextSolveStep() { return errors.New("no strategy can solve the puzzle") @@ -32,7 +32,7 @@ func (g *Game) Solve() error { } func (g *Game) nextSolveStep() bool { - return g.solver.run(0) + return g.solver.Run(0) } func (g *Game) prevSolveStep() { @@ -40,9 +40,9 @@ func (g *Game) prevSolveStep() { } func (g *Game) isFinished() bool { - return g.field.isSolved() + return g.field.IsSolved() } -func (g *Game) GetField() Field { +func (g *Game) GetField() board.Field { return *g.field } diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..a3baba9 --- /dev/null +++ b/todo.md @@ -0,0 +1 @@ +- Parser kann eigenes Package sein nur das Interface und die Helfer funktionen im Board lassen, jeder kann einen Parser für sseine Quelle schreiben. Vielleicht ein Standardparser in Board für gängige Typen oder Hilfsfunktionen \ No newline at end of file diff --git a/visualization.go b/visualization.go deleted file mode 100644 index cdd18fe..0000000 --- a/visualization.go +++ /dev/null @@ -1,5 +0,0 @@ -package sudoku - -// type StrategyVisualization interface { -// pointOut(f *Field) []Mark -// }