Thursday, February 16, 2012

Addition Flashcard Game

 
 


Psychologists have used various math tasks as a measure of mental abilities and a manipulation of mental workload for years.  This includes various math tasks in the PEBL Test battery, as well as things like backward arithmetic and the operation span task.  But this post shows a small little 'flashcard' game I made for my daughter to help her practice adding.




The goal was simple: present on the screen a math problem, allow the user to enter the answer, and when correct move on to the next one.  Do ten of these, record the time, and keep track of the time so she can try to beat her record.


So, the first question is, how do we generate a problem?  It would be easy to sample two digits between 0 and some number (say 10), figure out the sum by adding them up.  But that isn't where her skill level is right now, and it will tend to focus on sums around 10, rather than equally distributed from 0 to 20.  A better way to do it is to sample what the sum should be (equally between 1 and some number), then sample what one part of the sum should be (less than the sum), and compute what the other should be:


   sum <- RandomDiscrete(9)
   s1 <- RandomDiscrete(sum)
   s2 <- sum-s1









 



Now, we'd like to display the problem.  To do that, I'll make two text boxes: one for the problem, and one for the answer.


  tb <-  EasyTextBox(s1+  CR(1) + "+" + s2,6) + 
                     CR(1)+" _____" , 300,100,gWin,44,300,180)
   answer <- EasyTextBox("",300,285,gWin,44,300,70)




It will look sort of like this:


But I really like these aligned somehow. want the font to be monospaced rather than the default, so I'll create a font and change the font of these text boxes:
  font <- MakeFont("DejavuSansMono.ttf",0,44,
                    MakeColor("black"),MakeColor("white"),0)
  tb.font <- font
  answer.font <- font


Also, I want the text to be right-aligned. Because this is a mono-spaced font, we can just add spaces to the beginning of each row so its total length is what we want.  PEBL has a Format() function which does this on the right side, but no function for the left.  Let's call it PadFront().  The proper code would be:

   tb <-  EasyTextBox(PadFront(s1,6) + CR(1) +
               PadFront("+  "+s2,6)+CR(1)+" _____" , 
                300,100,gWin,44,300,180)




Now, it is just a matter of writing the PadFront function, which adds space to the beginning of a string until it is long enough.

define PadFront(in, size)
{
  text <- in +""
sl <- StringLength(text)
if(StringLength(text)>=size)
    {
           ret <- text
        }else {
           ret <- ListToString(Repeat(" ",(size-sl))) + text
 
       }
  return ret
}



The last piece is to get the input.  I want to validate the answer, so that if a wrong answer is provided, the answer disappears and they have to try again.  I'll use the GetInput function, and loop until the right answer is given.

   ans <- ""
   while(not ans ==sum+"" )
         {
           
              ans <- GetInput(answer,"")

               if(not ans == sum+"")
              {
                 ##You could play a sound  here
                answer.text <- ""
              } 

       }



Now it is just a matter of putting these pieces together and wrapping it in a main function.  The complete program is copied at the bottom of this post.  To change the range of the sum problems, edit gLowerSum and gUpperSum in a text editor.




define Start(p)
{
  gWin <- MakeWindow("black")
  gsleepEasy <- 1
  tb <-  EasyTextBox("",200,200,gWin,22,400,200)
  besttime <- -1
  best <- EasyLabel("",600,20,gWin,30) 

  ShowCursor(0)

   gLowerSum <- 1
   gUpperSum <- 9

   cont <- 1
   while(cont)
    {
     tb.text <- "READY? Press any key to begin."
     Show(tb)
     Draw()
     Hide(tb)
     WaitForAnyKEyPress()

   time1 <- GetTime()
   i <- 1
  while(i <=10)
  {
      SumProblem()
     i <- i + 1
  }
   time2 <- GetTime()

    time <- ROUNd((time2-time1)/1000,2)

   tb.text <- (i-1) +"  problems in   "+time +" seconds.  Again? [y/n]"
   Show(tb)
  
    if(time < besttime or besttime < 0)
     {
      besttime <- time
      best.text <- "Best time: "+time
    } 
 Draw()
   resp <- WaitForListKeyPress(["y","n"])
   if(resp=="n")
   {
     cont<- 0
   }
   Hide(tb)
}
}

define SumProblem ()
{

  font <- MakeFont("DejavuSansMono.ttf",0,44,  

                    MakeColor("black"),MakeColor("white"),0)

   sum <- RandomDiscrete(gUpperSum-gLowerSum+1) + gLowerSum - 1
   s1 <- RandomDiscrete(sum)
   s2 <- sum-s1

   tb <-  EasyTextBox(PadFront(s1,6) + CR(1) + PadFront("+  "+s2,6)+CR(1)+

                       " _____" , 300,100,gWin,44,300,180)

   answer <- EasyTextBox("",300,285,gWin,44,300,70)
  tb.font <- font
   answer.font <- font

   Draw()
  
   ans <- ""
   while(not ans ==sum+"" )
         {

              ans <- GetInput(answer,"")

               if(not ans == sum+"")
              {
                answer.text <- ""
              }   

       } 
}


define PadFront(in, size)
{
  text <- in +""
sl <- StringLength(text)
if(StringLength(text)>=size)
    {
           ret <- text
        }else {
           ret <- ListToString(Repeat(" ",(size-sl))) + text
 
       }
  return ret
}

No comments: