create oracle instead of card objects

This commit is contained in:
stryan 2021-07-23 18:33:17 -04:00
parent eb7b405641
commit 0723811faf
6 changed files with 178 additions and 364 deletions

View File

@ -1,19 +1,20 @@
package game package game
import ( import (
"encoding/json"
"fmt" "fmt"
"github.com/google/uuid"
) )
type Board struct { type Board struct {
Sentinal [4]Card `json:"sentinal"` Sentinal [4]*Card `json:"sentinal"`
Scourge [4]Card `json:"scourge"` Scourge [4]*Card `json:"scourge"`
} }
func NewBoard() *Board { func NewBoard() *Board {
return &Board{ return &Board{
Sentinal: [4]Card{CreateCard(-1), CreateCard(-1), CreateCard(-1), CreateCard(-1)}, Sentinal: [4]*Card{NewCard(-1, uuid.Nil), NewCard(-1, uuid.Nil), NewCard(-1, uuid.Nil), NewCard(-1, uuid.Nil)},
Scourge: [4]Card{CreateCard(-1), CreateCard(-1), CreateCard(-1), CreateCard(-1)}, Scourge: [4]*Card{NewCard(-1, uuid.Nil), NewCard(-1, uuid.Nil), NewCard(-1, uuid.Nil), NewCard(-1, uuid.Nil)},
} }
} }
@ -21,7 +22,7 @@ func (b *Board) String() string {
return fmt.Sprintf("---------\n|%v|%v|%v|%v|\n---------\n|%v|%v|%v|%v|\n---------\n", b.Sentinal[0], b.Sentinal[1], b.Sentinal[2], b.Sentinal[3], b.Scourge[0], b.Scourge[1], b.Scourge[2], b.Scourge[3]) return fmt.Sprintf("---------\n|%v|%v|%v|%v|\n---------\n|%v|%v|%v|%v|\n---------\n", b.Sentinal[0], b.Sentinal[1], b.Sentinal[2], b.Sentinal[3], b.Scourge[0], b.Scourge[1], b.Scourge[2], b.Scourge[3])
} }
func (b *Board) GetRow(id int) []Card { func (b *Board) GetRow(id int) []*Card {
if id == 1 { if id == 1 {
return b.Sentinal[:] return b.Sentinal[:]
} else { } else {
@ -29,6 +30,14 @@ func (b *Board) GetRow(id int) []Card {
} }
} }
func (b *Board) GetCard(id int, pos int) *Card {
if id == SentinalID {
return b.Sentinal[pos]
} else {
return b.Scourge[pos]
}
}
func (b *Board) Empty(id int) bool { func (b *Board) Empty(id int) bool {
res := true res := true
if id == SentinalID { if id == SentinalID {
@ -47,9 +56,9 @@ func (b *Board) Empty(id int) bool {
return res return res
} }
func (b *Board) Move(id, src, dest int) bool { func (b *Board) CanMove(id, src, dest int) bool {
var brd [4]Card var brd [4]*Card
if id == 1 { if id == SentinalID {
brd = b.Sentinal brd = b.Sentinal
} else { } else {
brd = b.Scourge brd = b.Scourge
@ -60,13 +69,31 @@ func (b *Board) Move(id, src, dest int) bool {
if !brd[dest].Empty() { if !brd[dest].Empty() {
return false return false
} }
if brd[src].Acted() { if brd[src].Sick {
return false
}
return true
}
func (b *Board) Move(id, src, dest int) bool {
var brd [4]*Card
if id == SentinalID {
brd = b.Sentinal
} else {
brd = b.Scourge
}
if brd[src].Empty() {
return false
}
if !brd[dest].Empty() {
return false
}
if brd[src].Sick {
return false return false
} }
brd[dest].Act()
brd[dest] = brd[src] brd[dest] = brd[src]
brd[src] = CreateCard(-1) brd[src] = NewCard(-1, uuid.Nil)
if id == 1 { if id == SentinalID {
b.Sentinal = brd b.Sentinal = brd
} else { } else {
b.Scourge = brd b.Scourge = brd
@ -75,8 +102,8 @@ func (b *Board) Move(id, src, dest int) bool {
} }
func (b *Board) CanPlay(id int, c *Card, dest int) bool { func (b *Board) CanPlay(id int, c *Card, dest int) bool {
var brd [4]Card var brd [4]*Card
if id == 1 { if id == SentinalID {
brd = b.Sentinal brd = b.Sentinal
} else { } else {
brd = b.Scourge brd = b.Scourge
@ -87,9 +114,9 @@ func (b *Board) CanPlay(id int, c *Card, dest int) bool {
return true return true
} }
func (b *Board) Play(id int, c *Card, dest int) bool { func (b *Board) Play(id int, c *Card, dest int, should bool) bool {
var brd [4]Card var brd [4]*Card
if id == 1 { if id == SentinalID {
brd = b.Sentinal brd = b.Sentinal
} else { } else {
brd = b.Scourge brd = b.Scourge
@ -97,8 +124,10 @@ func (b *Board) Play(id int, c *Card, dest int) bool {
if !brd[dest].Empty() { if !brd[dest].Empty() {
return false return false
} }
brd[dest] = *c if should {
if id == 1 { brd[dest] = c
}
if id == SentinalID {
b.Sentinal = brd b.Sentinal = brd
} else { } else {
b.Scourge = brd b.Scourge = brd
@ -106,23 +135,32 @@ func (b *Board) Play(id int, c *Card, dest int) bool {
return true return true
} }
func (b *Board) CanAttack(id, atk, def int) bool {
var aBrd [4]*Card
if id == SentinalID {
aBrd = b.Sentinal
} else {
aBrd = b.Scourge
}
if aBrd[atk].Empty() || aBrd[atk].Sick || atk != def {
return false
}
return true
}
func (b *Board) Attack(id int, atk, def int) int { func (b *Board) Attack(id int, atk, def int) int {
var aBrd [4]Card var aBrd [4]*Card
var dBrd [4]Card var dBrd [4]*Card
if id == 1 { if id == SentinalID {
aBrd = b.Sentinal aBrd = b.Sentinal
dBrd = b.Scourge dBrd = b.Scourge
} else { } else {
aBrd = b.Scourge aBrd = b.Scourge
dBrd = b.Sentinal dBrd = b.Sentinal
} }
if aBrd[atk].Empty() || !aBrd[atk].CanAttack(atk, def) {
return -1
}
aBrd[atk].Act()
if dBrd[def].Empty() { if dBrd[def].Empty() {
//health damage //health damage
if id == 1 { if id == SentinalID {
b.Sentinal = aBrd b.Sentinal = aBrd
b.Scourge = dBrd b.Scourge = dBrd
} else { } else {
@ -132,29 +170,11 @@ func (b *Board) Attack(id int, atk, def int) int {
return 1 return 1
} }
//Do actual battle math //Do actual battle math
attacker := aBrd[atk].Value() attacker := aBrd[atk].Power
defender := dBrd[def].Value() defender := dBrd[def].Power
dBrd[def].Acted()
//check atk buffs
for i, v := range aBrd {
if v.Value() == Two {
attacker = attacker + 1
}
if v.Value() == Three && (i == atk-1 || i == atk+1) {
attacker = attacker + 1
}
}
for i, v := range dBrd {
if v.Value() == Two {
defender = defender + 1
}
if v.Value() == Three && (i == def-1 || i == def+1) {
defender = defender + 1
}
}
if attacker > defender { if attacker > defender {
dBrd[def] = CreateCard(-1) dBrd[def] = NewCard(-1, uuid.Nil)
if id == 1 { if id == SentinalID {
b.Sentinal = aBrd b.Sentinal = aBrd
b.Scourge = dBrd b.Scourge = dBrd
} else { } else {
@ -164,8 +184,8 @@ func (b *Board) Attack(id int, atk, def int) int {
return 0 return 0
} }
if attacker == defender { if attacker == defender {
aBrd[atk] = CreateCard(-1) aBrd[atk] = NewCard(-1, uuid.Nil)
dBrd[def] = CreateCard(-1) dBrd[def] = NewCard(-1, uuid.Nil)
if id == 1 { if id == 1 {
b.Sentinal = aBrd b.Sentinal = aBrd
b.Scourge = dBrd b.Scourge = dBrd
@ -178,23 +198,3 @@ func (b *Board) Attack(id int, atk, def int) int {
return -1 return -1
} }
func (b *Board) MarshalJSON() ([]byte, error) {
res := [][]*PortableCard{{b.Sentinal[0].Port(), b.Sentinal[1].Port(), b.Sentinal[2].Port(), b.Sentinal[3].Port()}, {b.Scourge[0].Port(), b.Scourge[1].Port(), b.Scourge[2].Port(), b.Scourge[3].Port()}}
return json.Marshal(res)
}
func (b *Board) UnmarshalJSON(data []byte) (err error) {
var ported [][]PortableCard
err = json.Unmarshal(data, &ported)
if err != nil {
return err
}
for i := 0; i < 4; i++ {
b.Sentinal[i] = NewCard(ported[0][i].Type, ported[0][i].ID)
}
for i := 0; i < 4; i++ {
b.Scourge[i] = NewCard(ported[1][i].Type, ported[0][i].ID)
}
return
}

View File

@ -6,79 +6,18 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
) )
type Card interface { type Card struct {
Cast(g *Game) *Game Type CardType `json:"type"`
Upkeep(g *Game) *Game Power int `json:"power"`
Endstep(g *Game) *Game
Enters(g *Game) *Game
Value() CardValue
Act()
Acted() bool
Empty() bool
String() string
CanAttack(int, int) bool
Port() *PortableCard
}
type GenericCard struct {
Val CardValue `json:"value"`
Id uuid.UUID `json:"id"` Id uuid.UUID `json:"id"`
Sick bool `json:"sick"` Sick bool `json:"sick"`
Counters int `json:"counters"`
} }
func (g *GenericCard) Cast(game *Game) *Game { type CardType int
return nil
}
func (g *GenericCard) Enters(game *Game) *Game {
return nil
}
func (g *GenericCard) Upkeep(game *Game) *Game {
g.Sick = false
return nil
}
func (g *GenericCard) Endstep(game *Game) *Game {
return nil
}
func (g *GenericCard) Value() CardValue {
return g.Val
}
func (g *GenericCard) Acted() bool {
return g.Sick
}
func (g *GenericCard) Act() {
g.Sick = true
}
func (g *GenericCard) Empty() bool {
return false
}
func (g *GenericCard) String() string {
return fmt.Sprintf("%v", g.Val)
}
func (g *GenericCard) Port() *PortableCard {
return &PortableCard{
Type: int(g.Val),
ID: g.Id,
}
}
func (g *GenericCard) CanAttack(x, y int) bool {
if x == y && !g.Sick {
return true
}
return false
}
type CardValue int
const ( const (
Valk CardValue = iota Valk CardType = iota
Ace Ace
Two Two
Three Three
@ -89,130 +28,33 @@ const (
Eight Eight
) )
const ( const (
EmptyValue CardValue = -1 EmptyValue CardType = -1
) )
func (c CardValue) String() string { func (c CardType) String() string {
if c == -1 { if c == -1 {
return " " return " "
} }
return []string{"V", "A", "2", "3", "4", "5", "6", "7", "8"}[c] return []string{"V", "A", "2", "3", "4", "5", "6", "7", "8"}[c]
} }
func CreateCard(v int) Card { func NewCard(v int, id uuid.UUID) *Card {
return NewCard(v, uuid.New()) if id == uuid.Nil {
} id = uuid.New()
func NewCard(v int, id uuid.UUID) Card {
switch v {
case -1:
return &EmptyCard{
&GenericCard{
Val: EmptyValue,
Id: id,
Sick: true,
},
} }
case 1: return &Card{
return &AceCard{ Type: CardType(v),
&GenericCard{ Power: OraclePower(CardType(v), nil),
Val: Ace,
Id: id, Id: id,
Sick: false, Sick: false,
}, Counters: 0,
}
case 4:
return &FourCard{
&GenericCard{
Val: Four,
Id: id,
Sick: true,
},
}
case 8:
return &EightCard{
&GenericCard{
Val: Eight,
Id: id,
Sick: true,
},
0,
}
case 0:
return &Valkyrie{
&GenericCard{
Val: Valk,
Id: id,
Sick: false,
},
}
default:
return &GenericCard{
Val: CardValue(v),
Id: id,
Sick: true,
}
} }
} }
type EmptyCard struct { func (c *Card) Empty() bool {
*GenericCard return c.Type == EmptyValue
} }
func (e *EmptyCard) Empty() bool { func (c *Card) String() string {
return true return fmt.Sprintf("|%v|", c.Type)
}
type AceCard struct {
*GenericCard
}
type FourCard struct {
*GenericCard
}
func (f *FourCard) Enters(g *Game) *Game {
g.CanDraw = true
return g
}
type EightCard struct {
*GenericCard
Counters int `json:"counters"`
}
func (e *EightCard) CanAttack(x, y int) bool {
return false
}
func (e *EightCard) Upkeep(g *Game) *Game {
if e.Counters > 2 {
e = nil
}
return g
}
func (e *EightCard) Endstep(g *Game) *Game {
e.Counters = e.Counters + 1
return g
}
type Valkyrie struct {
*GenericCard
}
func (v *Valkyrie) Cast(g *Game) *Game {
g.GameBoard.Sentinal = [4]Card{CreateCard(-1), CreateCard(-1), CreateCard(-1), CreateCard(-1)}
g.GameBoard.Scourge = [4]Card{CreateCard(-1), CreateCard(-1), CreateCard(-1), CreateCard(-1)}
return g
}
func (v *Valkyrie) Enters(g *Game) *Game {
v = nil
return g
}
type PortableCard struct {
Type int `json:"type"`
ID uuid.UUID `json:"ID"`
} }

View File

@ -1,20 +1,21 @@
package game package game
import ( import (
"encoding/json"
"math/rand" "math/rand"
"time" "time"
"github.com/google/uuid"
) )
type Deck struct { type Deck struct {
Cards []Card `json:"cards"` Cards []*Card `json:"cards"`
} }
func NewDeck() *Deck { func NewDeck() *Deck {
cards := []Card{CreateCard(0)} cards := []*Card{NewCard(0, uuid.Nil)}
for i := 0; i < 3; i++ { for i := 0; i < 3; i++ {
for j := 1; j < 9; j++ { for j := 1; j < 9; j++ {
cards = append(cards, Card(CreateCard(j))) cards = append(cards, NewCard(j, uuid.Nil))
} }
} }
return &Deck{ return &Deck{
@ -22,7 +23,7 @@ func NewDeck() *Deck {
} }
} }
func DeckFromCards(c []Card) *Deck { func DeckFromCards(c []*Card) *Deck {
return &Deck{ return &Deck{
Cards: c, Cards: c,
} }
@ -38,11 +39,11 @@ func (d *Deck) Shuffle() {
d.Cards = cards d.Cards = cards
} }
func (d *Deck) Scry(s int) []Card { func (d *Deck) Scry(s int) []*Card {
seen := []Card{} seen := []*Card{}
if len(d.Cards) < s { if len(d.Cards) < s {
seen = d.Cards seen = d.Cards
d.Cards = []Card{} d.Cards = []*Card{}
return seen return seen
} }
seen = d.Cards[(len(d.Cards) - s):len(d.Cards)] seen = d.Cards[(len(d.Cards) - s):len(d.Cards)]
@ -50,32 +51,10 @@ func (d *Deck) Scry(s int) []Card {
return seen return seen
} }
func (d *Deck) Bottom(result []Card) { func (d *Deck) Bottom(result []*Card) {
d.Cards = append(result, d.Cards...) //Should shuffle result first? d.Cards = append(result, d.Cards...) //Should shuffle result first?
} }
func (d *Deck) Size() int { func (d *Deck) Size() int {
return len(d.Cards) return len(d.Cards)
} }
func (d *Deck) MarshalJSON() ([]byte, error) {
var ported []*PortableCard
for i, _ := range d.Cards {
ported = append(ported, d.Cards[i].Port())
}
return json.Marshal(ported)
}
func (d *Deck) UnmarshalJSON(data []byte) (err error) {
var ported []PortableCard
err = json.Unmarshal(data, &ported)
if err != nil {
return err
}
cards := []Card{}
for _, v := range ported {
cards = append(cards, NewCard(v.Type, v.ID))
}
d.Cards = cards
return
}

View File

@ -2,6 +2,7 @@ package game
import ( import (
"fmt" "fmt"
"log"
"strconv" "strconv"
"strings" "strings"
) )
@ -24,7 +25,7 @@ const (
) )
func (g GameStatus) String() string { func (g GameStatus) String() string {
return []string{"Lobby", "Ready", "Playing", "Stopped"}[g] return []string{"Lobby", "Ready", "Playing", "Stopped", "SentinalWin", "ScougeWin", "Draw"}[g]
} }
type Game struct { type Game struct {
@ -52,7 +53,7 @@ func NewGame() *Game {
SentinalDeck: deckA, SentinalDeck: deckA,
ScourgeDeck: deckB, ScourgeDeck: deckB,
CurrentTurn: 0, //start with no turn CurrentTurn: 0, //start with no turn
CardBuffer: DeckFromCards([]Card{}), CardBuffer: DeckFromCards([]*Card{}),
CanDraw: false, CanDraw: false,
HasDrawn: false, HasDrawn: false,
Status: StatusLobby, Status: StatusLobby,
@ -162,11 +163,11 @@ func (g *Game) PlayerStateAct(id int, cmd string) *GameView {
} }
if id == SentinalID { if id == SentinalID {
for _, v := range g.GameBoard.Sentinal { for _, v := range g.GameBoard.Sentinal {
v.Upkeep(g) OracleUpkeep(v, g)
} }
} else { } else {
for _, v := range g.GameBoard.Scourge { for _, v := range g.GameBoard.Scourge {
v.Upkeep(g) OracleUpkeep(v, g)
} }
} }
case "e": case "e":
@ -174,14 +175,14 @@ func (g *Game) PlayerStateAct(id int, cmd string) *GameView {
if id != g.CurrentTurn { if id != g.CurrentTurn {
return nil return nil
} }
g.CardBuffer = DeckFromCards([]Card{}) g.CardBuffer = DeckFromCards([]*Card{})
if id == SentinalID { if id == SentinalID {
for _, v := range g.GameBoard.Sentinal { for _, v := range g.GameBoard.Sentinal {
v.Endstep(g) OracleEndstep(v, g)
} }
} else { } else {
for _, v := range g.GameBoard.Scourge { for _, v := range g.GameBoard.Scourge {
v.Endstep(g) OracleEndstep(v, g)
} }
} }
if g.CurrentTurn == SentinalID { if g.CurrentTurn == SentinalID {
@ -256,11 +257,12 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck {
} }
x_i, _ := strconv.Atoi(cmd_s[1]) x_i, _ := strconv.Atoi(cmd_s[1])
y_i, _ := strconv.Atoi(cmd_s[2]) y_i, _ := strconv.Atoi(cmd_s[2])
res := g.GameBoard.Move(g.CurrentTurn, x_i, y_i) if g.GameBoard.CanMove(g.CurrentTurn, x_i, y_i) {
if res { OracleMove(g.GameBoard.GetCard(g.CurrentTurn, x_i), g)
g.GameBoard.Move(g.CurrentTurn, x_i, y_i)
return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn))
} else { } else {
return DeckFromCards([]Card{}) return DeckFromCards([]*Card{})
} }
case "a": case "a":
//attack //attack
@ -272,15 +274,18 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck {
} }
x_i, _ := strconv.Atoi(cmd_s[1]) x_i, _ := strconv.Atoi(cmd_s[1])
y_i, _ := strconv.Atoi(cmd_s[2]) y_i, _ := strconv.Atoi(cmd_s[2])
if g.GameBoard.CanAttack(g.CurrentTurn, x_i, y_i) {
OracleAttack(g.GameBoard.GetCard(g.CurrentTurn, x_i), g)
res := g.GameBoard.Attack(g.CurrentTurn, x_i, y_i) res := g.GameBoard.Attack(g.CurrentTurn, x_i, y_i)
if res == 1 { if res == 1 {
opp.Life = opp.Life - 1 opp.Life = opp.Life - 1
return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn))
} else if res == 0 {
return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn))
} else { } else {
fmt.Println("can't attack") return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn))
return DeckFromCards([]Card{}) }
} else {
log.Println("can't attack")
return DeckFromCards([]*Card{})
} }
case "p": case "p":
//play: return player boad or [] if invalid //play: return player boad or [] if invalid
@ -294,17 +299,16 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck {
x_i, _ := strconv.Atoi(cmd_s[1]) x_i, _ := strconv.Atoi(cmd_s[1])
y_i, _ := strconv.Atoi(cmd_s[2]) y_i, _ := strconv.Atoi(cmd_s[2])
card := curr.Hand[x_i] card := curr.Hand[x_i]
if g.GameBoard.CanPlay(g.CurrentTurn, &card, y_i) { shouldPlace := true
curr.Hand[x_i].Cast(g) if g.GameBoard.CanPlay(g.CurrentTurn, card, y_i) {
} shouldPlace = OracleCast(curr.Hand[x_i], g)
res := g.GameBoard.Play(g.CurrentTurn, &card, y_i) _ = g.GameBoard.Play(g.CurrentTurn, card, y_i, shouldPlace)
if res { OracleEnters(curr.Hand[x_i], g)
curr.Hand[x_i].Enters(g)
curr.Hand = append(curr.Hand[:x_i], curr.Hand[x_i+1:]...) curr.Hand = append(curr.Hand[:x_i], curr.Hand[x_i+1:]...)
return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn))
} else { } else {
fmt.Println("couldn't play") fmt.Println("couldn't play")
return DeckFromCards([]Card{}) return DeckFromCards([]*Card{})
} }
default: default:
fmt.Println("Invalid act command") fmt.Println("Invalid act command")

38
internal/game/oracle.go Normal file
View File

@ -0,0 +1,38 @@
package game
func OracleUpkeep(c *Card, g *Game) {
switch c.Type {
default:
c.Sick = false
}
return
}
func OracleCast(c *Card, g *Game) bool {
return true
}
func OracleEnters(c *Card, g *Game) {
c.Sick = true
return
}
func OracleLeaves(c *Card, g *Game) {
return
}
func OracleEndstep(c *Card, g *Game) {
return
}
func OraclePower(c CardType, g *Game) int {
return int(c)
}
func OracleMove(c *Card, g *Game) {
c.Sick = true
}
func OracleAttack(c *Card, g *Game) {
c.Sick = true
}

View File

@ -1,17 +1,9 @@
package game package game
import (
"encoding/json"
"fmt"
"log"
"github.com/google/uuid"
)
type Player struct { type Player struct {
Name string `json:"name"` Name string `json:"name"`
Id int `json:"id"` Id int `json:"id"`
Hand []Card `json:"hand"` Hand []*Card `json:"hand"`
Life int `json:"life"` Life int `json:"life"`
} }
@ -19,48 +11,7 @@ func NewPlayer(name string, id int) *Player {
return &Player{ return &Player{
Name: name, Name: name,
Id: id, Id: id,
Hand: []Card{}, Hand: []*Card{},
Life: 3, Life: 3,
} }
} }
func (p *Player) MarshalJSON() ([]byte, error) {
var ported_hand []*PortableCard
for i, _ := range p.Hand {
ported_hand = append(ported_hand, p.Hand[i].Port())
}
res := []interface{}{p.Name, p.Id, ported_hand, p.Life}
return json.Marshal(res)
}
func (p *Player) UnmarshalJSON(data []byte) (err error) {
ported := []interface{}{}
err = json.Unmarshal(data, &ported)
if err != nil {
return err
}
fmt.Println(ported)
p.Name = ported[0].(string)
p.Id = int(ported[1].(float64))
var tmp []interface{}
if ported[2] != nil {
tmp = ported[2].([]interface{})
} else {
tmp = []interface{}{}
}
p.Life = int(ported[3].(float64))
hand := []Card{}
for _, v := range tmp {
m := v.(map[string]interface{})
t := int(m["type"].(float64))
i := m["ID"].(string)
uid, err := uuid.Parse(i)
if err != nil {
log.Println("invalid card parse")
} else {
hand = append(hand, NewCard(t, uid))
}
}
p.Hand = hand
return
}