Create some subroutines and test

This commit is contained in:
Bel LaPointe
2021-03-14 23:29:50 -05:00
parent 60adca804b
commit d79721b760
8 changed files with 578 additions and 0 deletions

View 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)
}

View 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))
}

View 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)
}
})
}
}

View 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)
}

View File

@@ -0,0 +1,5 @@
package operation
import "local/sandbox/cards/src/entity"
type Int func(*entity.Game, interface{}) int

View 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
}

View 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
}

View 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)
}
})
}
}