Kotlin and Android Development featuring Jetpack: Chapter 4 AI never gives up rolling (page 109)

I found a bug in Penny Drop’s logic that causes it to ignore the AI’s lambda so AI players keep rolling over and over until they bust.

In GameViewModel.updateFromGameHandler(), you have the following code that’s being used to disable the roll and pass buttons when the AI is playing:

if (!result.isGameOver && result.currentPlayer?.isHuman == false) {
    canRoll.value = false
    canPass.value = false

The problem is, the same value gets passed by the coroutine to GameHandler.playAITurn, short-circuits the call to ai.rollAgain(slots), and never actually HAS an opportunity to become non-false, regardless of how many times the AI player rolls the dice.

You can confirm it by setting a breakpoint on AI.coinFlipIsHeads, and playing against Random Rachel using the code from chapter 4 of the .zip file. It will literally never hit the breakpoint, because canPass is always false, and
if (!canPass || ai.rollAGain(slots)) inevitably short-circuits.

Here’s a fix I came up with (all changes to GameViewModel)

First, add a new val aiCanPass:

    val canRoll = MutableLiveData(false)
    val canPass = MutableLiveData(false)
->  val aiCanPass = MutableLiveData(false);
    val currentTurnText = MutableLiveData("")
    val currentStandingsText = MutableLiveData("")

Then, in updateFromGameHandler():

    if (!result.isGameOver && result.currentPlayer?.isHuman == false) {
      canRoll.value = false;
      canPass.value = false;
->    aiCanPass.value = result.canPass;

and in playAITurn():

      if(currentPlayer != null && !currentPlayer.isHuman) {
->        aiCanPass.value == true
        )?.let { result ->

You’re 100% right. This gets fixed once we start working with a DB and grabbing the logic from there, but the chapter 4 logic is buggy just as you described.

This is on my list for updates, thanks again!