Skip to content

Commit

Permalink
fixed game state for persistence
Browse files Browse the repository at this point in the history
  • Loading branch information
ardan-bkennedy committed Jan 28, 2024
1 parent 7518b09 commit 5398e7b
Show file tree
Hide file tree
Showing 6 changed files with 183 additions and 130 deletions.
23 changes: 1 addition & 22 deletions app/services/engine/v1/handlers/gamegrp/gamegrp.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,8 +202,6 @@ func (h *handlers) tables(ctx context.Context, w http.ResponseWriter, r *http.Re
// state will return information about the game.
func (h *handlers) state(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
claims := mid.GetClaims(ctx)
address := common.HexToAddress(claims.Subject)

gameID := web.Param(ctx, "id")

g, err := game.Tables.Retrieve(gameID)
Expand All @@ -215,26 +213,7 @@ func (h *handlers) state(ctx context.Context, w http.ResponseWriter, r *http.Req
return web.Respond(ctx, w, resp, http.StatusOK)
}

state := g.State(ctx)

var cups []appCup
for _, accountID := range state.ExistingPlayers {
cup := state.Cups[accountID]

// Don't share the dice information for other players.
dice := []int{0, 0, 0, 0, 0}
if accountID == address {
dice = cup.Dice
}
cups = append(cups, toAppCup(cup, dice))
}

var bets []appBet
for _, bet := range state.Bets {
bets = append(bets, toAppBet(bet))
}

return web.Respond(ctx, w, toAppState(state, h.anteUSD, cups, bets), http.StatusOK)
return web.Respond(ctx, w, toAppState(g.State(ctx), h.anteUSD, common.HexToAddress(claims.Subject)), http.StatusOK)
}

// newGame creates a new game if there is no game or the status of the current game
Expand Down
26 changes: 24 additions & 2 deletions app/services/engine/v1/handlers/gamegrp/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,29 @@ type appState struct {
Balances []string `json:"balances"`
}

func toAppState(state game.State, anteUSD float64, cups []appCup, bets []appBet) appState {
func toAppState(state game.State, anteUSD float64, address common.Address) appState {
var cups []appCup
for _, accountID := range state.ExistingPlayers {
cup := state.Cups[accountID]

// Don't share the dice information for other players.
dice := []int{0, 0, 0, 0, 0}
if accountID == address {
dice = cup.Dice
}
cups = append(cups, toAppCup(cup, dice))
}

var bets []appBet
for _, bet := range state.Bets {
bets = append(bets, toAppBet(bet))
}

var balances []string
for _, balance := range state.Balances {
balances = append(balances, balance.Amount)
}

return appState{
GameID: state.GameID,
Status: state.Status,
Expand All @@ -31,7 +53,7 @@ func toAppState(state game.State, anteUSD float64, cups []appCup, bets []appBet)
Cups: cups,
ExistingPlayers: state.ExistingPlayers,
Bets: bets,
Balances: state.Balances,
Balances: balances,
}
}

Expand Down
63 changes: 38 additions & 25 deletions business/core/game/game.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@ type Banker interface {

// Game represents a single game that is being played.
type Game struct {
log *logger.Logger
converter *currency.Converter
banker Banker
mu sync.RWMutex
id string // Unique game id.
status string // Current status of the game.
round int // Current round of the game.
anteUSD float64 // The ante for joining this game.
cups map[common.Address]Cup // Game players with indexes cup access.
players []common.Address // Game players in the order they were added.
existingPlayers []common.Address // The set of players still in the game.
playerBalancesGWei []*big.Float // The balances of the players when added.
playerTurn int // The index of the player who's turn it is.
playerLastOut common.Address // The player who lost the last round.
playerLastWin common.Address // The player who won the last round.
bets []Bet // History of bets for the current round.
createdDate time.Time // The time the game was created. Used to help with caching.
log *logger.Logger
converter *currency.Converter
banker Banker
mu sync.RWMutex
id string // Unique game id.
createdDate time.Time // The time the game was created. Used to help with caching.
round int // Current round of the game.
status string // Current status of the game.
anteUSD float64 // The ante for joining this game.
playerLastOut common.Address // The player who lost the last round.
playerLastWin common.Address // The player who won the last round.
playerTurn int // The index of the player who's turn it is.
players []common.Address // Game players in the order they were added.
existingPlayers []common.Address // The set of players still in the game.
cups map[common.Address]Cup // Game players with indexes cup access.
bets []Bet // History of bets for the current round.
balancesGWei []Balance // The balances of the players when added.
}

// New creates a new game.
Expand Down Expand Up @@ -149,7 +149,11 @@ func (g *Game) AddAccount(ctx context.Context, player common.Address) error {

g.players = append(g.players, player)
g.existingPlayers = append(g.existingPlayers, player)
g.playerBalancesGWei = append(g.playerBalancesGWei, balanceGwei)

g.balancesGWei = append(g.balancesGWei, Balance{
Player: player,
Amount: balanceGwei,
})

return nil
}
Expand Down Expand Up @@ -531,8 +535,14 @@ func (g *Game) Reconcile(ctx context.Context) (*types.Transaction, *types.Receip
g.log.Info(ctx, "game.reconcole.updatebalance", "ERROR", err)
continue
}
oldBalanceGWei := g.playerBalancesGWei[i]
g.playerBalancesGWei[i] = balanceGwei

oldBalanceGWei := g.balancesGWei[i]

g.balancesGWei[i] = Balance{
Player: player,
Amount: balanceGwei,
}

g.log.Info(ctx, "game.reconcole.updatebalance", "player", player, "oldBlanceGWei", oldBalanceGWei, "balanceGWei", balanceGwei)
}

Expand All @@ -555,20 +565,23 @@ func (g *Game) State(ctx context.Context) State {
bets := make([]Bet, len(g.bets))
copy(bets, g.bets)

balances := make([]string, len(g.playerBalancesGWei))
for i, bal := range g.playerBalancesGWei {
balances[i] = g.converter.GWei2USD(bal)
balances := make([]BalanceFmt, len(g.balancesGWei))
for i, balance := range g.balancesGWei {
balances[i] = BalanceFmt{
Player: balance.Player,
Amount: g.converter.GWei2USD(balance.Amount),
}
}

return State{
GameID: g.id,
Round: g.round,
Status: g.status,
PlayerLastOut: g.playerLastOut,
PlayerLastWin: g.playerLastWin,
PlayerTurn: g.existingPlayers[g.playerTurn],
Round: g.round,
Cups: cups,
ExistingPlayers: existingPlayers,
Cups: cups,
Bets: bets,
Balances: balances,
}
Expand Down
20 changes: 17 additions & 3 deletions business/core/game/model.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package game

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
)

Expand All @@ -20,15 +22,15 @@ const minNumberPlayers = 2
// State represents a copy of the game state.
type State struct {
GameID string
Round int
Status string
PlayerLastOut common.Address
PlayerLastWin common.Address
PlayerTurn common.Address
Round int
Cups map[common.Address]Cup
ExistingPlayers []common.Address
Cups map[common.Address]Cup
Bets []Bet
Balances []string
Balances []BalanceFmt
}

// Bet represents a bet of dice made by a player.
Expand All @@ -45,3 +47,15 @@ type Cup struct {
Outs int
Dice []int
}

// Balance represents an individual balance for a player.
type Balance struct {
Player common.Address
Amount *big.Float
}

// BalanceFmt represents an individual formatted balance for a player.
type BalanceFmt struct {
Player common.Address
Amount string
}
121 changes: 82 additions & 39 deletions business/core/game/stores/gamedb/model.go
Original file line number Diff line number Diff line change
@@ -1,54 +1,97 @@
package gamedb

import (
"time"

"github.com/ardanlabs/liarsdice/business/core/game"
"github.com/ardanlabs/liarsdice/business/data/sqldb/dbarray"
)

type dbGame struct {
ID string `db:"game_id"`
Name string `db:"name"`
ID string `db:"game_id"`
Name string `db:"name"`
CreatedDate time.Time `db:"created_date"`
State dbState
Cups []dbCup
Bets []dbBet
Balances []dbBalance
}

type dbGameStatus struct {
ID string `db:"game_id"`
Iteration int `db:"iteration"`
Status string `db:"status"`
PlayerLastOut string `db:"player_last_out"`
PlayerLastWin string `db:"player_last_win"`
PlayerTurn string `db:"player_turn"`
Round int `db:"round"`
type dbState struct {
Round int `db:"round"`
Status string `db:"status"`
PlayerLastOut string `db:"player_last_out"`
PlayerLastWin string `db:"player_last_win"`
PlayerTurn string `db:"player_turn"`
ExistingPlayers any `db:"existing_players"`
}

type dbGameCup struct {
ID string `db:"game_id"`
Iteration int `db:"iteration"`
Player string `db:"player"`
OrderIdx int `db:"order_idx"`
Outs int `db:"outs"`
type dbCup struct {
Round int `db:"round"`
Player string `db:"player"`
OrderIdx int `db:"order_idx"`
Outs int `db:"outs"`
Dice any `db:"dice"`
}

type dbGameDice struct {
ID string `db:"game_id"`
Iteration int `db:"iteration"`
Player string `db:"player"`
Dice int `db:"dice"`
type dbBet struct {
Round int `db:"round"`
Player string `db:"player"`
Number int `db:"number"`
Suit int `db:"suit"`
}

type dbGameExistingPlayers struct {
ID string `db:"game_id"`
Iteration int `db:"iteration"`
Player string `db:"player"`
type dbBalance struct {
Round int `db:"round"`
Player string `db:"player"`
Amount string `db:"amount"`
}

type dbGameBets struct {
ID string `db:"game_id"`
Iteration int `db:"iteration"`
Player string `db:"player"`
Number int `db:"number"`
Suit int `db:"suit"`
}
func toDBGame(g *game.Game, state game.State) dbGame {
cups := make([]dbCup, len(state.Cups))
for player, cup := range state.Cups {
cups = append(cups, dbCup{
Round: state.Round,
Player: player.String(),
OrderIdx: cup.OrderIdx,
Outs: cup.Outs,
Dice: dbarray.Array(cup.Dice),
})
}

type dbGameBalances struct {
ID string `db:"game_id"`
Iteration int `db:"iteration"`
Player string `db:"player"`
Balance string `db:"balance"`
}
bets := make([]dbBet, len(state.Bets))
for _, bet := range state.Bets {
bets = append(bets, dbBet{
Round: state.Round,
Player: bet.Player.String(),
Number: bet.Number,
Suit: bet.Suit,
})
}

balances := make([]dbBalance, len(state.Balances))
for _, balance := range state.Balances {
balances = append(balances, dbBalance{
Round: state.Round,
Player: balance.Player.String(),
Amount: balance.Amount,
})
}

// func toDBGame(status game.State)
return dbGame{
ID: state.GameID,
Name: state.GameID,
CreatedDate: g.CreatedDate(),
State: dbState{
Round: state.Round,
Status: state.Status,
PlayerLastOut: state.PlayerLastOut.String(),
PlayerLastWin: state.PlayerLastWin.String(),
PlayerTurn: state.PlayerTurn.String(),
ExistingPlayers: dbarray.Array(state.ExistingPlayers),
},
Cups: cups,
Bets: bets,
Balances: balances,
}
}
Loading

0 comments on commit 5398e7b

Please sign in to comment.