30 August 2011

The Beauty of a Coded Revolving Door

I have been struggling with a programming problem for a couple of years that I found nearly impossible to solve. (I finally solved it just last week, but that is the point of this posting.) The problem was so overwhelming, and my desire to solve it so strong, that I would ask almost everyone that I had known for a while about it. I had asked programmers, biologists, geologists, physicists and just about everyone else I could think of (except artists and musicians who generally turn their noses up and programming related things). Though I would try to translate the problem into their respective field, they all got the same basic problem.

My primary purpose in asking so many people from so many different backgrounds was in hopes that one of them would spark some idea of a solution that I could run with. To my disappointment, none could offer any real help with the issue. Though, one programmer suggested using an array to store the variables which is eventually what I did and many added to the solution, none offered the big solution that I was hoping for. In the end, I should have expected that the solution would come from dozens of little nuggets instead of a giant lump.

The problem goes like this: There are eight basic virtues. I wish to determine a person's ultimate virtue, the one that overrides all others, partly because it is fun and partly because it can tell a lot about that person's perspective and thus why they do what they do.

The best way I know to determine the overriding virtue is to compare the each virtue against each other (a or b) instead of a ranking or other comparison. This method forces the person to decide which virtue is valued most of all in a given context. Such questioning results in a bank of 28 questions containing all the possible pairings (I did not develop the question bank; Origin Systems gets credit for that). In just seven questions, I can reduce the eight virtues down to the single most important virtue. To do this I ask a series of four randomly selected questions that compare all eight virtues, and only the eight virtues.

The first key to the problem was that there could be no overlap: each virtue is asked only once in the opening round. Asking any one virtue twice would defeat the purpose. The second key to the problem—and perhaps the more challenging—is the preference to have the first four questions randomized. If I would have forsaken the randomization then I could have solved the rest of the problem long ago; but what fun would that be? After the opening round, the virtues are then compared in a tournament style: the answers from questions one and two are compared in question five and the answers from questions three and four and compared in question six. The final question, question seven is a comparison of the answers from question five and six.

One of the primary motivators for programming this has been a desire to share the test with others. I could have simply given out the whole of 28 questions but knowing most people the sheer number and complexity of the questioning would have proved foreboding. Instead, I wanted to "hand out" a polished form of the test that could be taken as easily as shared. And, I must confess, at some point I find it difficult to flip through a list of 28 questions trying to remember which virtues have been compared and what the response were.

The solution to providing a randomized tournament questionnaire came while running. (Since my running partner decided to go home to get married, I wish them the best, I have found that I have a lot of thinking time while running and was able to bring together everyone’s input over the years.) Also a major part of the solution and jogging ideas has been my recent massive expenditure of time on learning Action Script 3 (the programming language of Adobe Flash) for another project. Everything came together and here is the final outline of the solution:
  1. All eight possible virtues are stored in an array (an array is a way to store multiple variable under a single name, like the shoe storage bins outside a play pin: one object, the shoe bin, multiple and separate slots). The array, called myVirtues, looks like this: myVirtues:Array = ["Compassion", "Honesty", "Valor", "Sacrifice", "Honor", "Justice", "Spirituality", "Humility"];
  2. The array is randomized using some quick sorting which is by no means scientific and I am sure not that good, but good enough.
  3. The brilliance that made the whole thing possible is: pop(). This attribute removes the last item from the array (i.e. takes out the last pair of shoes from the shoe bin). The removal ensures that the virtue cannot be reused and moves the marker to the next available virtue. pop() is ran again with the second virtue stored with the first one in another array called myQuiz.
  4. The second array, myQuiz, is sorted alphabetically before proceeding. This too was a stroke of brilliance inspired from by a friend teaching me calculus. Before the sorting, I was having to double all my coding related to matching myQuiz with the appropriate questions; once as a + b and again as b + a because I was not sure which order they would pop out in. By sorting them before the comparison I do not need to worry about the order because they will always be in alphabetical order so I only needed to make sure the values myQuiz is compared against were also in alphabetical order.
  5. Once myQuiz is matched to a question number, the question is presented to the user.
  6. At this point, I have come to realize that in terms of programming Google is my best friend for learning things but biology is my best teacher for helping me find solutions. I have found inspired solutions many times by learning how living creatures have developed to overcome obstacles. In my original plan of how to handle round two of questions I was going to create a third array to store the answers in. This turned out to be unneeded by using unshift() which does the opposite of pop(): it puts something in first place in the array and pushes everything else back one (i.e. it moves all the shoes down one slot and adds a pair into the first slot). This was somehow inspired by the way the body handles stress though the actual connection between the two escapes me. This technique reduces the amount of code needed by allowing the exact same mechanism that selects the first round of questions to handle the second and all subsequent rounds without modification. The initial array becomes a revolving door for providing virtues until the array is down to its last virtue.
For me, one of the most beautiful parts of the code is the "revolving door" array  because that with a single line of code the program knows when it has asked the seventh question: if(myVirtues.length > 1). The program keeps asking questions until it is done. No extra coding, just plain and simple "end of line."

Thank you to everyone who has ever answered my probing questions about the way things work, without you I would never have found this solution.

No comments:

Post a Comment