Improve AI to stop selling everything.
This commit is contained in:
@@ -242,11 +242,27 @@ func (b *Bot) decideShop(v *game.View, mem *Memory) *Action {
|
||||
}
|
||||
return 0
|
||||
})
|
||||
// Selling a pet permanently trades a body for a temporary apple — the
|
||||
// apple's one-battle buff shows up in the rollout, but it vanishes next
|
||||
// round, so the persistent value of the pet is simply destroyed. The
|
||||
// future-value term barely registers this (normFuture squashes small deck
|
||||
// swings), which once let the bot treat "sell my worst pet" as free and
|
||||
// bleed its board down to a single pet over successive shop turns. This
|
||||
// explicit penalty prices the loss back in: it scales with the persistent
|
||||
// worth of the pets sold and with how much the future still matters
|
||||
// (1-alpha), so it bites hardest early and fades to nothing in the final
|
||||
// round, where selling for a decisive last battle is a legitimate play the
|
||||
// rollout can judge on its own.
|
||||
futureWeight := 1 - immediateWeight(v)
|
||||
for k := 1; k <= min(3, len(sellable)); k++ {
|
||||
ids := make([]string, 0, k)
|
||||
nd := slices.Clone(deck)
|
||||
petValueSold := 0.0
|
||||
for _, s := range sellable[:k] {
|
||||
ids = append(ids, s.ID)
|
||||
if s.IsPet() {
|
||||
petValueSold += keepValue(s)
|
||||
}
|
||||
idx := slices.IndexFunc(nd, func(c game.Card) bool { return c.ID == s.ID })
|
||||
nd = slices.Delete(nd, idx, idx+1)
|
||||
nd = append(nd, cx.simApple())
|
||||
@@ -260,6 +276,7 @@ func (b *Bot) decideShop(v *game.View, mem *Memory) *Action {
|
||||
cands = append(cands, candidate{
|
||||
act: &Action{Type: "sell", Cards: ids},
|
||||
decks: [][]game.Card{nd},
|
||||
bias: -sellPetPenalty * futureWeight * petValueSold,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -297,6 +314,13 @@ func (b *Bot) decideShop(v *game.View, mem *Memory) *Action {
|
||||
base = slices.Delete(base, idx, idx+1)
|
||||
base = cx.applyTemplateShopEffects(base, t, game.TriggerTriple)
|
||||
}
|
||||
// Never bet the whole board on the trade: the reward is the top of
|
||||
// the next tier's deck, which can be a food card (or nothing, if the
|
||||
// deck is spent), so trading away the last pets risks an all-food,
|
||||
// auto-losing deck. Mirror the sell guard and skip such a trade.
|
||||
if !deckHasPet(base) {
|
||||
continue
|
||||
}
|
||||
pool := cx.unseenPool(v.Round + 1)
|
||||
if len(pool) == 0 {
|
||||
pool = game.TierContentsForPack(v.Pack, v.Round+1)
|
||||
|
||||
Reference in New Issue
Block a user