can start a game

This commit is contained in:
stryan 2022-02-20 18:36:52 -05:00
parent 32e7fa3278
commit 6c356c9731
9 changed files with 219 additions and 67 deletions

View File

@ -47,7 +47,7 @@ func TestNewBoard(t *testing.T) {
func TestGetPiece(t *testing.T) { func TestGetPiece(t *testing.T) {
b := NewBoard(4) b := NewBoard(4)
p := NewPiece(2, Red) p := NewPieceFromInt(2, Red)
b.board[0][0].entity = p b.board[0][0].entity = p
np, err := b.GetPiece(9, 9) np, err := b.GetPiece(9, 9)
if err == nil { if err == nil {
@ -68,7 +68,7 @@ func TestGetPiece(t *testing.T) {
func TestPlace(t *testing.T) { func TestPlace(t *testing.T) {
b := NewBoard(4) b := NewBoard(4)
p := NewPiece(2, Red) p := NewPieceFromInt(2, Red)
res, err := b.Place(8, 9, p) res, err := b.Place(8, 9, p)
if err == nil { if err == nil {
t.Errorf("able to place in invalid location") t.Errorf("able to place in invalid location")
@ -94,7 +94,7 @@ func TestPlace(t *testing.T) {
func TestRemove(t *testing.T) { func TestRemove(t *testing.T) {
b := NewBoard(4) b := NewBoard(4)
p := NewPiece(2, Red) p := NewPieceFromInt(2, Red)
res, err := b.Place(0, 0, p) res, err := b.Place(0, 0, p)
if err != nil { if err != nil {

51
colour_enumer.go Normal file
View File

@ -0,0 +1,51 @@
// Code generated by "enumer -type=Colour"; DO NOT EDIT.
//
package main
import (
"fmt"
)
const _ColourName = "RedBlueNoColour"
var _ColourIndex = [...]uint8{0, 3, 7, 15}
func (i Colour) String() string {
if i < 0 || i >= Colour(len(_ColourIndex)-1) {
return fmt.Sprintf("Colour(%d)", i)
}
return _ColourName[_ColourIndex[i]:_ColourIndex[i+1]]
}
var _ColourValues = []Colour{0, 1, 2}
var _ColourNameToValueMap = map[string]Colour{
_ColourName[0:3]: 0,
_ColourName[3:7]: 1,
_ColourName[7:15]: 2,
}
// ColourString retrieves an enum value from the enum constants string name.
// Throws an error if the param is not part of the enum.
func ColourString(s string) (Colour, error) {
if val, ok := _ColourNameToValueMap[s]; ok {
return val, nil
}
return 0, fmt.Errorf("%s does not belong to Colour values", s)
}
// ColourValues returns all values of the enum
func ColourValues() []Colour {
return _ColourValues
}
// IsAColour returns "true" if the value is listed in the enum definition. "false" otherwise
func (i Colour) IsAColour() bool {
for _, v := range _ColourValues {
if i == v {
return true
}
}
return false
}

View File

@ -8,7 +8,7 @@ import (
"strings" "strings"
) )
var cmdRegxp = regexp.MustCompile("([a-zA-Z])([1-9])(x|-)([a-zA-Z])([1-9])") var cmdRegxp = regexp.MustCompile("([a-zA-Z])([0-9])(x|-)([a-zA-Z])([0-9])")
var ranks = "ABCDEFHIJKLMNOPQRSTUVWXYZ" var ranks = "ABCDEFHIJKLMNOPQRSTUVWXYZ"
//RawCommand is a game command, converted from algebraic notation //RawCommand is a game command, converted from algebraic notation

View File

@ -17,6 +17,7 @@ func TestNewRawCommand(t *testing.T) {
}{ }{
{"A1xC3", true, 0, 1, 2, 3, "x"}, {"A1xC3", true, 0, 1, 2, 3, "x"},
{"d7-d1", true, 3, 7, 3, 1, "-"}, {"d7-d1", true, 3, 7, 3, 1, "-"},
{"c0-c1", true, 2, 0, 2, 1, "-"},
{"AA-k3", false, 0, 0, 0, 0, ""}, {"AA-k3", false, 0, 0, 0, 0, ""},
{"a1/b4", false, 0, 0, 0, 0, ""}, {"a1/b4", false, 0, 0, 0, 0, ""},
} }

18
game.go
View File

@ -19,6 +19,7 @@ const (
) )
//Colour reperensents player colour //Colour reperensents player colour
//go:generate enumer -type=Colour
type Colour int type Colour int
//Colour consts //Colour consts
@ -112,7 +113,7 @@ func (g *Game) Mutate(cmd *ParsedCommand) (bool, error) {
return false, errors.New("bad game state") return false, errors.New("bad game state")
} }
} }
return true, nil return res, nil
} }
//SetupPiece adds a piece to the board during setup //SetupPiece adds a piece to the board during setup
@ -120,11 +121,14 @@ func (g *Game) SetupPiece(x, y int, p *Piece) (bool, error) {
if g.state != gameSetup { if g.state != gameSetup {
return false, errors.New("Trying to setup piece when not in setup") return false, errors.New("Trying to setup piece when not in setup")
} }
if p == nil {
return false, errors.New("Tried to setup a nil piece")
}
if !g.board.validatePoint(x, y) { if !g.board.validatePoint(x, y) {
return false, errors.New("Invalid location") return false, errors.New("Invalid location")
} }
if p.Owner != g.board.GetColor(x, y) { if p.Owner != g.board.GetColor(x, y) {
return false, errors.New("Can't setup piece on enemy board") return false, fmt.Errorf("Can't setup piece on enemy board: %v != %v", p.Owner, g.board.GetColor(x, y))
} }
return g.board.Place(x, y, p) return g.board.Place(x, y, p)
} }
@ -208,7 +212,7 @@ func (g *Game) strike(x, y, s, t int) (bool, error) {
//endPiece lost //endPiece lost
g.board.Remove(s, t) g.board.Remove(s, t)
//scouts replace the piece that was destroyed //scouts replace the piece that was destroyed
if startPiece.Rank == 1 { if startPiece.Rank == Scout {
g.board.Remove(x, y) g.board.Remove(x, y)
g.board.Place(s, t, startPiece) g.board.Place(s, t, startPiece)
} }
@ -228,11 +232,15 @@ func (g *Game) combat(atk, def *Piece) (int, error) {
} }
//handle special cases first //handle special cases first
//miner hitting bomb //miner hitting bomb
if atk.Rank == 3 && def.Rank == 12 { if atk.Rank == Miner && def.Rank == Bomb {
return 1, nil return 1, nil
} }
//anyone else hitting bomb
if def.Rank == Bomb {
return -1, nil
}
//spy hitting marshal //spy hitting marshal
if atk.Rank == 0 && def.Rank == 10 { if atk.Rank == Spy && def.Rank == Marshal {
return 1, nil return 1, nil
} }
//normal cases //normal cases

View File

@ -1,29 +1,63 @@
package main package main
import "testing" import (
"errors"
"fmt"
"testing"
)
func dummyMiniGame() *Game { func dummyMiniGame() (*Game, error) {
g := &Game{ g := &Game{
board: NewBoard(4), board: NewBoard(4),
state: gameSetup, state: gameSetup,
} }
//Setup terrain //Setup terrain
g.board.AddTerrain(1, 1, 1) terrain := []struct {
g.board.AddTerrain(2, 2, 1) x, y, t int
//Setup blue (5 pieces) }{
g.SetupPiece(0, 0, NewPiece(0, Blue)) {1, 1, 1},
g.SetupPiece(0, 1, NewPiece(1, Blue)) {2, 2, 1},
g.SetupPiece(0, 2, NewPiece(2, Blue)) }
g.SetupPiece(0, 3, NewPiece(3, Blue)) for _, tt := range terrain {
g.SetupPiece(1, 3, NewPiece(4, Blue)) res, err := g.board.AddTerrain(tt.x, tt.y, tt.t)
//Setup red (5 pieces) if err != nil {
g.SetupPiece(3, 0, NewPiece(0, Red)) return nil, err
g.SetupPiece(3, 1, NewPiece(1, Red)) }
g.SetupPiece(3, 2, NewPiece(2, Red)) if !res {
g.SetupPiece(3, 3, NewPiece(3, Red)) return nil, errors.New("Error creating terrain")
g.SetupPiece(2, 1, NewPiece(4, Red)) }
}
pieces := []struct {
x, y int
p *Piece
}{
{0, 0, NewPiece(Flag, Blue)},
{3, 0, NewPiece(Spy, Blue)},
{2, 0, NewPiece(Captain, Blue)},
{3, 1, NewPiece(Marshal, Blue)},
{0, 1, NewPiece(Bomb, Blue)},
return g {1, 2, NewPiece(Flag, Red)},
{3, 2, NewPiece(Spy, Red)},
{2, 3, NewPiece(Captain, Red)},
{0, 2, NewPiece(Marshal, Red)},
{0, 3, NewPiece(Bomb, Red)},
}
for _, tt := range pieces {
res, err := g.SetupPiece(tt.x, tt.y, tt.p)
if err != nil {
return nil, fmt.Errorf("Piece %v,%v:%v", tt.x, tt.y, err)
}
if !res {
return nil, errors.New("error placing dummy piece")
}
}
_, err := g.SetupPiece(0, 0, NewPiece(Flag, Blue))
if err != nil {
return nil, err
}
return g, nil
} }
func TestNewGame(t *testing.T) { func TestNewGame(t *testing.T) {
@ -38,8 +72,8 @@ func TestNewGame(t *testing.T) {
func TestSetupPiece(t *testing.T) { func TestSetupPiece(t *testing.T) {
g := NewGame() g := NewGame()
p1 := NewPiece(0, Blue) p1 := NewPieceFromInt(0, Blue)
p2 := NewPiece(0, Red) p2 := NewPieceFromInt(0, Red)
res, err := g.SetupPiece(0, 0, p1) res, err := g.SetupPiece(0, 0, p1)
if err == nil || res == true { if err == nil || res == true {
t.Errorf("Expected to fail setup piece but didn't") t.Errorf("Expected to fail setup piece but didn't")
@ -57,7 +91,7 @@ func TestSetupPiece(t *testing.T) {
if err == nil { if err == nil {
t.Error("expected to fail setting up piece in invalid spot") t.Error("expected to fail setting up piece in invalid spot")
} }
res, err = g.SetupPiece(4, 0, p2) res, err = g.SetupPiece(4, 5, p2)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -75,3 +109,62 @@ func TestStart(t *testing.T) {
t.Fatal("expected game to start") t.Fatal("expected game to start")
} }
} }
func TestMiniCreation(t *testing.T) {
g, err := dummyMiniGame()
if err != nil {
t.Fatalf("mini game not created: %v", err)
}
if g.state != gameSetup {
t.Fatal("mini game not in right state")
}
}
func TestMiniGame1(t *testing.T) {
g, err := dummyMiniGame()
if err != nil {
t.Fatal(err)
}
if !g.Start() {
t.Fatal("could not start mini game")
}
if g.state != gameTurnRed {
t.Error("game starting on wrong turn")
}
r := NewDummyPlayer(Red)
b := NewDummyPlayer(Blue)
var moves = []struct {
input string
player Player
res bool
}{
{"c3-b3", r, true},
{"c0-c1", b, true},
{"d2xd1", r, true},
{"c1-d1", b, true},
{"b3-c3", r, true},
{"d1xd2", b, true},
}
i := 0
for _, tt := range moves {
tname := fmt.Sprintf("%v input: %v", i, tt.input)
i++
t.Run(tname, func(t *testing.T) {
raw, err := NewRawCommand(tt.input)
if err != nil {
t.Fatalf("error creating RawCommand from %v:%v", tt.input, err)
}
parsed, err := g.Parse(tt.player, raw)
if err != nil {
t.Fatal(err)
}
res, err := g.Mutate(parsed)
if err != nil {
t.Error(err)
}
if tt.res != res {
t.Errorf("Expected command to be %v but was %v", tt.res, res)
}
})
}
}

54
main.go
View File

@ -3,43 +3,16 @@ package main
import "fmt" import "fmt"
func main() { func main() {
red := NewDummyPlayer(Red) //red := NewDummyPlayer(Red)
blue := NewDummyPlayer(Blue) //blue := NewDummyPlayer(Blue)
game := NewGame() g := NewGame()
game.state = gameSetup g.state = gameSetup
addpiece(game, 0, Blue, 0, 0) printboardcolours(g)
addpiece(game, 1, Blue, 0, 1)
addpiece(game, 2, Blue, 1, 2)
addpiece(game, 3, Blue, 2, 4)
addpiece(game, 3, Blue, 1, 3)
addpiece(game, 4, Blue, 2, 6)
addpiece(game, 5, Blue, 3, 3)
addpiece(game, 9, Blue, 0, 6)
addpiece(game, 9, Blue, 0, 7)
addpiece(game, 0, Blue, 3, 5)
addriver(game, 3, 2)
addriver(game, 4, 2)
addriver(game, 3, 6)
addriver(game, 4, 6)
addpiece(game, 0, Red, 4, 0)
addpiece(game, 1, Red, 4, 1)
addpiece(game, 2, Red, 5, 2)
addpiece(game, 3, Red, 6, 4)
addpiece(game, 3, Red, 5, 3)
addpiece(game, 4, Red, 6, 6)
addpiece(game, 5, Red, 7, 3)
addpiece(game, 9, Red, 4, 5)
addpiece(game, 9, Red, 4, 7)
addpiece(game, 0, Red, 7, 5)
fmt.Printf("%v %v\n%v\n", red, blue, game)
game.Start()
return return
} }
func addpiece(game *Game, rank int, c Colour, x int, y int) { func addpiece(game *Game, rank int, c Colour, x int, y int) {
res, err := game.SetupPiece(x, y, NewPiece(rank, c)) res, err := game.SetupPiece(x, y, NewPieceFromInt(rank, c))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -57,3 +30,18 @@ func addriver(game *Game, x int, y int) {
panic("can't river") panic("can't river")
} }
} }
func printboardcolours(g *Game) {
for i := range g.board.board {
for j := range g.board.board[i] {
c := "X"
if g.board.board[i][j].colour == Red {
c = "R"
} else if g.board.board[i][j].colour == Blue {
c = "B"
}
fmt.Printf("%v", c)
}
fmt.Println("")
}
}

View File

@ -13,6 +13,7 @@ const (
Captain Captain
General General
Marshal Marshal
Bomb
) )
//Piece :game piece //Piece :game piece
@ -22,8 +23,8 @@ type Piece struct {
Hidden bool Hidden bool
} }
//NewPiece creates a new piece //NewPieceFromInt creates a new piece
func NewPiece(r int, o Colour) *Piece { func NewPieceFromInt(r int, o Colour) *Piece {
return &Piece{ return &Piece{
Rank: Rank(r), Rank: Rank(r),
Owner: o, Owner: o,
@ -31,6 +32,15 @@ func NewPiece(r int, o Colour) *Piece {
} }
} }
//NewPiece generates a piece by rank
func NewPiece(r Rank, o Colour) *Piece {
return &Piece{
Rank: r,
Owner: o,
Hidden: false,
}
}
//NewHiddenPiece creates a new hidden piece //NewHiddenPiece creates a new hidden piece
func NewHiddenPiece(o Colour) *Piece { func NewHiddenPiece(o Colour) *Piece {
return &Piece{ return &Piece{

View File

@ -7,9 +7,9 @@ import (
"fmt" "fmt"
) )
const _RankName = "FlagSpyScoutMinerCaptainGeneralMarshal" const _RankName = "FlagSpyScoutMinerCaptainGeneralMarshalBomb"
var _RankIndex = [...]uint8{0, 4, 7, 12, 17, 24, 31, 38} var _RankIndex = [...]uint8{0, 4, 7, 12, 17, 24, 31, 38, 42}
func (i Rank) String() string { func (i Rank) String() string {
if i < 0 || i >= Rank(len(_RankIndex)-1) { if i < 0 || i >= Rank(len(_RankIndex)-1) {
@ -18,7 +18,7 @@ func (i Rank) String() string {
return _RankName[_RankIndex[i]:_RankIndex[i+1]] return _RankName[_RankIndex[i]:_RankIndex[i+1]]
} }
var _RankValues = []Rank{0, 1, 2, 3, 4, 5, 6} var _RankValues = []Rank{0, 1, 2, 3, 4, 5, 6, 7}
var _RankNameToValueMap = map[string]Rank{ var _RankNameToValueMap = map[string]Rank{
_RankName[0:4]: 0, _RankName[0:4]: 0,
@ -28,6 +28,7 @@ var _RankNameToValueMap = map[string]Rank{
_RankName[17:24]: 4, _RankName[17:24]: 4,
_RankName[24:31]: 5, _RankName[24:31]: 5,
_RankName[31:38]: 6, _RankName[31:38]: 6,
_RankName[38:42]: 7,
} }
// RankString retrieves an enum value from the enum constants string name. // RankString retrieves an enum value from the enum constants string name.