Quote the real price when a call exceeds the stack
Facing more than you have left is a call for your whole stack — commit() clamps the commitment — so labelling it "Call 35" when only 20 can be paid promised a price the player could neither make nor owed. It now reads "All in 20". The ViewModel also submits the clamped amount rather than relying on the engine to fix it up, so the action sent never disagrees with the label shown. Verified by reverting: both new label tests fail. Tests: 141 -> 144 (64 engine JVM, 64 Android host, 16 app). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,8 @@ import com.jsjdesigns.poker.game.DecisionOffer
|
||||
data class ActionButtons(
|
||||
val showFold: Boolean,
|
||||
val checkOrCallLabel: String,
|
||||
/** What calling actually costs: the engine clamps a call to the stack. */
|
||||
val effectiveCall: Int,
|
||||
val showRaise: Boolean,
|
||||
/** False when there is exactly one legal raise size, so a slider is pointless. */
|
||||
val showSlider: Boolean,
|
||||
@@ -29,10 +31,20 @@ fun buttonsFor(offer: DecisionOffer): ActionButtons {
|
||||
val low = if (shoveOnly) offer.maxRaiseTo else offer.minRaiseTo
|
||||
val high = offer.maxRaiseTo
|
||||
|
||||
// Facing more than you have left is a call for your whole stack: the engine
|
||||
// clamps the commitment, so quoting the full price promises something the
|
||||
// player cannot pay and does not owe.
|
||||
val effectiveCall = minOf(offer.toCall, offer.stack)
|
||||
|
||||
return ActionButtons(
|
||||
// Folding a free hand is never correct, so don't invite an accidental muck.
|
||||
showFold = !offer.canCheck,
|
||||
checkOrCallLabel = if (offer.canCheck) "Check" else "Call ${offer.toCall}",
|
||||
checkOrCallLabel = when {
|
||||
offer.canCheck -> "Check"
|
||||
effectiveCall >= offer.stack -> "All in $effectiveCall"
|
||||
else -> "Call $effectiveCall"
|
||||
},
|
||||
effectiveCall = effectiveCall,
|
||||
showRaise = offer.canRaise,
|
||||
showSlider = high > low,
|
||||
sliderMin = low,
|
||||
|
||||
@@ -153,7 +153,10 @@ class PokerViewModel : ViewModel() {
|
||||
fun checkOrCall(token: Long) {
|
||||
val o = offer.value ?: return
|
||||
if (o.token != token) return
|
||||
submit(token, if (o.canCheck) Action(ActionType.CHECK) else Action(ActionType.CALL, o.toCall))
|
||||
// Send what the button promised. The engine would clamp an oversized call
|
||||
// anyway, but the submitted action should not disagree with the label.
|
||||
val cost = minOf(o.toCall, o.stack)
|
||||
submit(token, if (o.canCheck) Action(ActionType.CHECK) else Action(ActionType.CALL, cost))
|
||||
}
|
||||
|
||||
fun raiseTo(token: Long, amount: Int) = submit(token, Action(ActionType.RAISE, amount))
|
||||
|
||||
@@ -97,3 +97,48 @@ class ActionButtonsTest {
|
||||
assertEquals("All in", raiseLabel(b, 500))
|
||||
}
|
||||
}
|
||||
|
||||
class CallCostTest {
|
||||
|
||||
private fun offer(toCall: Int, stack: Int) = DecisionOffer(
|
||||
token = 1L,
|
||||
handNumber = 1,
|
||||
street = Street.RIVER,
|
||||
seat = 0,
|
||||
hole = listOf(0, 1),
|
||||
board = emptyList(),
|
||||
pot = 100,
|
||||
toCall = toCall,
|
||||
minRaiseTo = 999,
|
||||
maxRaiseTo = stack,
|
||||
stack = stack,
|
||||
canCheck = false,
|
||||
canRaise = false,
|
||||
)
|
||||
|
||||
/**
|
||||
* Facing more than you have left is a call for your whole stack; the engine
|
||||
* clamps the commitment. Quoting the full price promised a payment the player
|
||||
* could not make and did not owe.
|
||||
*/
|
||||
@Test
|
||||
fun `facing more than the stack is labelled as an all in for the stack`() {
|
||||
val b = buttonsFor(offer(toCall = 35, stack = 20))
|
||||
assertEquals("All in 20", b.checkOrCallLabel)
|
||||
assertEquals(20, b.effectiveCall)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `calling exactly the stack is also an all in`() {
|
||||
val b = buttonsFor(offer(toCall = 20, stack = 20))
|
||||
assertEquals("All in 20", b.checkOrCallLabel)
|
||||
assertEquals(20, b.effectiveCall)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `an affordable call quotes the real price`() {
|
||||
val b = buttonsFor(offer(toCall = 35, stack = 500))
|
||||
assertEquals("Call 35", b.checkOrCallLabel)
|
||||
assertEquals(35, b.effectiveCall)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user