mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-16 08:52:42 +00:00
Equalize co-op gift magnitudes to kill 'always leave' dominant strategy
Old values (open ±7, leave ±4) had matching EV but asymmetric variance; risk-averse parties had a strict preference to always leave gifts, which collapsed the dilemma. New values (all ±6) keep EV=0 for both strategies AND equalize variance. Choice now depends entirely on inferring sender intent. Adds TestCoopGiftVarianceSymmetric — fails loud if anyone reintroduces asymmetric magnitudes. EV test was already in place but only checked the mean; missed this on first pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -626,12 +626,12 @@ Multi-day party runs separate from solo. 2–4 players, 2–7 days depending on
|
|||||||
|
|
||||||
**Spectator betting.** Parimutuel pool, 10% rake. Bets can be placed or increased any time during the run; positions are locked in (success or failure can't be switched). Party members can bet on their own run — sandbagging while heavily bet against is exploitative and visible. Odds line shows estimated success% based on party levels, pets, neutral funding assumption, and a hidden TwinBee Helpfulness Rating (rolling last 30 floor events: how often his recommendation was right). Helpfulness shifts the line ±20% but is never shown directly — players notice the line moves after events resolve.
|
**Spectator betting.** Parimutuel pool, 10% rake. Bets can be placed or increased any time during the run; positions are locked in (success or failure can't be switched). Party members can bet on their own run — sandbagging while heavily bet against is exploitative and visible. Odds line shows estimated success% based on party levels, pets, neutral funding assumption, and a hidden TwinBee Helpfulness Rating (rolling last 30 floor events: how often his recommendation was right). Helpfulness shifts the line ±20% but is never shown directly — players notice the line moves after events resolve.
|
||||||
|
|
||||||
**Gifts.** Anyone *not* in the run can spend one harvest action to send a Care Basket or a Mimic. The party never sees which type. Vote `open` or `leave`. Modifiers are EV-symmetric at a 50/50 sender mix:
|
**Gifts.** Anyone *not* in the run can spend one harvest action to send a Care Basket or a Mimic. The party never sees which type. Vote `open` or `leave`. Magnitudes are equalized across all four outcomes — both "always open" and "always leave" yield EV=0 with σ=6, so neither is risk-averse-dominant. The choice is purely about reading sender intent.
|
||||||
|
|
||||||
| | Open | Leave |
|
| | Open | Leave |
|
||||||
|-------------|------|-------|
|
|-------------|------|-------|
|
||||||
| **Care Basket** | +7% (boost) | −4% (basket explodes) |
|
| **Care Basket** | +6% (boost) | −6% (basket explodes) |
|
||||||
| **Mimic** | −7% (mimic does what mimics do) | +4% (sad mimic helps anyway) |
|
| **Mimic** | −6% (mimic does what mimics do) | +6% (sad mimic helps anyway) |
|
||||||
|
|
||||||
Multiple gifts stack additively — coordinated senders can swing odds significantly. The full gift log is public at end of run.
|
Multiple gifts stack additively — coordinated senders can swing odds significantly. The full gift log is public at end of run.
|
||||||
|
|
||||||
|
|||||||
@@ -16,21 +16,21 @@ import (
|
|||||||
|
|
||||||
// ── Gift Constants ──────────────────────────────────────────────────────────
|
// ── Gift Constants ──────────────────────────────────────────────────────────
|
||||||
//
|
//
|
||||||
// Modifiers chosen so the EV of "always open" vs "always leave" is symmetric
|
// Magnitudes equalized across all four outcomes so neither "always open" nor
|
||||||
// at a 50/50 sender mix — the party has to read the context, not the math.
|
// "always leave" is variance-dominant at a 50/50 sender mix. Asymmetric
|
||||||
|
// magnitudes (e.g., open=±7, leave=±4) gave leave the same EV with lower
|
||||||
|
// variance, making it a dominant strategy for risk-averse parties — which
|
||||||
|
// collapses the dilemma into "always leave."
|
||||||
//
|
//
|
||||||
// basket opened: +7 basket unopened: -4
|
// basket opened: +6 basket unopened: -6
|
||||||
// mimic opened: -7 mimic unopened: +4
|
// mimic opened: -6 mimic unopened: +6
|
||||||
//
|
//
|
||||||
// At 50/50 sender mix:
|
// Both strategies: EV=0, σ=6. The choice becomes "read sender intent" only.
|
||||||
// always open EV = 0.5×(+7) + 0.5×(−7) = 0
|
|
||||||
// always leave EV = 0.5×(−4) + 0.5×(+4) = 0
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
coopGiftBasketOpened = 7
|
coopGiftBasketOpened = 6
|
||||||
coopGiftBasketUnopened = -4
|
coopGiftBasketUnopened = -6
|
||||||
coopGiftMimicOpened = -7
|
coopGiftMimicOpened = -6
|
||||||
coopGiftMimicUnopened = 4
|
coopGiftMimicUnopened = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -293,6 +293,31 @@ func TestCoopGiftEVSymmetric(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCoopGiftVarianceSymmetric(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
// Equal EV is not enough — if open and leave have different variance, a
|
||||||
|
// risk-averse party always picks the lower-variance side and the
|
||||||
|
// dilemma collapses. Magnitudes must be equal across all four outcomes.
|
||||||
|
abs := func(x int) int {
|
||||||
|
if x < 0 {
|
||||||
|
return -x
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
mags := []int{
|
||||||
|
abs(coopGiftBasketOpened),
|
||||||
|
abs(coopGiftBasketUnopened),
|
||||||
|
abs(coopGiftMimicOpened),
|
||||||
|
abs(coopGiftMimicUnopened),
|
||||||
|
}
|
||||||
|
for i := 1; i < len(mags); i++ {
|
||||||
|
if mags[i] != mags[0] {
|
||||||
|
t.Errorf("gift magnitudes must be equal across all four outcomes; got %v", mags)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCoopParimutuelNoWinners(t *testing.T) {
|
func TestCoopParimutuelNoWinners(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
bets := []CoopBet{
|
bets := []CoopBet{
|
||||||
|
|||||||
Reference in New Issue
Block a user