Create some subroutines and test
This commit is contained in:
36
src/game/rule/operation/bool.go
Normal file
36
src/game/rule/operation/bool.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"local/sandbox/cards/src/entity"
|
||||
)
|
||||
|
||||
type Bool func(*entity.Game, interface{}) bool
|
||||
|
||||
var boolStringified = map[string]Bool{
|
||||
"charge": charge,
|
||||
"deal": deal,
|
||||
"bet": bet,
|
||||
"trade": trade,
|
||||
"end": end,
|
||||
}
|
||||
|
||||
func (foo *Bool) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return foo.FromString(s)
|
||||
}
|
||||
|
||||
func (foo *Bool) FromString(s string) error {
|
||||
for k, v := range boolStringified {
|
||||
if k == s {
|
||||
*foo = v
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("unknown bool method " + s)
|
||||
}
|
||||
20
src/game/rule/operation/compare.go
Normal file
20
src/game/rule/operation/compare.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func compareNumber(a int, b interface{}) int {
|
||||
v := convertNumber(b)
|
||||
if a == v {
|
||||
return 0
|
||||
}
|
||||
if a > v {
|
||||
return 1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func compareString(a string, b interface{}) int {
|
||||
return strings.Compare(a, convertString(b))
|
||||
}
|
||||
37
src/game/rule/operation/compare_test.go
Normal file
37
src/game/rule/operation/compare_test.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package operation
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCompareNumber(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
a int
|
||||
b interface{}
|
||||
want int
|
||||
}{
|
||||
"int int equal": {
|
||||
a: 1,
|
||||
b: 1,
|
||||
want: 0,
|
||||
},
|
||||
"int int gt": {
|
||||
a: 2,
|
||||
b: 1,
|
||||
want: 1,
|
||||
},
|
||||
"int int lt": {
|
||||
a: 0,
|
||||
b: 1,
|
||||
want: -1,
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := compareNumber(c.a, c.b)
|
||||
if got != c.want {
|
||||
t.Fatal(got, c.a, c.b)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
22
src/game/rule/operation/convert.go
Normal file
22
src/game/rule/operation/convert.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func convertNumber(v interface{}) int {
|
||||
s := fmt.Sprint(v)
|
||||
v2, _ := strconv.ParseFloat(s, 64)
|
||||
return int(v2)
|
||||
}
|
||||
|
||||
func convertString(v interface{}) string {
|
||||
switch v.(type) {
|
||||
case string:
|
||||
return v.(string)
|
||||
case []byte:
|
||||
return string(v.([]byte))
|
||||
}
|
||||
return fmt.Sprint(v)
|
||||
}
|
||||
5
src/game/rule/operation/int.go
Normal file
5
src/game/rule/operation/int.go
Normal file
@@ -0,0 +1,5 @@
|
||||
package operation
|
||||
|
||||
import "local/sandbox/cards/src/entity"
|
||||
|
||||
type Int func(*entity.Game, interface{}) int
|
||||
13
src/game/rule/operation/operation_test.go
Normal file
13
src/game/rule/operation/operation_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"local/sandbox/cards/src/entity"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOperationInterface(t *testing.T) {
|
||||
foo := func(*entity.Game, interface{}) int { return 0 }
|
||||
var _ Int = foo
|
||||
bar := func(*entity.Game, interface{}) bool { return false }
|
||||
var _ Bool = bar
|
||||
}
|
||||
80
src/game/rule/operation/phase.go
Normal file
80
src/game/rule/operation/phase.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"local/sandbox/cards/src/entity"
|
||||
)
|
||||
|
||||
func charge(game *entity.Game, charge interface{}) bool {
|
||||
if game == nil {
|
||||
return false
|
||||
}
|
||||
v := entity.Currency(convertNumber(charge))
|
||||
game.ChargeActivePlayers(v)
|
||||
game.NextPhase()
|
||||
return true
|
||||
}
|
||||
|
||||
func deal(game *entity.Game, deal interface{}) bool {
|
||||
if game == nil {
|
||||
return false
|
||||
}
|
||||
n := convertNumber(deal)
|
||||
game.Deal(n)
|
||||
game.NextPhase()
|
||||
return true
|
||||
}
|
||||
|
||||
func bet(game *entity.Game, _ interface{}) bool {
|
||||
if game == nil {
|
||||
return false
|
||||
}
|
||||
if len(game.ActivePlayers()) == 0 {
|
||||
game.NextPhase()
|
||||
game.NextTurn()
|
||||
return true
|
||||
}
|
||||
|
||||
player := &game.Players[game.Current.Turn]
|
||||
raised := player.Active && player.Bet > game.Current.Bet
|
||||
if raised {
|
||||
game.Current.Bet = player.Bet
|
||||
for i := range game.Players {
|
||||
game.Players[i].Checked = false
|
||||
}
|
||||
}
|
||||
player.Checked = player.Active && (player.Checked || player.Balance == 0 || player.Bet == game.Current.Bet)
|
||||
|
||||
if game.IsAllActivePlayersChecked() && game.IsPotRight() {
|
||||
game.NextPhase()
|
||||
game.NextTurn()
|
||||
return true
|
||||
}
|
||||
|
||||
if player.Checked {
|
||||
game.NextTurn()
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func trade(game *entity.Game, max interface{}) bool {
|
||||
if game == nil {
|
||||
return false
|
||||
}
|
||||
panic("not impl")
|
||||
}
|
||||
|
||||
func end(game *entity.Game, _ interface{}) bool {
|
||||
if game == nil {
|
||||
return false
|
||||
}
|
||||
panic("not impl")
|
||||
}
|
||||
|
||||
func playerCount(game *entity.Game, v interface{}) bool {
|
||||
if game == nil {
|
||||
return false
|
||||
}
|
||||
v2 := convertNumber(charge)
|
||||
return len(game.ActivePlayers()) == v2
|
||||
}
|
||||
365
src/game/rule/operation/phase_test.go
Normal file
365
src/game/rule/operation/phase_test.go
Normal file
@@ -0,0 +1,365 @@
|
||||
package operation
|
||||
|
||||
import (
|
||||
"local/sandbox/cards/src/entity"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBoolInterface(t *testing.T) {
|
||||
var _ Bool = charge
|
||||
var _ Bool = deal
|
||||
var _ Bool = bet
|
||||
var _ Bool = trade
|
||||
var _ Bool = end
|
||||
}
|
||||
|
||||
func TestCharge(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
game *entity.Game
|
||||
charge interface{}
|
||||
check func(bool, *entity.Game) bool
|
||||
}{
|
||||
"game is nil": {
|
||||
check: func(a bool, _ *entity.Game) bool {
|
||||
return a == false
|
||||
},
|
||||
},
|
||||
"players is nil": {
|
||||
game: &entity.Game{},
|
||||
check: func(a bool, _ *entity.Game) bool {
|
||||
return a == true
|
||||
},
|
||||
},
|
||||
"cannot afford, active": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Balance: 4, Active: true},
|
||||
},
|
||||
},
|
||||
charge: 5,
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
player := game.Players[0]
|
||||
return a == true && player.Balance == 4 && player.Pot == 0 && game.Pot() == 0
|
||||
},
|
||||
},
|
||||
"cannot afford, not active": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Balance: 4},
|
||||
},
|
||||
},
|
||||
charge: 5,
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
player := game.Players[0]
|
||||
return a == true && player.Balance == 4 && player.Pot == 0 && game.Pot() == 0
|
||||
},
|
||||
},
|
||||
"can afford, active": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Balance: 6, Active: true},
|
||||
},
|
||||
},
|
||||
charge: 5,
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
player := game.Players[0]
|
||||
return a == true && player.Balance == 1 && player.Pot == 5 && game.Pot() == 5
|
||||
},
|
||||
},
|
||||
"can afford, not active": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Balance: 6},
|
||||
},
|
||||
},
|
||||
charge: 5,
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
player := game.Players[0]
|
||||
return a == true && player.Balance == 6 && player.Pot == 0 && game.Pot() == 0
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
got := charge(c.game, c.charge)
|
||||
if approved := c.check(got, c.game); !approved {
|
||||
t.Fatalf("not approved: got=%v, game=%+v", got, c.game)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeal(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
game *entity.Game
|
||||
deal interface{}
|
||||
check func(bool, *entity.Game) bool
|
||||
}{
|
||||
"game is nil": {
|
||||
check: func(a bool, _ *entity.Game) bool {
|
||||
return a == false
|
||||
},
|
||||
},
|
||||
"players is nil": {
|
||||
game: &entity.Game{},
|
||||
check: func(a bool, _ *entity.Game) bool {
|
||||
return a == true
|
||||
},
|
||||
},
|
||||
"no active, no hand": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{},
|
||||
},
|
||||
},
|
||||
deal: 5,
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
player := game.Players[0]
|
||||
return a == true && player.Hand.Len() == 0
|
||||
},
|
||||
},
|
||||
"active, no hand": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true},
|
||||
},
|
||||
},
|
||||
deal: 5,
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
player := game.Players[0]
|
||||
return a == true && player.Hand.Len() == 5
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if c.game != nil {
|
||||
c.game.Deck = newDeck()
|
||||
}
|
||||
got := deal(c.game, c.deal)
|
||||
if approved := c.check(got, c.game); !approved {
|
||||
t.Fatalf("not approved: got=%v, game=%+v", got, c.game)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func newDeck() entity.Deck {
|
||||
deck := make([]entity.Card, 0, 26)
|
||||
discard := make([]entity.Card, 0, 26)
|
||||
for i := 0; i < 52; i++ {
|
||||
card := entity.Card{Suit: i % 4, Value: i % 13}
|
||||
if i%2 == 1 {
|
||||
deck = append(deck, card)
|
||||
} else {
|
||||
discard = append(discard, card)
|
||||
}
|
||||
}
|
||||
return entity.Deck{
|
||||
Deck: deck,
|
||||
Discard: discard,
|
||||
}
|
||||
}
|
||||
|
||||
func TestBet(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
game *entity.Game
|
||||
check func(bool, *entity.Game) bool
|
||||
}{
|
||||
"game is nil": {
|
||||
check: func(a bool, _ *entity.Game) bool {
|
||||
return a == false
|
||||
},
|
||||
},
|
||||
"players is nil": {
|
||||
game: &entity.Game{},
|
||||
check: func(a bool, _ *entity.Game) bool {
|
||||
return a == true
|
||||
},
|
||||
},
|
||||
"no active": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{},
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == true && !game.Players[0].Checked
|
||||
},
|
||||
},
|
||||
"active, checked": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true},
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == true && !game.Players[0].Checked
|
||||
},
|
||||
},
|
||||
"active, checked, pots wrong, has balance": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true, Bet: 2, Balance: 3},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 3,
|
||||
},
|
||||
},
|
||||
check: func(a bool, _ *entity.Game) bool {
|
||||
return a == false
|
||||
},
|
||||
},
|
||||
"active, checked, pots wrong, no balance": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true, Bet: 2, Balance: 0},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 3,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == true && !game.Players[0].Checked
|
||||
},
|
||||
},
|
||||
"first turn in phase: checks": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true, Bet: 0, Balance: 5},
|
||||
entity.Player{Active: true, Checked: false, Bet: 0, Balance: 5},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 0,
|
||||
Turn: 0,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == false && game.Players[0].Checked && game.Current.Turn == 1
|
||||
},
|
||||
},
|
||||
"only turn in phase: checks": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true, Bet: 0, Balance: 5},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 0,
|
||||
Turn: 0,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == true && !game.Players[0].Checked && game.Current.Turn == 0
|
||||
},
|
||||
},
|
||||
"only turn in phase: raises": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: false, Bet: 5, Balance: 5},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 0,
|
||||
Turn: 0,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == true && !game.Players[0].Checked && game.Current.Turn == 0 && game.Players[0].Bet == 0 && game.Players[0].Pot == 5 && game.Current.Bet == 0
|
||||
},
|
||||
},
|
||||
"first turn in phase: raises": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: false, Bet: 5, Balance: 5},
|
||||
entity.Player{Active: true, Checked: false, Bet: 0, Balance: 5},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 0,
|
||||
Turn: 0,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == false && game.Players[0].Checked && game.Current.Turn == 1 && game.Players[0].Bet == 5 && game.Players[0].Pot == 0 && game.Current.Bet == 5
|
||||
},
|
||||
},
|
||||
"last: check": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true, Bet: 5, Balance: 5},
|
||||
entity.Player{Active: true, Checked: true, Bet: 5, Balance: 5},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 5,
|
||||
Turn: 1,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == true && !game.Players[0].Checked && game.Current.Turn == 0 && game.Players[0].Bet == 0 && game.Players[0].Pot == 5 && game.Current.Bet == 0
|
||||
},
|
||||
},
|
||||
"mid: raise": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: false, Bet: 5, Balance: 15},
|
||||
entity.Player{Active: true, Checked: false, Bet: 7, Balance: 15},
|
||||
entity.Player{Active: true, Checked: false, Bet: 0, Balance: 15},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 5,
|
||||
Turn: 1,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == false && !game.Players[0].Checked && game.Current.Turn == 2 && game.Players[0].Bet == 5 && game.Players[0].Pot == 0 && game.Current.Bet == 7 && game.Players[1].Checked && !game.Players[2].Checked && game.Players[1].Bet == 7 && game.Players[1].Pot == 0
|
||||
},
|
||||
},
|
||||
"mid: check": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true, Bet: 0, Balance: 15},
|
||||
entity.Player{Active: true, Checked: false, Bet: 0, Balance: 15},
|
||||
entity.Player{Active: true, Checked: false, Bet: 0, Balance: 15},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 0,
|
||||
Turn: 1,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == false && game.Players[0].Checked && game.Current.Turn == 2 && game.Players[0].Bet == 0 && game.Players[0].Pot == 0 && game.Current.Bet == 0 && game.Players[1].Checked && !game.Players[2].Checked && game.Players[1].Bet == 0 && game.Players[1].Pot == 0
|
||||
},
|
||||
},
|
||||
"last: raise": {
|
||||
game: &entity.Game{
|
||||
Players: []entity.Player{
|
||||
entity.Player{Active: true, Checked: true, Bet: 0, Balance: 15},
|
||||
entity.Player{Active: true, Checked: true, Bet: 0, Balance: 15},
|
||||
entity.Player{Active: true, Checked: false, Bet: 10, Balance: 5},
|
||||
},
|
||||
Current: entity.Current{
|
||||
Bet: 0,
|
||||
Turn: 2,
|
||||
},
|
||||
},
|
||||
check: func(a bool, game *entity.Game) bool {
|
||||
return a == false && !game.Players[0].Checked && game.Current.Turn == 0 && game.Players[0].Bet == 0 && game.Players[0].Pot == 0 && game.Current.Bet == 10 && !game.Players[1].Checked && game.Players[2].Checked && game.Players[1].Bet == 0 && game.Players[1].Pot == 0
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for name, d := range cases {
|
||||
c := d
|
||||
t.Run(name, func(t *testing.T) {
|
||||
if c.game != nil {
|
||||
c.game.Deck = newDeck()
|
||||
}
|
||||
got := bet(c.game, nil)
|
||||
if approved := c.check(got, c.game); !approved {
|
||||
t.Fatalf("not approved: got=%v, game=%+v", got, c.game)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user