Welcome to the fourth entry in the Intermediate ColdFusion Contest. The earlier entries may be found at the end of this post. Today's entry is from Uipko Berghuis. Before reading on, please check his application here. You can download his code from the download link at the bottom. Please respect the copyright of the creator.
Let's get started. The first thing I noticed about this application was the use of JavaScript prompts for gathering information. I don't know why but I really don't like that. But that's not the end of the world. His other UI choices I like. It is very simple, but it works, although normally I would imagine BANK would be DEALER instead.
The game worked for me until I ran out of money, and then I got 'stuck' and could no longer restart. Even if I removed the URL variables and simply opened up "index.cfm", after the prompts for my name and the logon, the screen would simply say START. I noticed that it seemed to think I only had 0 credits. I began to dig and discovered that as soon as you made a bet that emptied your purse, the game would abort. It was due to this line here:
// Check for url cheaters
variables.newGame = url.bet GT variables.player.iCredits OR url.bet LTE 0;
As the comment says, he was trying to ensure a person wasn't cheating, however, it didn't take into account the case where the player bets it all. If you try to verify this, it is a bit hard to reset the game. You can only reset if the url.action field has a value, and you must add &reset=1.
Another little nit - in stop.cfm, he does:
<cfset session = structClear(session)>
You don't set the result of structClear to the session. Rather, you simply throw away the result:
<cfset structClear(session)>
I see in other files he did this correctly. (FYI, I've never heard of the name Uipko, so if you are a girl, forgive me!)
This solution also made use of CFCs. From what I can see - he makes very good use of the var statement and doesn't seem to forget any. He does do a few questionable things in his CFCs though. First off - he uses the This scope for instance data. This is generally frowned upon and most people will tell you to use the Variables scope and write a get/set method to access the data. He also uses the cfproperty tag. This doesn't do anything except add metadata to the CFC, and is (again, generally) only typically used in web services. I'd normally suggest against both of these techniques. Oh - one more thing about the CFCs. I noticed a few had output="true" where he wasn't really outputting anything. This isn't the end of the word, but will create extra whitespace. (Somewhere... out there.... a poor country is yearning, begging, pleading for whitespace. ColdFusion is there to meet that need!)
So, as before, let me hear what other's think, and you can download the code from the link below. See it, Tony? It's maybe two inches lower. See it? Right there? No, not there Tony, there. (Sorry, that's the last Tony in-joke I'll make. I promise!)
Earlier Entries:
This is the fourth entry. We have eight more to go. My feeling is that I'll get one more done this week, and then four or so next week, with a wrap up in early December, just in time to start the Advanced/Jedi/Guru/Warlord/ThunderTiki/etc contest - just in case you were worried you would be bored over the Christmas holidays. ;)
Archived Comments
I agree with you Ray, the drawback's for me was the javascript prompts and the inability to play another game, other than that nice job!
I was just playing the Entry 4 Blackjack game and had a situation where my, blackjack of 10h, Ad _lost_ to the Dealer's 6h Qh 5c which is also a 21.
I didn't dig deep into the content rules, but I think the player should win this hand instead of losing. I'll spare you all the screen shot, but I hate losing. A push probably wouldn't have upset me enough to write about it either.
On the plus side, the UI looks good. The green background was very casino and well thought out.
All right, I read the rules.
If the computer and the player tie, the computer (dealer) wins.
Booo!
Several times I tried to bet more than 90 'credits' and was unable to. When the cards were dealt, I would click 'Hit' or 'Stay' adn it would kick me back to the 'start' screen. I had to do teh 'reset=1' thing a few times before it would reset.
you said last last time. GRRRRRR
good thing my entry hasnt been graded yet, or id be trollin' hard.... :)
I've had some problems with the UI as well... it seems that every time I'm dealt a hand and click "stay" it takes me back to the START screen. (I haven't tried the manual reset yet though)
I downloaded the code and have a few quick comments:
1) I saw "constructors" called constructor(), create() and init(), although init() seemed very rate. To me this is a big issue: every piece of literature I've read on CFCs recommends using init() as a constructor. Unless there is a very compelling reason otherwise I recommend using init() to be consistent.
2) In deck.cfc getCard() doesn't do anything at all... is this just old code that wasn't deleted?
3) A lot of methods that declare a void returntype end with a "return" statement. I personally don't include return statements unless they are actually returning a variable, to me it looks cleaner and is easier to read. This is mostly an issue of personal style though. (Hasn't Ray mentioned that programmers by nature don't like other programmers' style?)
4) I like the use of CFCs to model different pieces of the game, but I would recommend using getters/setters to better encapsulate implementation details. For example, most of the logic of dealing a card is contained in Player.cfc, NOT in Deck.cfc like I expected. If Deck.cfc is changed to store the cards in a struct instead of an array then Player.cfc will need changed as well. A cleaner implementation would be to have all of the dealing logic contained within the getCard() method of Deck.cfc.
5) It would be cool if the deck could be "shuffled" and returned to its full status without re-initializing the entire object.
6) In index.cfm some variables aren't scoped consistenly. For example, url.action is sometimes just called "action". This makes it hard to tell what variable is being used.
7) The code was generally commented very nicely, I liked how the contest rules were documented in index.cfm
8) I loved the "Wall of Fame" idea. Tres cool.
I got dealt an Ace, An Ace, and a Jack. It said I busted. Shouldn't I be at 12?
I didn't like the JavaScript prompts either.
data in a cfproperty tag shows up in the CFC metadata. From a documentation standpoint, I would consider it a bad practice not to use them.
I simply got this when clicking "hit":
The web site you are accessing has experienced an unexpected error.
Please contact the website administrator.
The following information is meant for the website developer for debugging purposes.
Error Occurred While Processing Request
The element at position 0 cannot be found.
Resources:
* Enable Robust Exception Information to provide greater detail about the source of errors. In the Administrator, click Debugging & Logging > Debugging Settings, and select the Robust Exception Information option.
* Check the ColdFusion documentation to verify that you are using the correct syntax.
* Search the Knowledge Base to find a solution to your problem.
Browser Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12) Gecko/20050915 Firefox/1.0.7
Remote Address 213.132.0.105
Referrer http://ray.camdenfamily.com...
Date/Time 22-Nov-05 03:13 AM
@ray
Your guess was oke I'm a guy, it's a dutch name, but also pretty unknown here in the Netherlands. It's harder than I tought, to read about the bad things in your code. But after counting to ten it went better, and it's a good learning experince. Normaly I only get criticst on the (dis)functionality from the users point of view.
I totally agree with the prompts, I didn't had the time to change thoose things. Design isn't my kind of thing, so I didn't put mutch time into it.
hmmmm, I added the cheaters part at the last day, after my colleageus tried to cheat and succeeded :) So obviously didn't test it to good, sorry.
I don't get it why the this scope is bad, but totally agree that getters and setters would be better. I always tought that it's a no go to use variables scope inside cfc's, isn't it?
The use of cfproperty is just a habbit that comes form the cms I'm working with. The getMetadata was also a easy way to make an generic constructor. About the output=true, prob. just forgot them to put back after debugging :(
@seth
About the init() I din't know, good point will use only init next time. For the rest of the points I only can say "true"
Uipko wrote:
> It's harder than I tought, to read about
> the bad things in your code
LOL, I know exactly what you mean. It was a lot harder than I was expecting too :)
any chance we can get a glimpse of the ninja contest entry criteria? or does that ruin it?
im one impatient mother effer... yeah, i know :)