Thursday, April 4, 2013

Crack the Code!

I have designed a little game based on the encryption scripts I have discussed in my recent postings. I'm calling it "Crack the Code."

The goal of the game is to identify an "encrypted" word as fast as you can without making any mistakes. If you make even one mistake, the game is over. The player's score is based on the time it takes to identify the word in the group, using a countdown timer starting at 20. So, if you identify the word immediately, you get 20 points. If it takes you 15 seconds to determine the word, your score is 5. The game is also over if the timer reaches 0.

The encrypted word is among a group of five chosen at random from a list of over 1600 six-letter words. I'm using a list I found at the following web site:

I found this based on the following Google search: "list of words with only 6 letters." As it turns out, people have compiled lists of words with varying lengths (people with time on their hands). This one seemed as good as any, though I have found myself having to remove some questionable words from the list. So far nothing too bad, just those sure to make any normal fifth grader laugh or smirk (e.g. rectum, nudity, dickey, tampon). However, I keep coming across words that are questionable, so I'll definitely need to print out the list at some point and review it carefully. (If you download and play the game, consider the word list appropriate for only those over 18 for now. Better yet, substitute your own word list instead.)

The game uses all of the scripts discussed in my previous posts, though of course I had to add lots more coding to create the game. There are far too many to go into any great detail here, but I will discuss a few. First, here is a screen snapshot of the game, along with the LiveCode file. I've also exported the game for both Macintosh and Windows for those of you who don't have LiveCode but who might want to play game:

I'm debating whether I'll do any more development on this little game. I think I'll share it with a few people to see if they find it enjoyable (or maybe hear from some of you reading this posting). If I get some positive vibes about it, I may be motivated to go further. One obvious enhancement would be to store the high score to give the player something to shoot for. Another obvious enhancement would be to let people update or change the word list. When I taught fifth grade, my students were confronted with learning a weekly list of spelling words, so I think this game would make a fun way to learn the words. (Do fifth graders still have to learn how to spell weekly word lists?)

OK, here are some of the most important programming notes:

First, note that the list of words are stored in a text field called "words" on a separate card (named "data"). I just copied and pasted the word list into the field.

Next, check out the script on the card "game." Yes, there is  lot of code on here, but if you scroll down to the very bottom, you will find the following:

on opencard
   hide button "New Game"
   hide field "bonus letter"
end opencard

So, when the card is first opened, this script takes over. This is actually a nice example of using the "divide and conquer" strategy for programming by creating custom procedures. And, procedures can easily be reused where ever it is appropriate to do so. For example, you will find I use the "newWord" procedure elsewhere to begin a new round within a single game.

The script to create the timer deserves some mention, as it shows a good approach to using time as a game variable. As I mentioned above, in this game you have 20 seconds to choose one of the five words. The quicker you are, the more points you get because the number of seconds remaining is your score for that round. However, the game ends if you choose the wrong word in any round. This 100% accuracy creates a a healthy game "tension," in my opinion -- you want to be quick, but you dare not make a mistake. Here is the script for "computerTime":

on computeTime
   put 20 into varTimeLimit
   if varGameActive is true then
      put the seconds into gVarTimeEnd
      put varTimeLimit-(gVarTimeEnd-gVarTimeStart) into gametime
      put "Time: "&gametime into line 1 of field "display time"
      send "computeTime" to me in 50 milliseconds
      if gametime<= 0 then TimeUp
   end if
end computeTime

Line 2 makes 20 seconds the time limit to choose a letter. If the clock gets to 0, another procedure I created -- "TimeUp" -- is triggered in line 8.

The global variable "varGameActive" is either true or false. The clock is only running when true.

Line 4 puts the current time, in seconds, into the variable "gVarTimeEnd." ("Seconds" is actually a system variable that contains this information.) There is a similar line of code with the variable gVarTimeStart that is executed near the start of the procedure "newWord." So, line 5 subtracts gVarTimeStart from gVarTimeEnd to determine the number of seconds that have transpired. However, since we want the game action to feature a time that counts down from 20, we have to subtract that number from varTimeLimit.

