package field import ( "fmt" "strings" ) type Part interface { IsSolved() bool ForEachCell(fn func(cell *Cell)) GetMissingNumbers() []int RemoveNote(field *Field, note int, trigger string, marks []Mark) String() string } // ────────────────────────────────────────────────────────────────────────────── // // LINE STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // type Line struct { cells []*Cell } func (l *Line) IsSolved() bool { //TODO return false } func (l *Line) ForEachCell(fn func(cell *Cell)) { for _, cell := range l.cells { fn(cell) } } func (l *Line) GetMissingNumbers() []int { return getMissingNumbersHelper(len(l.cells), l.ForEachCell) } func (l *Line) RemoveNote(field *Field, note int, trigger string, marks []Mark) { l.ForEachCell(func(cell *Cell) { cell.Notes.Remove(field, cell, note, trigger, marks) }) } func (l *Line) String() string { return lineString(l, "Line") } // ────────────────────────────────────────────────────────────────────────────── // // ROW STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // type Row struct { Line } func (r *Row) String() string { return lineString(r, "Row") } // ────────────────────────────────────────────────────────────────────────────── // // COLUMN STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // type Column struct { Line } func (c *Column) String() string { return lineString(c, "Column") } // ────────────────────────────────────────────────────────────────────────────── // // BLOCK STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // type Block struct { cells [][]*Cell } func (b *Block) IsSolved() bool { //TODO return false } func (b *Block) ForEachCell(fn func(cell *Cell)) { for _, row := range b.cells { for _, cell := range row { fn(cell) } } } func (b *Block) GetMissingNumbers() []int { max := len(b.cells) * len(b.cells[0]) return getMissingNumbersHelper(max, b.ForEachCell) } func (b *Block) RemoveNote(field *Field, note int, trigger string, marks []Mark) { b.ForEachCell(func(cell *Cell) { cell.Notes.Remove(field, cell, note, trigger, marks) }) } func (b *Block) String() string { var str strings.Builder str.WriteString("Block:\t") lastLine := 0 b.ForEachCell(func(cell *Cell) { fmt.Fprintf(&str, "%d ", cell.number) if lastLine == cell.Pos.inBlockRow { } }) return str.String() } // ────────────────────────────────────────────────────────────────────────────── // // HELPER // // ────────────────────────────────────────────────────────────────────────────── // func lineString(part Part, name string) string { var str strings.Builder fmt.Fprintf(&str, "%s:\t", name) part.ForEachCell(func(cell *Cell) { fmt.Fprintf(&str, "%d ", cell.number) }) return str.String() } func getMissingNumbersHelper(max int, iterate func(fn func(cell *Cell))) []int { present := make(map[int]bool, max) iterate(func(cell *Cell) { if cell.number != 0 { present[cell.number] = true } }) var missing []int for i := 1; i <= max; i++ { if !present[i] { missing = append(missing, i) } } return missing }