exercism/go/minesweeper/board.go

113 lines
1.9 KiB
Go

package minesweeper
import (
"bytes"
"errors"
"strconv"
)
const testVersion = 1
type Board [][]byte
// Count fills in the number of mines in adjacent squares on the board
func (b Board) Count() error {
if !b.isValid() {
return errors.New("Invalid Board")
}
for i := range b {
for j := range b[i] {
switch b[i][j] {
case '+', '-', '|', '*':
continue
case ' ':
num := b.countAdjacentMines(j, i)
if num != 0 {
b[i][j] = []byte(strconv.Itoa(num))[0]
}
default:
return errors.New("Invalid Board")
}
}
}
return nil
}
// countAdjacentMines returns the number of mines adjacent to x,y
// or -1 if x,y is invalid
func (b Board) countAdjacentMines(x, y int) int {
var numMines int
if b.isMine(x-1, y-1) {
numMines++
}
if b.isMine(x, y-1) {
numMines++
}
if b.isMine(x+1, y-1) {
numMines++
}
if b.isMine(x-1, y) {
numMines++
}
if b.isMine(x, y) {
numMines++
}
if b.isMine(x+1, y) {
numMines++
}
if b.isMine(x-1, y+1) {
numMines++
}
if b.isMine(x, y+1) {
numMines++
}
if b.isMine(x+1, y+1) {
numMines++
}
return numMines
}
func (b Board) isMine(x, y int) bool {
if x < 0 || y < 0 || x > len(b[0])-1 || y > len(b)-1 {
return false
}
return b[y][x] == '*'
}
func (b Board) isValid() bool {
if len(b) <= 0 {
// no size
return false
}
for i := range b {
if len(b[i]) != len(b[0]) {
// All rows must be same length
return false
}
for j := range b[i] {
// Check top & bottom row for border
if i == 0 || i == len(b)-1 {
// Check corners for border
if j == 0 || j == len(b[i])-1 {
if b[i][j] != '+' {
return false
}
} else if b[i][j] != '-' {
return false
}
} else {
if j == 0 || j == len(b[i])-1 {
if b[i][j] != '|' {
return false
}
}
}
}
}
return true
}
func (b Board) String() string {
return "\n" + string(bytes.Join(b, []byte{'\n'}))
}