Now, the timer has to be running continuously as it shows the player how much time is remaining, so we need to put this procedure in a loop that never ends so long as varGameActive is true. So, notice line 7:

send "computeTime" to me in 50 milliseconds

This line probably looks a little odd, but you will see this construction often in LiveCode, so it's a good idea to get comfortable with it. It's also quite powerful. Anytime you see the word "me," LiveCode is referring to the particular object within which the line of code is located. It could be a button, a procedure, a card, etc. -- any of the LiveCode objects. This is a handy and quick way to refer to the object you are working on without having to name it explicitly. "Me" is a relative term that LiveCode understands. In this case, "me" refers to the procedure "computerTime."  50 milliseconds is obviously not a long time. Basically, this line just says "Wait just a moment, then come back to me." Why 50 milliseconds, and not say 10, 70, or 100? I'm not sure. I saw this line of code in another example on the RunRev web site, so I adopted it. (Perhaps I, or you, will play around with this at some point.)

(You might be wondering why I named these variables with a "g" in front, seemingly breaking from my naming convention. Well, I had first written this code for another game, and I was using the convention of putting the lower case g in front of all global variables. I've stopped doing that in more recent projects, but because I was copying and pasting, I just decided to leave the variable names as they were.)

Let's turn our attention to the procedure "newWord." This procedure chooses five random words are chosen from the list.  As mentioned above, the words are stored in a field called "words" on a separate card (named "data"). Here is part of the scripting convention for choosing the five random words:

   put random (the number of lines in field "words" on card "data") into x
   put line x of field "words" on card "data" into varWord1
   repeat forever
      put random (the number of lines in field "words" on card "data") into x
      put line x of field "words" on card "data" into varWord2
      if varWord2 <> varWord1 then exit repeat
   end repeat

Line 1 first counts the number of lines in field "words" and puts that number into x. As simple as this is, it is very important because you can substitute any list of words you want without worrying about how many there are. There are about 1600 in the list now, but you could pare this down to just 5 if you wanted to (of course, the same five words would then be chosen each time, making for a pretty boring game). And no, I don't know the limit as to the number of words (i.e. lines) that can hold data in any single text field (I should look that up). Line 2 puts that random word in the variable "varWord1".

Next, there are four groups of code that use the "repeat forever" command, one each for the remaining variables holding the words chosen at random (e.g. varWord2, varWord3, varWord4, varWord5). Lines 4 and 5 basically repeat lines 1 and 2, substituting varWord2 for varWord1. Line 6 is the key. It repeats the loop forever until varWord1 and varWord2 are different words. In a list of 1600 words, this shouldn't take long.

So, by the time I get to choosing varWord5, line 6 looks like this:

if varWord5 <> varWord1 and varWord5 <> varWord2 and varWord5 <> varWord3 and varWord5 <> varWord2 then exit repeat

I'm simply comparing varWord5 with the other four words already chosen with the computer repeat the loop until a unique word has been found.

You might recall from an earlier post that I shunned this strategy for choosing unique elements in a list because it might take the computer a long time if the list was very small. In an earlier post I had shown a clever strategy for making sure that a unique element would be chosen at each random number. Given that I have over 1600 words, I figured this was not necessary, plus I was wanting to try something new. So, what happens if you pare the list down from 1600 words to just, say, 6? Well, I tried doing and the performance was excellent -- no noticeable lag. As Mr. Spock would say, "Interesting."

There is lots more to write about, and I may do so in later posts, but let me end on the topic of sound effects. In short, I think they are extremely important. Because time is of the essence, the sound effects give you all the feedback you need to know if you have or have not been successful. But what if you have a hearing impairment and can't hear the sounds. The game just continues to the next word if you are successful versus providing the player with feedback if they are not. Still, it would be worthwhile to explore providing some kind of visual feedback -- perhaps a screen flicker -- if the guess is correct.

Play the game and let me know if even this primitive draft is any fun.

1 comment:

  1. That is why it is so important to use only proven software, especially if it is used in our daily work. I praise IT solutions for business from because I am sure that such native applications work very stable.