Linking QiChat and Code

Putting it all together: the number decomposition quiz

Okay, so we did our first maths challenge, but multiplication is pretty easy. Let’s try something a bit more advanced: decomposing a number into factors; this will put into practice some things we saw previously.

Make sure to add this code below the previous QiChat, not to replace it - so that now, if you say “challenge me”, pepper will ask you one or another of the questions.

u:(challenge me) %DECOMPOSE_CHALLENGE
Can you decompose 28 as the product of two numbers?
   u1:({it's} 7 times 4)
   Right!
   u1:(*)
   Wrong!

Now, if we were to try to randomize this the same way we did before, but we’ll have the issue that there are a lot of ways of giving this answer, such as:

  • 4 x 7
  • 2 x 14
  • 1 x 28
    … we could enumerate all these possibilities, but this would make our code needlessly complicated.

Instead let’s use a ^execute statement, by passing parameters:

concept:(small_number) [2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20]
concept:(times) [times ×]

u:(challenge me) %DECOMPOSE_CHALLENGE
Can you decompose, $result as the product of two numbers? $show="? × ? ≟ $result"
   u1:({it's} _~small_number  _~times _~small_number)
   $1 $2 $3 $factorA=$1 $factorB=$3 $show="$factorA × $factorB ≟ $result" let's see ...
   ^execute(evaluateDecomposition, $factorA , $factorB )

proposal: %RESULT_RIGHT
$show="right!" Yes, you're right %RERANDOMIZE  $show=" "

proposal: %RESULT_WRONG
$show="$factorA × $factorB ≠ $result" No, $factorA times $factorB equals $wrongResult %RERANDOMIZE $show=" "

To keep things simple, use the same randomize function as before. Previously, the multiplication result was a local variable, now save it as a member variable so you can access it later on:

var multiplicationResult = -1

private fun randomize() {
   val numberA = Random.nextInt(3, 9)
   val numberB = Random.nextInt(3, 9)
   multiplicationResult = numberA * numberB
   // ...
}

And in onRobotFocusGained, two changes:

  • Add a new evaluateDecomposition executor
  • At start, go to the DECOMPOSE_CHALLENGE bookmark
override fun onRobotFocusGained(qiContext: QiContext) {
   // ...
   // Executors
   val executors : Map<String, QiChatExecutor> = hashMapOf(
       "drumRoll" to DrumRollExecutor(qiContext),
       "evaluateDecomposition" to EvaluateDecompositionExecutor(qiContext)
   )
   qiChatbot.executors = executors
   // Start the dialogue
   chat.addOnStartedListener {  goToBookmark("DECOMPOSE_CHALLENGE") }
   chat.run()
}

Create the executor as an inner class:

private inner class EvaluateDecompositionExecutor(qiContext: QiContext) :
   BaseQiChatExecutor(qiContext) {
   override fun runWith(params: List<String>) {
       Log.i(TAG, "Running with: $params")
       if (params.size >= 2) {
           val firstFactor = params[0].toInt()
           val secondFactor = params[1].toInt()
           if (firstFactor * secondFactor == multiplicationResult) {
               goToBookmark("RESULT_RIGHT")
           } else {
               goToBookmark("RESULT_WRONG")
               qiChatbot?.variable("wrongResult")?.value = (firstFactor * secondFactor).toString()
           }
       }
   }
   override fun stop() {}
}

... and now your pepper will ask you slightly more difficult question, putting together bookmarks, variables and ^execute.