In preparation for working on the Kanji section of the NNB Tools, I decided to revisit the Kana Match game and touch up a few things I'd left undone initially.
The two main points I'd meant to address were the countdown timer and a scoring multiplier.
The countdown timer was the main one I wanted to tackle, since the way I'd left it resulted in almost no real increase in difficulty on the timer for the first 20+ levels, and then around level 26 it would start becoming noticeably more challenging at it got faster, and by level 30 there was no chance of you not running out of time.
This was because the original algorithm just cumulatively subtracted the level number from the timer value.
kanatimer = kanatimer - levelnumber
So, for instance, 100 -1 = 99, 99 -2 = 97, 97 -3 = 94, 94 -4 = 90, etc... until the timer ran out. I graphed this out on paper to get a visual of what it looked like;
and Dustin Quigley helped me get a "real" graph of it in Wolfram Alpha.
So I decided to sketch out my idea of how I'd like the timer to actually operate and then try to figure out a way to program it. Given that I'm quite math challenged, I just decided to try breaking it down into a form I could work with. So initially I graphed it and looked at how it changed over time... and I noticed that the amount of time left essentially halved every 10 levels. I figured that I could write a little function to decrease the count by 5 for the first 10 levels, then 2.5 for the next 10, 1.25 for the next 10 etc... to give myself the asymptote to 0 type "long tail" I wanted.
Then I decided to ask around for advice on how to perhaps more easily and "correctly" achieve this through some simple mathematical equation. Thankfully I have a number of friends who are sheer geniuses at math compared to myself. ;)
First Mike Dejonge started walking me through the different pieces of the equation for an exponential decay so that I could understand what each part did, while at the same time Michael Katsevman was showing me a Wolfram Alpha graph of what it would actually look like (using a negative exponent). Dustin Quigley was giving me a variation on that using a positive, but less than 1, number that made it a little easier to see what was going on.
Their advice and graphs were precisely what I had in mind! So I went ahead and implemented it and it worked perfectly!
timer = 500 * 0.95e^level
Now instead of any reasonably skilled users all hitting game over within a few levels of each other with little difference in score, now one could have much more "wiggle room" to eek out a considerably bigger score by managing to hold on longer as the timer was more slowly whittled away toward the end.
Whereas before I would essentially always hit game over between levels 28 and 30 or so... now I might eeek it out until level 37 on a more challenging setting, or level 42 with less challenging settings (easier kana etc).
Thus my first hurdle was finally overcome with all their help. Thanks guys!
Then I moved on to the scoring multiplier. This one was thankfully a little more in my league. ;)
What I had in mind was a way to offset the loss in points a user would get when playing with more of the kana, the more "difficult" ones, selected... since this would most likely mean they would lose the game sooner. So I wanted to find a way to give them a scoring bonus depending on how many of the 4 options they selected, and which ones (from easier to harder).
First I wanted to get an idea what size multiplier I'd want to use. So I rather unscientifically compared my score on an "easy" game (Level: 42 Score: 20962) with my score on a "hard" game (Level: 37 Score: 18607) and did a little basic math to see that very rough 1.2x multiplier would make up the lost points and give a slight score bonus for playing the more difficult option. After sketching ideas in my notebook for awhile, I ended up with a rough approximation to work with;
- 1x base multiplier.
- 0.033 for 2 options checked, 0.066 for 3 options, and 0.1 for all 4 options checked.
- 0 bonus for only the basic unvoiced kana, 0.010 for the basic voiced, 0.034 for the compound unvoiced, and 0.056 for the compound voiced.
This would be added up to arrive at your score multiplier, with more of a bonus granted to the more difficult options... and a maximum 1.2x multiplier.
This was applied to each match (10 points x multiplier), and to the remaining time bonus (500 - amount of time used x multiplier) which was added to your score at the end of each level. This seemed to work out well enough for what I wanted. :)
Also, in the process of working that out, since I used floating point numbers for everything short of the actual score display (which was trimmed down to an integer), I noticed what I thought was a "bug" in the math... since when I selected 3 or 4 options, I'd suddenly go from 3 decimal places to 16 decimal places with an odd 1 or 2 way out there by itself in the 16th decimal place.
Carlos Torres was kind enough to point out the reason for this to me. :)
In short, my novice level programming skills and utter dearth of mathematics education had bitten me in the rear once again. ;) I decided to simply round the number to a fixed 3 decimal places for my own peace of mind, even though it really had no bearing on the actual scoring in practice.
Aside from that I did a few other minor tweaks... I tried to improve the coloring on the selected cells in the game itself to make them a little easier to see and a little better looking; tweaked the description color; made the side bar "start a new game" button only show up if a game was in progress; improved the code for the options list to space it out better and allow clicking on the labels as well as the checkboxes; and finally, I changed the code in a crazy way to precache the images for the Pause, Level Finish, and Time Up screens.
This last point was definitely a first for me. I decided to use a method where you base64 encode the image data and include it directly in the style sheet! While this increased my style sheet size up to 120kB, it allows the images to load instantly when you hit those screens since the image data was already loaded as part of the CSS on initial page load. It seems to work exactly like I'd wanted, so that's how it is for now. :)
There are still a few other things I might like to try, such as the new html5 history manipulation options and some AJAX loading of data on initial page load so that I can do the redirecting without actually triggering a full page reload... but that will have to wait until I get some more "real work" done to pay the bills. ;) Have to keep a roof over my head!
I can't wait to get things polished up with the basic NNB Tools code so that I'm ready to tackle the larger challenge of the Kanji Tools!
じゃ、またね~ ^^/