package field import ( "fmt" "strings" ) // ────────────────────────────────────────────────────────────────────────────── // // META STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // type Properties struct { Rows int Columns int BlockRows int BlockColumns int BlockSizeRow int BlockSizeColumn int Rating float64 } // ────────────────────────────────────────────────────────────────────────────── // // FIELD STRUCTURE // // ────────────────────────────────────────────────────────────────────────────── // type Field struct { props *Properties cells [][]Cell changes []Change } func New(props Properties, cells [][]Cell) *Field { field := Field{ props: &props, cells: cells, } return &field } // ────────────────────────────────────────────────────────────────────────────── // // GETTER // // ────────────────────────────────────────────────────────────────────────────── // func (f *Field) GetRow(r int) (*Row, error) { if r >= f.props.Rows || r < 0 { return nil, outOfBound } cellPtrs := make([]*Cell, len(f.cells[r])) for i := range f.cells[r] { cellPtrs[i] = &f.cells[r][i] } return &Row{ Line: Line{ cells: cellPtrs, }, }, nil } func (f *Field) GetColumn(c int) (*Column, error) { if c >= f.props.Columns || c < 0 { return nil, outOfBound } // Performance result := &Column{ Line: Line{ cells: make([]*Cell, 0, f.props.Rows), }, } // Copying for _, row := range f.cells { result.cells = append(result.cells, &row[c]) } return result, nil } func (f *Field) GetBlock(r, c int) (*Block, error) { if r < 0 || r >= f.props.BlockRows || c < 0 || c >= f.props.BlockColumns { return nil, outOfBound } startRow := r * f.props.BlockSizeRow startCol := c * f.props.BlockSizeColumn block := &Block{ cells: make([][]*Cell, f.props.BlockSizeRow), } for row := range block.cells { // Effizientes Kopieren der Zeile block.cells[row] = make([]*Cell, f.props.BlockSizeColumn) for column := range block.cells[row] { block.cells[row][column] = &f.cells[startRow+row][startCol+column] } } return block, nil } func (f *Field) GetEachPartAtPos(pos *Position) []Part { row, err := f.GetRow(pos.row) if err != nil { return nil } column, err := f.GetColumn(pos.column) if err != nil { return nil } block, err := f.GetBlock(pos.blockRow, pos.blockColumn) if err != nil { return nil } return append([]Part{}, row, column, block) } func (f *Field) GetCell(r, c int) (*Cell, error) { if r > f.props.Rows || c > f.props.Columns { return nil, outOfBound } return &f.cells[r][c], nil } func (f *Field) GetRating() float64 { return f.props.Rating } // ────────────────────────────────────────────────────────────────────────────── // // FOREACH FUNCTIONS // // ────────────────────────────────────────────────────────────────────────────── // func (f *Field) ForEachPart(fn func(part Part)) { f.ForEachRow(func(row *Row) { fn(row) }) f.ForEachColumn(func(column *Column) { fn(column) }) f.ForEachBlock(func(block *Block) { fn(block) }) } func (f *Field) ForEachPartAtPos(pos *Position, fn func(part Part)) { parts := f.GetEachPartAtPos(pos) for _, part := range parts { fn(part) } } func (f *Field) ForEachRow(fn func(row *Row)) { for i := range f.props.Rows { row, err := f.GetRow(i) if err != nil { fmt.Println(err.Error()) return } fn(row) } } func (f *Field) ForEachColumn(fn func(column *Column)) { for i := range f.props.Columns { column, err := f.GetColumn(i) if err != nil { fmt.Println(err.Error()) return } fn(column) } } func (f *Field) ForEachBlock(fn func(block *Block)) { for r := range f.props.BlockRows { for c := range f.props.BlockColumns { block, err := f.GetBlock(r, c) if err != nil { fmt.Println(err.Error()) return } fn(block) } } } func (f *Field) ForEachCell(fn func(cell *Cell)) { for _, row := range f.cells { for _, cell := range row { fn(&cell) } } } // ────────────────────────────────────────────────────────────────────────────── // // MODIFIER // // ────────────────────────────────────────────────────────────────────────────── // func (f *Field) AddChange(eChange *ExternalChange) { change := Change{ Cell: eChange.Cell, marks: eChange.Marks, action: eChange.Action, value: eChange.Value, from: eChange.From, triggerdBy: eChange.TriggerdBy, } change.do() f.changes = append(f.changes, change) } func (f *Field) SetRating(rating float64) { f.props.Rating = rating } // ────────────────────────────────────────────────────────────────────────────── // // STATE // // ────────────────────────────────────────────────────────────────────────────── // func (f *Field) String() string { //TODO: auf beliebige größen anpassen var sb strings.Builder // Oberer Rahmen sb.WriteString("╔═══════╤═══════╤═══════╗\n") for i := range f.cells { sb.WriteString("║ ") // Linke Rahmenseite for j, cell := range f.cells[i] { // Wert ausgeben oder Punkt für 0 val := cell.number if val == 0 { sb.WriteString("·") } else { sb.WriteString(string('0' + val)) } // Trennlinien zwischen Blöcken und Zellen if (j+1)%3 == 0 { if j < 8 { sb.WriteString(" │ ") } else { sb.WriteString(" ║\n") // Rechte Rahmenseite + Zeilenumbruch } } else { sb.WriteString(" ") } } // Horizontale Trennlinien nach jeder 3. Zeile if (i+1)%3 == 0 && i < 8 { sb.WriteString("╟───────┼───────┼───────╢\n") } } // Unterer Rahmen sb.WriteString("╚═══════╧═══════╧═══════╝") return sb.String() } func (f *Field) StringNotesForNumber(n int) string { return "StringNotesForNumber is not implementet" } func (f *Field) StringNotes() string { var str strings.Builder fmt.Fprintf(&str, "Notes:\n") f.ForEachCell(func(cell *Cell) { fmt.Fprintf(&str, "Pos: %d/%d - Notes: %v\n", cell.Pos.row, cell.Pos.column, cell.Notes.numbers) }) return str.String() } func (f *Field) IsSolved() bool { result := true f.ForEachCell(func(cell *Cell) { if cell.number == 0 { result = false } }) /* TODO: if !f.isValid() { return false } */ return result } func (f *Field) IsValid() bool { //In jedem Part gibt es jede Zahl max ein mal //Die Zahl kommt nicht in intersecting parts vor return false }