From 62aaf967e7e70095a4417b35bf2e4589ccd5497e Mon Sep 17 00:00:00 2001 From: Maas Lalani <maas@lalani.dev> Date: Tue, 21 Dec 2021 23:24:53 -0500 Subject: [PATCH] extract position --- board/display.go | 92 ++++++++++++++++++++-------- board/position.go | 25 -------- position/position.go | 40 ++++++++++++ {board => position}/position_test.go | 2 +- 4 files changed, 109 insertions(+), 50 deletions(-) delete mode 100644 board/position.go create mode 100644 position/position.go rename {board => position}/position_test.go (97%) diff --git a/board/display.go b/board/display.go index f2f385f..e44dd1e 100644 --- a/board/display.go +++ b/board/display.go @@ -3,14 +3,19 @@ package board import ( "fmt" "strings" + + "github.com/maaslalani/gambit/position" ) var ( - border = []string{ - "┌", "┬", "┐", - "├", "┼", "┤", - "└", "┴", "┘", - } + border = []string{"┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘"} + + borderBottomOffset = 6 + borderMiddleOffset = 3 + borderTopOffset = 0 + + files = []string{"A", "B", "C", "D", "E", "F", "G", "H"} + ranks = []int{7, 6, 5, 4, 3, 2, 1, 0} ) const ( @@ -19,35 +24,39 @@ const ( marginLeft = " " ) -var ( - files = []string{"A", "B", "C", "D", "E", "F", "G", "H"} - ranks = []int{7, 6, 5, 4, 3, 2, 1, 0} -) - +// String prints the board in a human readable format. +// The left and bottom sides have labels for ranks and files respectively +// All pieces are surrounded with borders. func (b Board) String() string { var s string + if b.reversed { - ranks = []int{0, 1, 2, 3, 4, 5, 6, 7} + ranks = reverse(ranks) } + for r, row := range ranks { - if r == 0 { - s += buildRow(border[0], border[1], border[2]) - s += "\n" + + if isFirstRow(r) { + s += buildRow(borderTopOffset) + "\n" } + for c, cell := range b.grid[row] { - if c == 0 { - s += fmt.Sprintf(" %d ", row+1) + if isFirstColumn(c) { + s += fmt.Sprintf(" %d ", position.RowToRank(row)) } + s += fmt.Sprintf("%s %s ", vertical, cell) - if c == len(ranks)-1 { + + if isLastColumn(c) { s += vertical } } - if r < len(b.grid)-1 { - s += buildRow(border[3], border[4], border[5]) + + if !isLastRow(r) { + s += buildRow(borderMiddleOffset) } else { - s += buildRow(border[6], border[7], border[8]) - s += "\n " + marginLeft + s += buildRow(borderBottomOffset) + s += "\n " s += strings.Join(files, " ") } s += "\n" @@ -56,12 +65,47 @@ func (b Board) String() string { return s } -func buildRow(left, middle, right string) string { +// isLastRow returns whether or not the given row is the last row of the +// board based on the number of ranks on the board. +func isLastRow(i int) bool { + return i == len(ranks)-1 +} + +// isLastColumn returns whether or not the given column is the last column of +// the board based on the number of files on the board. +func isLastColumn(i int) bool { + return i == len(files)-1 +} + +// isFirstRow returns whether or not the given row is the first row +func isFirstRow(i int) bool { + return i == 0 +} + +// isFirstColumn returns whether or not the given column is the first column +func isFirstColumn(i int) bool { + return i == 0 +} + +// buildRow builds a row string based on the given borders for the left and +// right side and correctly pads the middle with the given character adjusted +// to the number of rows on the board. +func buildRow(borderOffset int) string { + var left, middle, right = border[borderOffset], border[borderOffset+1], border[borderOffset+2] var row []string row = append(row, left) - for i := 0; i < 7; i++ { + for i := 0; i < len(ranks)-1; i++ { row = append(row, middle) } row = append(row, right) - return fmt.Sprintf("\n%s%s", marginLeft, strings.Join(row, horizontal+horizontal+horizontal)) + return fmt.Sprintf("\n %s", strings.Join(row, horizontal+horizontal+horizontal)) +} + +// reverse reverses the given slice of ints. +func reverse(ranks []int) []int { + var reversed []int + for i := len(ranks) - 1; i >= 0; i-- { + reversed = append(reversed, ranks[i]) + } + return reversed } diff --git a/board/position.go b/board/position.go deleted file mode 100644 index 4a50be2..0000000 --- a/board/position.go +++ /dev/null @@ -1,25 +0,0 @@ -package board - -import ( - "fmt" - "strconv" -) - -type Position struct { - Row int // rank - Col int // file -} - -func (p Position) String() string { - // Given a position in row, column form we return a readable - // string that represents a rank and file such as E4 or G7 - return fmt.Sprintf("%c%d", p.Col+'A', p.Row+1) -} - -func ToPosition(s string) Position { - // Given a string such as E4 or G7, we return a position in - // row, column form to be used as a position in the board's - parsed, _ := strconv.Atoi(string(s[1])) - row := parsed - 1 - return Position{row, int(s[0] - 'A')} -} diff --git a/position/position.go b/position/position.go new file mode 100644 index 0000000..e43dbc2 --- /dev/null +++ b/position/position.go @@ -0,0 +1,40 @@ +package position + +import ( + "fmt" + "strconv" +) + +type Position struct { + Row int // rank + Col int // file +} + +func (p Position) String() string { + // Given a position in row, column form we return a readable + // string that represents a rank and file such as E4 or G7 + return fmt.Sprintf("%c%d", ColumnToFile(p.Col), RowToRank(p.Row)) +} + +func ToPosition(s string) Position { + // Given a string such as E4 or G7, we return a position in + // row, column form to be used as a position in the board's + return Position{RankToRow(s[1]), FileToColumn(s[0])} +} + +func RowToRank(row int) int { + return row + 1 +} + +func RankToRow(rank byte) int { + parsed, _ := strconv.Atoi(string(rank)) + return parsed - 1 +} + +func ColumnToFile(column int) string { + return fmt.Sprintf("%c", column+'A') +} + +func FileToColumn(file byte) int { + return int(file - 'A') +} diff --git a/board/position_test.go b/position/position_test.go similarity index 97% rename from board/position_test.go rename to position/position_test.go index a6b9e20..797e875 100644 --- a/board/position_test.go +++ b/position/position_test.go @@ -1,4 +1,4 @@ -package board +package position import "testing"