Fix shop action costs and pass semantics.
Only buying costs gold; selling and trading (Triple) are free. Pass is now a final action, legal only at or under the pet limit: it forfeits remaining gold and ends that player's shopping for the round, with the shop closing once everyone has passed. That makes the separate cleanup phase unreachable (you sell down in-shop before passing), so it is removed. The client asks for confirmation before passing, and the bot knows buys are the only coin sink, when passing is legal, and that it must sell down before it can pass.
This commit is contained in:
@@ -65,11 +65,12 @@ func TestE2EBotGame(t *testing.T) {
|
||||
t.Fatal("no bot seat in the game")
|
||||
}
|
||||
|
||||
// Play the human side: pass whenever it's our turn. The game can only
|
||||
// reach the arrange phase if the bot spends its own three coins too.
|
||||
// Play the human side: pass on our first turn (passing is final, so one
|
||||
// is all we get). The game can only reach the arrange phase if the bot
|
||||
// shops and passes on its own too.
|
||||
deadline := time.Now().Add(25 * time.Second)
|
||||
for v.Phase == game.PhaseShop && time.Now().Before(deadline) {
|
||||
if v.Turn == v.YouSeat && v.Players[v.YouSeat].Coins > 0 && v.Pending == nil {
|
||||
if v.Turn == v.YouSeat && !v.Players[v.YouSeat].Ready && v.Pending == nil {
|
||||
send(t, ctx, ws, map[string]any{"type": "pass"})
|
||||
}
|
||||
rctx, rcancel := context.WithTimeout(ctx, 10*time.Second)
|
||||
|
||||
+11
-15
@@ -76,8 +76,6 @@ func botDelay(phase game.Phase) time.Duration {
|
||||
switch phase {
|
||||
case game.PhaseShop:
|
||||
return ms(700, 900)
|
||||
case game.PhaseCleanup:
|
||||
return ms(900, 600)
|
||||
case game.PhaseArrange:
|
||||
return ms(1600, 1600)
|
||||
default: // battle acknowledgement
|
||||
@@ -127,9 +125,6 @@ func applyBotAction(g *game.Game, playerID string, a *ai.Action) error {
|
||||
case "buy":
|
||||
return g.Buy(playerID, a.Row)
|
||||
case "sell":
|
||||
if g.Phase == game.PhaseCleanup {
|
||||
return g.CleanupSell(playerID, a.Cards)
|
||||
}
|
||||
return g.Sell(playerID, a.Cards)
|
||||
case "trade":
|
||||
return g.TradeStart(playerID, a.Cards)
|
||||
@@ -146,8 +141,9 @@ func applyBotAction(g *game.Game, playerID string, a *ai.Action) error {
|
||||
}
|
||||
|
||||
// botFallback makes the trivially legal move for whatever the game is
|
||||
// waiting on: pass the shop turn, take the first trade option, sell the
|
||||
// first excess pets, submit the deck as-is, or acknowledge the battle.
|
||||
// waiting on: pass the shop turn (selling down to the pet limit first if
|
||||
// passing would be refused), take the first trade option, submit the deck
|
||||
// as-is, or acknowledge the battle.
|
||||
func botFallback(g *game.Game, playerID string) error {
|
||||
p := g.PlayerByID(playerID)
|
||||
if p == nil {
|
||||
@@ -158,16 +154,16 @@ func botFallback(g *game.Game, playerID string) error {
|
||||
if g.Pending != nil && g.Pending.PlayerID == playerID {
|
||||
return g.TradeChoose(playerID, 0)
|
||||
}
|
||||
return g.Pass(playerID)
|
||||
case game.PhaseCleanup:
|
||||
excess := p.PetCount() - game.MaxPets
|
||||
ids := make([]string, 0, excess)
|
||||
for _, c := range p.Deck {
|
||||
if c.IsPet() && len(ids) < excess {
|
||||
ids = append(ids, c.ID)
|
||||
if excess := p.PetCount() - game.MaxPets; excess > 0 {
|
||||
ids := make([]string, 0, excess)
|
||||
for _, c := range p.Deck {
|
||||
if c.IsPet() && len(ids) < excess {
|
||||
ids = append(ids, c.ID)
|
||||
}
|
||||
}
|
||||
return g.Sell(playerID, ids)
|
||||
}
|
||||
return g.CleanupSell(playerID, ids)
|
||||
return g.Pass(playerID)
|
||||
case game.PhaseArrange:
|
||||
ids := make([]string, len(p.Deck))
|
||||
for i, c := range p.Deck {
|
||||
|
||||
@@ -122,11 +122,7 @@ func (s *Server) apply(r *room, c *client, msg clientMessage) {
|
||||
case "buy":
|
||||
err = g.Buy(c.playerID, msg.Row)
|
||||
case "sell":
|
||||
if g.Phase == game.PhaseCleanup {
|
||||
err = g.CleanupSell(c.playerID, msg.Cards)
|
||||
} else {
|
||||
err = g.Sell(c.playerID, msg.Cards)
|
||||
}
|
||||
err = g.Sell(c.playerID, msg.Cards)
|
||||
case "trade":
|
||||
err = g.TradeStart(c.playerID, msg.Cards)
|
||||
case "tradeChoose":
|
||||
|
||||
Reference in New Issue
Block a user