diff --git a/board_test.go b/board_test.go index 215a95d..befd397 100644 --- a/board_test.go +++ b/board_test.go @@ -47,7 +47,7 @@ func TestNewBoard(t *testing.T) { func TestGetPiece(t *testing.T) { b := NewBoard(4) - p := NewPiece(2, Red) + p := NewPieceFromInt(2, Red) b.board[0][0].entity = p np, err := b.GetPiece(9, 9) if err == nil { @@ -68,7 +68,7 @@ func TestGetPiece(t *testing.T) { func TestPlace(t *testing.T) { b := NewBoard(4) - p := NewPiece(2, Red) + p := NewPieceFromInt(2, Red) res, err := b.Place(8, 9, p) if err == nil { t.Errorf("able to place in invalid location") @@ -94,7 +94,7 @@ func TestPlace(t *testing.T) { func TestRemove(t *testing.T) { b := NewBoard(4) - p := NewPiece(2, Red) + p := NewPieceFromInt(2, Red) res, err := b.Place(0, 0, p) if err != nil { diff --git a/colour_enumer.go b/colour_enumer.go new file mode 100644 index 0000000..6c581a8 --- /dev/null +++ b/colour_enumer.go @@ -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 +} diff --git a/command.go b/command.go index ed514e1..029d574 100644 --- a/command.go +++ b/command.go @@ -8,7 +8,7 @@ import ( "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" //RawCommand is a game command, converted from algebraic notation diff --git a/command_test.go b/command_test.go index 7bde21c..9d24583 100644 --- a/command_test.go +++ b/command_test.go @@ -17,6 +17,7 @@ func TestNewRawCommand(t *testing.T) { }{ {"A1xC3", true, 0, 1, 2, 3, "x"}, {"d7-d1", true, 3, 7, 3, 1, "-"}, + {"c0-c1", true, 2, 0, 2, 1, "-"}, {"AA-k3", false, 0, 0, 0, 0, ""}, {"a1/b4", false, 0, 0, 0, 0, ""}, } diff --git a/game.go b/game.go index 8a43230..d2c4593 100644 --- a/game.go +++ b/game.go @@ -19,6 +19,7 @@ const ( ) //Colour reperensents player colour +//go:generate enumer -type=Colour type Colour int //Colour consts @@ -112,7 +113,7 @@ func (g *Game) Mutate(cmd *ParsedCommand) (bool, error) { return false, errors.New("bad game state") } } - return true, nil + return res, nil } //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 { 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) { return false, errors.New("Invalid location") } 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) } @@ -208,7 +212,7 @@ func (g *Game) strike(x, y, s, t int) (bool, error) { //endPiece lost g.board.Remove(s, t) //scouts replace the piece that was destroyed - if startPiece.Rank == 1 { + if startPiece.Rank == Scout { g.board.Remove(x, y) g.board.Place(s, t, startPiece) } @@ -228,11 +232,15 @@ func (g *Game) combat(atk, def *Piece) (int, error) { } //handle special cases first //miner hitting bomb - if atk.Rank == 3 && def.Rank == 12 { + if atk.Rank == Miner && def.Rank == Bomb { return 1, nil } + //anyone else hitting bomb + if def.Rank == Bomb { + return -1, nil + } //spy hitting marshal - if atk.Rank == 0 && def.Rank == 10 { + if atk.Rank == Spy && def.Rank == Marshal { return 1, nil } //normal cases diff --git a/game_test.go b/game_test.go index 706d490..321c7e3 100644 --- a/game_test.go +++ b/game_test.go @@ -1,29 +1,63 @@ package main -import "testing" +import ( + "errors" + "fmt" + "testing" +) -func dummyMiniGame() *Game { +func dummyMiniGame() (*Game, error) { g := &Game{ board: NewBoard(4), state: gameSetup, } //Setup terrain - g.board.AddTerrain(1, 1, 1) - g.board.AddTerrain(2, 2, 1) - //Setup blue (5 pieces) - g.SetupPiece(0, 0, NewPiece(0, Blue)) - g.SetupPiece(0, 1, NewPiece(1, Blue)) - g.SetupPiece(0, 2, NewPiece(2, Blue)) - g.SetupPiece(0, 3, NewPiece(3, Blue)) - g.SetupPiece(1, 3, NewPiece(4, Blue)) - //Setup red (5 pieces) - g.SetupPiece(3, 0, NewPiece(0, Red)) - g.SetupPiece(3, 1, NewPiece(1, Red)) - g.SetupPiece(3, 2, NewPiece(2, Red)) - g.SetupPiece(3, 3, NewPiece(3, Red)) - g.SetupPiece(2, 1, NewPiece(4, Red)) + terrain := []struct { + x, y, t int + }{ + {1, 1, 1}, + {2, 2, 1}, + } + for _, tt := range terrain { + res, err := g.board.AddTerrain(tt.x, tt.y, tt.t) + if err != nil { + return nil, err + } + if !res { + return nil, errors.New("Error creating terrain") + } + } + 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) { @@ -38,8 +72,8 @@ func TestNewGame(t *testing.T) { func TestSetupPiece(t *testing.T) { g := NewGame() - p1 := NewPiece(0, Blue) - p2 := NewPiece(0, Red) + p1 := NewPieceFromInt(0, Blue) + p2 := NewPieceFromInt(0, Red) res, err := g.SetupPiece(0, 0, p1) if err == nil || res == true { t.Errorf("Expected to fail setup piece but didn't") @@ -57,7 +91,7 @@ func TestSetupPiece(t *testing.T) { if err == nil { 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 { t.Fatal(err) } @@ -75,3 +109,62 @@ func TestStart(t *testing.T) { 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) + } + }) + } +} diff --git a/main.go b/main.go index 0105d38..abbe74f 100644 --- a/main.go +++ b/main.go @@ -3,43 +3,16 @@ package main import "fmt" func main() { - red := NewDummyPlayer(Red) - blue := NewDummyPlayer(Blue) - game := NewGame() - game.state = gameSetup - addpiece(game, 0, Blue, 0, 0) - 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() - + //red := NewDummyPlayer(Red) + //blue := NewDummyPlayer(Blue) + g := NewGame() + g.state = gameSetup + printboardcolours(g) return } 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 { panic(err) } @@ -57,3 +30,18 @@ func addriver(game *Game, x int, y int) { 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("") + } +} diff --git a/piece.go b/piece.go index 60848d9..51d7b7b 100644 --- a/piece.go +++ b/piece.go @@ -13,6 +13,7 @@ const ( Captain General Marshal + Bomb ) //Piece :game piece @@ -22,8 +23,8 @@ type Piece struct { Hidden bool } -//NewPiece creates a new piece -func NewPiece(r int, o Colour) *Piece { +//NewPieceFromInt creates a new piece +func NewPieceFromInt(r int, o Colour) *Piece { return &Piece{ Rank: Rank(r), 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 func NewHiddenPiece(o Colour) *Piece { return &Piece{ diff --git a/rank_enumer.go b/rank_enumer.go index 4f46237..58a326b 100644 --- a/rank_enumer.go +++ b/rank_enumer.go @@ -7,9 +7,9 @@ import ( "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 { if i < 0 || i >= Rank(len(_RankIndex)-1) { @@ -18,7 +18,7 @@ func (i Rank) String() string { 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{ _RankName[0:4]: 0, @@ -28,6 +28,7 @@ var _RankNameToValueMap = map[string]Rank{ _RankName[17:24]: 4, _RankName[24:31]: 5, _RankName[31:38]: 6, + _RankName[38:42]: 7, } // RankString retrieves an enum value from the enum constants string name.