diff --git a/internal/game/board.go b/internal/game/board.go index d2a88bf..bd1ff5d 100644 --- a/internal/game/board.go +++ b/internal/game/board.go @@ -1,19 +1,20 @@ package game import ( - "encoding/json" "fmt" + + "github.com/google/uuid" ) type Board struct { - Sentinal [4]Card `json:"sentinal"` - Scourge [4]Card `json:"scourge"` + Sentinal [4]*Card `json:"sentinal"` + Scourge [4]*Card `json:"scourge"` } func NewBoard() *Board { return &Board{ - Sentinal: [4]Card{CreateCard(-1), CreateCard(-1), CreateCard(-1), CreateCard(-1)}, - Scourge: [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{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]) } -func (b *Board) GetRow(id int) []Card { +func (b *Board) GetRow(id int) []*Card { if id == 1 { return b.Sentinal[:] } 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 { res := true if id == SentinalID { @@ -47,9 +56,9 @@ func (b *Board) Empty(id int) bool { return res } -func (b *Board) Move(id, src, dest int) bool { - var brd [4]Card - if id == 1 { +func (b *Board) CanMove(id, src, dest int) bool { + var brd [4]*Card + if id == SentinalID { brd = b.Sentinal } else { brd = b.Scourge @@ -60,13 +69,31 @@ func (b *Board) Move(id, src, dest int) bool { if !brd[dest].Empty() { 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 } - brd[dest].Act() brd[dest] = brd[src] - brd[src] = CreateCard(-1) - if id == 1 { + brd[src] = NewCard(-1, uuid.Nil) + if id == SentinalID { b.Sentinal = brd } else { 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 { - var brd [4]Card - if id == 1 { + var brd [4]*Card + if id == SentinalID { brd = b.Sentinal } else { brd = b.Scourge @@ -87,9 +114,9 @@ func (b *Board) CanPlay(id int, c *Card, dest int) bool { return true } -func (b *Board) Play(id int, c *Card, dest int) bool { - var brd [4]Card - if id == 1 { +func (b *Board) Play(id int, c *Card, dest int, should bool) bool { + var brd [4]*Card + if id == SentinalID { brd = b.Sentinal } else { brd = b.Scourge @@ -97,8 +124,10 @@ func (b *Board) Play(id int, c *Card, dest int) bool { if !brd[dest].Empty() { return false } - brd[dest] = *c - if id == 1 { + if should { + brd[dest] = c + } + if id == SentinalID { b.Sentinal = brd } else { b.Scourge = brd @@ -106,23 +135,32 @@ func (b *Board) Play(id int, c *Card, dest int) bool { 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 { - var aBrd [4]Card - var dBrd [4]Card - if id == 1 { + var aBrd [4]*Card + var dBrd [4]*Card + if id == SentinalID { aBrd = b.Sentinal dBrd = b.Scourge } else { aBrd = b.Scourge dBrd = b.Sentinal } - if aBrd[atk].Empty() || !aBrd[atk].CanAttack(atk, def) { - return -1 - } - aBrd[atk].Act() if dBrd[def].Empty() { //health damage - if id == 1 { + if id == SentinalID { b.Sentinal = aBrd b.Scourge = dBrd } else { @@ -132,29 +170,11 @@ func (b *Board) Attack(id int, atk, def int) int { return 1 } //Do actual battle math - attacker := aBrd[atk].Value() - defender := dBrd[def].Value() - 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 - } - } + attacker := aBrd[atk].Power + defender := dBrd[def].Power if attacker > defender { - dBrd[def] = CreateCard(-1) - if id == 1 { + dBrd[def] = NewCard(-1, uuid.Nil) + if id == SentinalID { b.Sentinal = aBrd b.Scourge = dBrd } else { @@ -164,8 +184,8 @@ func (b *Board) Attack(id int, atk, def int) int { return 0 } if attacker == defender { - aBrd[atk] = CreateCard(-1) - dBrd[def] = CreateCard(-1) + aBrd[atk] = NewCard(-1, uuid.Nil) + dBrd[def] = NewCard(-1, uuid.Nil) if id == 1 { b.Sentinal = aBrd b.Scourge = dBrd @@ -178,23 +198,3 @@ func (b *Board) Attack(id int, atk, def int) int { 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 -} diff --git a/internal/game/card.go b/internal/game/card.go index fd5b23e..2aee713 100644 --- a/internal/game/card.go +++ b/internal/game/card.go @@ -6,79 +6,18 @@ import ( "github.com/google/uuid" ) -type Card interface { - Cast(g *Game) *Game - Upkeep(g *Game) *Game - Endstep(g *Game) *Game - Enters(g *Game) *Game - Value() CardValue - Act() - Acted() bool - Empty() bool - String() string - CanAttack(int, int) bool - Port() *PortableCard +type Card struct { + Type CardType `json:"type"` + Power int `json:"power"` + Id uuid.UUID `json:"id"` + Sick bool `json:"sick"` + Counters int `json:"counters"` } -type GenericCard struct { - Val CardValue `json:"value"` - Id uuid.UUID `json:"id"` - Sick bool `json:"sick"` -} - -func (g *GenericCard) Cast(game *Game) *Game { - 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 +type CardType int const ( - Valk CardValue = iota + Valk CardType = iota Ace Two Three @@ -89,130 +28,33 @@ const ( Eight ) const ( - EmptyValue CardValue = -1 + EmptyValue CardType = -1 ) -func (c CardValue) String() string { +func (c CardType) String() string { if c == -1 { return " " } return []string{"V", "A", "2", "3", "4", "5", "6", "7", "8"}[c] } -func CreateCard(v int) Card { - return NewCard(v, 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 &AceCard{ - &GenericCard{ - Val: Ace, - Id: id, - Sick: false, - }, - } - 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, - } +func NewCard(v int, id uuid.UUID) *Card { + if id == uuid.Nil { + id = uuid.New() + } + return &Card{ + Type: CardType(v), + Power: OraclePower(CardType(v), nil), + Id: id, + Sick: false, + Counters: 0, } } -type EmptyCard struct { - *GenericCard +func (c *Card) Empty() bool { + return c.Type == EmptyValue } -func (e *EmptyCard) Empty() bool { - return true -} - -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"` +func (c *Card) String() string { + return fmt.Sprintf("|%v|", c.Type) } diff --git a/internal/game/deck.go b/internal/game/deck.go index 733c51d..aa732a6 100644 --- a/internal/game/deck.go +++ b/internal/game/deck.go @@ -1,20 +1,21 @@ package game import ( - "encoding/json" "math/rand" "time" + + "github.com/google/uuid" ) type Deck struct { - Cards []Card `json:"cards"` + Cards []*Card `json:"cards"` } func NewDeck() *Deck { - cards := []Card{CreateCard(0)} + cards := []*Card{NewCard(0, uuid.Nil)} for i := 0; i < 3; i++ { for j := 1; j < 9; j++ { - cards = append(cards, Card(CreateCard(j))) + cards = append(cards, NewCard(j, uuid.Nil)) } } return &Deck{ @@ -22,7 +23,7 @@ func NewDeck() *Deck { } } -func DeckFromCards(c []Card) *Deck { +func DeckFromCards(c []*Card) *Deck { return &Deck{ Cards: c, } @@ -38,11 +39,11 @@ func (d *Deck) Shuffle() { d.Cards = cards } -func (d *Deck) Scry(s int) []Card { - seen := []Card{} +func (d *Deck) Scry(s int) []*Card { + seen := []*Card{} if len(d.Cards) < s { seen = d.Cards - d.Cards = []Card{} + d.Cards = []*Card{} return seen } seen = d.Cards[(len(d.Cards) - s):len(d.Cards)] @@ -50,32 +51,10 @@ func (d *Deck) Scry(s int) []Card { return seen } -func (d *Deck) Bottom(result []Card) { +func (d *Deck) Bottom(result []*Card) { d.Cards = append(result, d.Cards...) //Should shuffle result first? } func (d *Deck) Size() int { 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 -} diff --git a/internal/game/game.go b/internal/game/game.go index abab658..4c4e2dd 100644 --- a/internal/game/game.go +++ b/internal/game/game.go @@ -2,6 +2,7 @@ package game import ( "fmt" + "log" "strconv" "strings" ) @@ -24,7 +25,7 @@ const ( ) 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 { @@ -52,7 +53,7 @@ func NewGame() *Game { SentinalDeck: deckA, ScourgeDeck: deckB, CurrentTurn: 0, //start with no turn - CardBuffer: DeckFromCards([]Card{}), + CardBuffer: DeckFromCards([]*Card{}), CanDraw: false, HasDrawn: false, Status: StatusLobby, @@ -162,11 +163,11 @@ func (g *Game) PlayerStateAct(id int, cmd string) *GameView { } if id == SentinalID { for _, v := range g.GameBoard.Sentinal { - v.Upkeep(g) + OracleUpkeep(v, g) } } else { for _, v := range g.GameBoard.Scourge { - v.Upkeep(g) + OracleUpkeep(v, g) } } case "e": @@ -174,14 +175,14 @@ func (g *Game) PlayerStateAct(id int, cmd string) *GameView { if id != g.CurrentTurn { return nil } - g.CardBuffer = DeckFromCards([]Card{}) + g.CardBuffer = DeckFromCards([]*Card{}) if id == SentinalID { for _, v := range g.GameBoard.Sentinal { - v.Endstep(g) + OracleEndstep(v, g) } } else { for _, v := range g.GameBoard.Scourge { - v.Endstep(g) + OracleEndstep(v, g) } } if g.CurrentTurn == SentinalID { @@ -256,11 +257,12 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck { } x_i, _ := strconv.Atoi(cmd_s[1]) y_i, _ := strconv.Atoi(cmd_s[2]) - res := g.GameBoard.Move(g.CurrentTurn, x_i, y_i) - if res { + if g.GameBoard.CanMove(g.CurrentTurn, x_i, y_i) { + 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)) } else { - return DeckFromCards([]Card{}) + return DeckFromCards([]*Card{}) } case "a": //attack @@ -272,15 +274,18 @@ func (g *Game) PlayerAct(id int, cmd string) *Deck { } x_i, _ := strconv.Atoi(cmd_s[1]) y_i, _ := strconv.Atoi(cmd_s[2]) - res := g.GameBoard.Attack(g.CurrentTurn, x_i, y_i) - if res == 1 { - opp.Life = opp.Life - 1 - return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) - } else if res == 0 { - return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) + 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) + if res == 1 { + opp.Life = opp.Life - 1 + return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) + } else { + return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) + } } else { - fmt.Println("can't attack") - return DeckFromCards([]Card{}) + log.Println("can't attack") + return DeckFromCards([]*Card{}) } case "p": //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]) y_i, _ := strconv.Atoi(cmd_s[2]) card := curr.Hand[x_i] - if g.GameBoard.CanPlay(g.CurrentTurn, &card, y_i) { - curr.Hand[x_i].Cast(g) - } - res := g.GameBoard.Play(g.CurrentTurn, &card, y_i) - if res { - curr.Hand[x_i].Enters(g) + shouldPlace := true + if g.GameBoard.CanPlay(g.CurrentTurn, card, y_i) { + shouldPlace = OracleCast(curr.Hand[x_i], g) + _ = g.GameBoard.Play(g.CurrentTurn, card, y_i, shouldPlace) + OracleEnters(curr.Hand[x_i], g) curr.Hand = append(curr.Hand[:x_i], curr.Hand[x_i+1:]...) return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn)) } else { fmt.Println("couldn't play") - return DeckFromCards([]Card{}) + return DeckFromCards([]*Card{}) } default: fmt.Println("Invalid act command") diff --git a/internal/game/oracle.go b/internal/game/oracle.go new file mode 100644 index 0000000..a7037d7 --- /dev/null +++ b/internal/game/oracle.go @@ -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 +} diff --git a/internal/game/player.go b/internal/game/player.go index 0ebaa3a..5c227b4 100644 --- a/internal/game/player.go +++ b/internal/game/player.go @@ -1,66 +1,17 @@ package game -import ( - "encoding/json" - "fmt" - "log" - - "github.com/google/uuid" -) - type Player struct { - Name string `json:"name"` - Id int `json:"id"` - Hand []Card `json:"hand"` - Life int `json:"life"` + Name string `json:"name"` + Id int `json:"id"` + Hand []*Card `json:"hand"` + Life int `json:"life"` } func NewPlayer(name string, id int) *Player { return &Player{ Name: name, Id: id, - Hand: []Card{}, + Hand: []*Card{}, 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 -}