Monday, July 10, 2017

The "Any 3 for 15" Game and the Courage to Start Over

I'm again teaching two courses for the University of Georgia this summer. One is a design course and recently we were talking about accessibility. I've tried to broaden my students' understanding of accessibility. I want them to see accessibility more as a design paradigm rather than a set of mandated technical requirements. That is, instead of seeing accessibility as nuisance for a designer, I want them to see accessibility as an opportunity to improve their designs.

One little activity I've used over the years is a cool little game that demonstrates the power of representation, namely that the way a concept, principle, or procedure is represented can dramatically alter the ease of learning it.

The rules of the game are simple. There are two players and each takes turn picking a number from 1 to 9. Once a number is chosen, it is unavailable to be chosen again. The player with the first hand with any three numbers that equal 15 is the winner. It's a surprisingly challenging game to play. As we play it, people begin to have the feeling that they've played the game before. There is a big reveal at the end. It turns out that this little game is really just tic-tac-toe (also known as naughts and crosses), but in mathematical form. The game is fully revealed when the numbers are shown in this pattern:


This is commonly known as a magic square. Notice how any row, column, or diagonal adds up to 15. Obviously, adults don't play tic-tac-toe any more because once you know the secret to choosing the center square, there is no way you can lose. However, even after the big reveal, the math version of the game is still a challenge to player. The two versions of the game have exactly the same rules, but the representation of each is dramatically different. My hope is that students will take this point to heart and try to find the best representation for their designs.

Creating a Version of the Game with LiveCode


I've had groups play this game for years using PowerPoint. I would just stay in edit mode and manually move the numbers around as the game is played. However, it occurred to me a few hours before class that I could create a quick version in LiveCode that would be easier to manage. Forty-five minutes later, I had a nice working version of the game. I still had to mentally keep checking to see if one of the players had three numbers that added up to 15. After class I thought it be great to program LiveCode to do this checking. Well, that began a design saga that took me over a week to complete.

Identifying All Unique Groups of Three Numbers


The algorithm needs to check all possible combinations of three numbers in the player's hand after each turn. I saw a couple of way to handle this problem. One way is to use a well-known formula to determine the total number of possible combinations, then turn LiveCode loose spitting out random combinations until all of the unique ones were found. Here's the formula:


r is the number of numbers in a given combination, which is always 3 in this case.

n is the total number of numbers in the list, which is the number of numbers a player has drawn up that point.

Obviously, the player has to have at least three numbers before you start calculating. And, the most numbers a player will have is 5 given that the players take turns drawing numbers. The formula above indicates there are only a total of 10 unique combinations of three numbers in a list of 5 numbers. (Order of the numbers obviously does not matter.)

A better strategy - and the one I selected - was to figure out the algorithm first, mapping it out step by step on paper. It's pretty simple:

Take five numbers: 1, 2, 3, 4, 5

The pattern of combinations can be determined as follows:

123
124
125
134
135
145
234
235
245
345

Yep, there are 10 of them. Do you see the pattern? There are three loops here corresponding to each digit in a row. Believe me, it is very easy to get totally confused in trying to troubleshoot a problem with an algorithm having three interwoven loops - it's like trying to balance three spinning plates on sticks. Once you focus on one, the others are prone to fall.

I spent about two hours on a Sunday afternoon working on this without success. I came back to the problem that evening, only to find myself thoroughly confused. So, I started over.

On the Reluctance to Start Over


I had about three hours invested in an approach that was not working. At times, it appeared I was tantalizingly close, just to have the algorithm fall apart again. The idea of starting over after having invested so much time is a tough pill to swallow. And yes, I think it does take some courage to admit defeat and start from scratch.

I turned to a favorite strategy where I build a new "toy app" from scratch that focuses solely on this one problem. In this virtual sandbox, I find I can focus better on a thorny problem. It really helps to start with a blank canvas and not have all of the other stuff from the bigger project jumbling around in your head. It was a busy week, so it was only Wednesday when I got round to doing this.

Unfortunately, my second approach yielded the same confounding results. And I again decided I needed to start over. Fortunately, all of the code this time was contained in a single button in a very simple stack, so I just moved that button off to the side and made a new button. I worked on this Friday night and some of Saturday. And, I again got myself into a brain splitting knot.

Fourth Time's a Charm


I again decided to start over. Although I had basically the right idea behind the loops, my approach to ending one loop and starting the next was flawed. The week's efforts convinced me that I needed to focus on the most concrete representation of the problem I could muster. So, instead of working with ever growing looping lists within variables, I used fields as containers. This gave me a visual form to seeing how the algorithm worked, not unlike the tic-tac-toe example.

I don't think I can sufficiently or succinctly explain my solution here, but suffice it to say it was a joyous moment when my program finally worked.

The lesson to take away here is sometimes the wisest way to solve a problem is to abandon an approach -- regardless of the amount of time already invested in it -- and start over.  Knowing when to throw in the towel is tricky, but I guess that's where the wisdom comes in.

Play the "Any 3 for 15" Game


(Alert! Depending on your Internet speed, this can take a full minute to download.)

And yes, the game title definitely needs work. Right now, it sounds like a selfish version of the Three Musketeers motto (i.e. "All for one and one for all").

A Final Note: Computing Factorials with LiveCode


I mentioned that I flirted with the idea first of using the formula above as my starting point for my solution to this problem. I spent about 15 minutes trying to program LiveCode to compute the factorial of a given number. I would have eventually figured it out, but fortunately,I stopped and did a google search and found a very elegant solution:

The example comes from this web page:

http://docs.runrev.com/Control-Structure/function

To quote from that page:

"A function can call itself. The following example calls itself to compute the factorial of an integer:"

 function factorial theNumber  
 if theNumber <= 1 then return 1  
 else return theNumber * factorial(theNumber -1)  
 end factorial  

My solution would have been quite convoluted in comparison. And, I learned something new about LiveCode as a result.