Refactor Sudoku solver architecture
This commit is contained in:
+123
@@ -0,0 +1,123 @@
|
||||
package field
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
// NOTES STRUCTURE //
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
|
||||
import "slices"
|
||||
|
||||
type Notes struct {
|
||||
numbers []int
|
||||
}
|
||||
|
||||
func (n *Notes) Add(field *Field, cell *Cell, note int, trigger string, marks []Mark) {
|
||||
if slices.Contains(n.numbers, note) {
|
||||
return // Note already exists
|
||||
}
|
||||
field.changes = append(field.changes, Change{
|
||||
Cell: cell,
|
||||
marks: marks,
|
||||
action: ActionSetNote,
|
||||
value: note,
|
||||
from: 0,
|
||||
triggerdBy: trigger,
|
||||
})
|
||||
n.numbers = append(n.numbers, note)
|
||||
}
|
||||
|
||||
func (n *Notes) Remove(field *Field, cell *Cell, note int, trigger string, marks []Mark) {
|
||||
for i, existing := range n.numbers {
|
||||
if existing == note {
|
||||
field.changes = append(field.changes, Change{
|
||||
Cell: cell,
|
||||
marks: marks,
|
||||
action: ActionRemoveNote,
|
||||
value: 0,
|
||||
from: note,
|
||||
triggerdBy: trigger,
|
||||
})
|
||||
|
||||
n.numbers = append(n.numbers[:i], n.numbers[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Notes) Get() []int {
|
||||
copySlice := make([]int, len(n.numbers))
|
||||
copy(copySlice, n.numbers)
|
||||
return copySlice
|
||||
}
|
||||
|
||||
func (n *Notes) Has(i int) bool {
|
||||
return slices.Contains(n.numbers, i)
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
// CELL STRUCTURE //
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
|
||||
type Cell struct {
|
||||
number int
|
||||
Notes *Notes
|
||||
Pos *Position
|
||||
}
|
||||
|
||||
func NewCell(number int, pos *Position) *Cell {
|
||||
cell := Cell{
|
||||
number: number,
|
||||
Pos: pos,
|
||||
Notes: &Notes{},
|
||||
}
|
||||
return &cell
|
||||
}
|
||||
|
||||
func (c *Cell) SetNumber(field *Field, n int, trigger string, marks []Mark) {
|
||||
if c.number == n {
|
||||
return
|
||||
}
|
||||
|
||||
if field == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if n <= 0 || n > field.props.Rows || n > field.props.Columns {
|
||||
return
|
||||
}
|
||||
|
||||
field.changes = append(field.changes, Change{
|
||||
Cell: c,
|
||||
marks: marks,
|
||||
action: ActionSetNumber,
|
||||
value: n,
|
||||
from: c.number,
|
||||
triggerdBy: trigger,
|
||||
})
|
||||
|
||||
c.number = n
|
||||
}
|
||||
|
||||
func (c *Cell) RemoveNumber(field *Field, trigger string, marks []Mark) {
|
||||
if c.number == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if field == nil {
|
||||
return
|
||||
}
|
||||
|
||||
field.changes = append(field.changes, Change{
|
||||
action: ActionSetNumber,
|
||||
Cell: c,
|
||||
value: 0,
|
||||
from: c.number,
|
||||
marks: marks,
|
||||
triggerdBy: trigger,
|
||||
})
|
||||
|
||||
c.number = 0
|
||||
}
|
||||
|
||||
func (c *Cell) GetNumber() int {
|
||||
return c.number
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package field
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
)
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
// MARK STRUCTURE //
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
|
||||
type Mark struct {
|
||||
Cell *Cell
|
||||
Change *Change
|
||||
color color.Color
|
||||
}
|
||||
|
||||
func (m *Mark) GetColor() color.Color {
|
||||
return m.color
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
// CHANGE_ACTION TYPE //
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
|
||||
type ChangeAction int
|
||||
|
||||
const (
|
||||
ActionSetNumber = iota
|
||||
ActionSetNote
|
||||
ActionRemoveNumber
|
||||
ActionRemoveNote
|
||||
)
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
// 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
|
||||
action ChangeAction
|
||||
value int
|
||||
from int
|
||||
triggerdBy string //strategy or manuell
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
// GETTER //
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
|
||||
func (c *Change) GetMarks() []Mark {
|
||||
return c.marks
|
||||
}
|
||||
|
||||
func (c *Change) GetAction() ChangeAction {
|
||||
return c.action
|
||||
}
|
||||
|
||||
func (c *Change) GetTo() int {
|
||||
return c.value
|
||||
}
|
||||
|
||||
func (c *Change) GetFrom() int {
|
||||
return c.from
|
||||
}
|
||||
|
||||
func (c *Change) GetTriggeredBy() string {
|
||||
return c.triggerdBy
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
// ??? //
|
||||
// ────────────────────────────────────────────────────────────────────────────── //
|
||||
|
||||
func (c *Change) do() {
|
||||
switch c.action {
|
||||
|
||||
case ActionSetNumber:
|
||||
c.Cell.number = c.value
|
||||
|
||||
case ActionSetNote:
|
||||
c.Cell.Notes.numbers = append(c.Cell.Notes.numbers, c.value)
|
||||
|
||||
case ActionRemoveNumber:
|
||||
c.Cell.number = 0
|
||||
|
||||
case ActionRemoveNote:
|
||||
for i, existing := range c.Cell.Notes.numbers {
|
||||
if existing == c.from {
|
||||
c.Cell.Notes.numbers = append(c.Cell.Notes.numbers[:i], c.Cell.Notes.numbers[i+1:]...)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package field
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
outOfBound = errors.New("invalid coordinates")
|
||||
invalidField = errors.New("can not parse Field")
|
||||
)
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
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
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package field
|
||||
|
||||
type Position struct {
|
||||
row int
|
||||
column int
|
||||
blockRow int
|
||||
blockColumn int
|
||||
inBlockRow int
|
||||
inBlockColumn int
|
||||
}
|
||||
|
||||
func NewPosition(row, column, blockRow, blockColumn, inBlockRow, inBlockColumn int) *Position {
|
||||
pos := Position{
|
||||
row: row,
|
||||
column: column,
|
||||
blockRow: blockRow,
|
||||
blockColumn: blockColumn,
|
||||
inBlockRow: inBlockRow,
|
||||
inBlockColumn: inBlockColumn,
|
||||
}
|
||||
return &pos
|
||||
}
|
||||
|
||||
func (p *Position) GetRow() int {
|
||||
return p.row
|
||||
}
|
||||
|
||||
func (p *Position) GetColumn() int {
|
||||
return p.column
|
||||
}
|
||||
|
||||
func (p *Position) GetBlockRow() int {
|
||||
return p.blockRow
|
||||
}
|
||||
|
||||
func (p *Position) GetBlockColumn() int {
|
||||
return p.blockColumn
|
||||
}
|
||||
|
||||
func (p *Position) GetInBlockRow() int {
|
||||
return p.inBlockRow
|
||||
}
|
||||
|
||||
func (p *Position) GetInBlockColumn() int {
|
||||
return p.inBlockColumn
|
||||
}
|
||||
|
||||
func (p *Position) GetCoords() (int, int) {
|
||||
return p.row, p.column
|
||||
}
|
||||
|
||||
func (p *Position) GetBlockCoords() (int, int) {
|
||||
return p.blockRow, p.blockColumn
|
||||
}
|
||||
|
||||
func (p *Position) GetInBlockCoords() (int, int) {
|
||||
return p.inBlockRow, p.inBlockColumn
|
||||
}
|
||||
Reference in New Issue
Block a user