Improve AI difficulty scaling.
This commit is contained in:
@@ -149,6 +149,17 @@ func (b *Bot) pick(cands []candidate) candidate {
|
||||
if len(cands) == 1 {
|
||||
return cands[0]
|
||||
}
|
||||
// Below competent play, the bot sometimes ignores its evaluation entirely
|
||||
// and plays a random legal move. Softmax temperature alone can't make a bot
|
||||
// a genuine pushover: it still samples among sensibly-generated candidates
|
||||
// and, on this game's shop/dice variance, that wins ~1 game in 5 even
|
||||
// against expert play. Real, occasional mistakes — buying the wrong pet,
|
||||
// passing with coins in hand, a scrambled battle order — are what let a
|
||||
// competent human beat "easy" almost every time. The rate is zero at and
|
||||
// above competent level, so medium and hard never blunder.
|
||||
if p := blunderProb(b.level); p > 0 && rand.Float64() < p {
|
||||
return cands[rand.IntN(len(cands))]
|
||||
}
|
||||
temp := 0.02 + 0.30*(1-b.level)
|
||||
best := math.Inf(-1)
|
||||
for _, c := range cands {
|
||||
@@ -170,6 +181,24 @@ func (b *Bot) pick(cands []candidate) candidate {
|
||||
return cands[len(cands)-1]
|
||||
}
|
||||
|
||||
// competentLevel is the skill (on the [0,1] level scale) at which the bot is
|
||||
// meant to be an even match for a competent human: at or above it the bot
|
||||
// never throws a game on purpose. Difficulties are calibrated around it —
|
||||
// easy well below, medium at it, hard above.
|
||||
const competentLevel = 0.6
|
||||
|
||||
// blunderProb is the chance pick discards its evaluation and plays a uniformly
|
||||
// random legal move. It is zero at competent level and above, and ramps up
|
||||
// steeply below, so only the easy tier makes real mistakes. blunderMax is the
|
||||
// rate at level 0 (the weakest possible bot).
|
||||
func blunderProb(level float64) float64 {
|
||||
const blunderMax = 0.75
|
||||
if level >= competentLevel {
|
||||
return 0
|
||||
}
|
||||
return blunderMax * (competentLevel - level) / competentLevel
|
||||
}
|
||||
|
||||
// budget returns the rollout counts for this difficulty: how many opponent
|
||||
// deck/order guesses to test against, and how many dice-randomized battle
|
||||
// simulations to run per guess. Fewer samples means noisier estimates, which
|
||||
|
||||
Reference in New Issue
Block a user