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

View File

@ -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 GenericCard struct {
Val CardValue `json:"value"`
type Card struct {
Type CardType `json:"type"`
Power int `json:"power"`
Id uuid.UUID `json:"id"`
Sick bool `json:"sick"`
Counters int `json:"counters"`
}
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,
},
func NewCard(v int, id uuid.UUID) *Card {
if id == uuid.Nil {
id = uuid.New()
}
case 1:
return &AceCard{
&GenericCard{
Val: Ace,
return &Card{
Type: CardType(v),
Power: OraclePower(CardType(v), nil),
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,
}
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)
}

View File

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

View File

@ -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])
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 if res == 0 {
return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn))
} else {
fmt.Println("can't attack")
return DeckFromCards([]Card{})
return DeckFromCards(g.GameBoard.GetRow(g.CurrentTurn))
}
} else {
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")

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
import (
"encoding/json"
"fmt"
"log"
"github.com/google/uuid"
)
type Player struct {
Name string `json:"name"`
Id int `json:"id"`
Hand []Card `json:"hand"`
Hand []*Card `json:"hand"`
Life int `json:"life"`
}
@ -19,48 +11,7 @@ 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
}