Raymond Camden's Blog Rss

ColdFusion Contest Entry Examined - Part 2

19

Posted in ColdFusion | Posted on 10-05-2005 | 4,740 views

Today we are going to look at the second contest entry. What is interesting about this one is that it takes the opposite approach from the first entry. In the first entry, the user had to guess the right number. In this entry, the computer has to guess it. This is what I had originally wanted, but to be honest, either way is fine, so I have no problem with the first entry's approach.

The second entry can be viewed here. Please go take a look at it before reading on. Now that you have looked at it, here is the code.

view plain print about
1<!--Set Default Values -->
2<cfparam name="numhigh" default="100">
3<cfparam name="numlow" default="1">
4<cfparam name="numcurrent" default="0">
5<cfparam name="guess" default="">
6
7<!--- Set Try Counter --->
8<cfparam name="counter" default="-1">
9<cfset counter=counter + 1>
10
11<!-- If guess is HIGH -->
12<cfif guess is 'High'>
13<cfset numhigh=numcurrent>
14</cfif>
15
16<!-- If guess is LOW -->
17<cfif guess is 'Low'>
18<cfset numlow=numcurrent>
19</cfif>
20
21<!--- Generate random number between low and high set points --->
22<cfset oldcurrent = numcurrent>
23<cfset numcurrent= RandRange(numlow, numhigh)>
24<cfloop condition="oldcurrent is numcurrent">
25<cfset numcurrent= RandRange(numlow, numhigh)>
26</cfloop>
27
28
29
30<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
31<html xmlns="http://www.w3.org/1999/xhtml">
32<head>
33<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
34<title>Number Guessing Game</title>
35<style type="text/css">
36<!--
37.style1 {
38    color: #999999;
39    font-family: Arial, Helvetica, sans-serif;
40    font-size: 14px;
41    font-weight: bold;
42    text-decoration: none;
43}
44.style2 {
45    color: #FF0000;
46    font-weight: bold;
47    text-decoration: none;
48}
49.textformat {
50    font-family: Arial, Helvetica, sans-serif;
51    font-size: 14px;
52    text-decoration: none;
53}
54.start {
55    font-family: Arial, Helvetica, sans-serif;
56    font-size: 14px;
57    font-weight: bold;
58    color: #FF0000;
59}
60.guess {
61    font-family: Arial, Helvetica, sans-serif;
62    font-size: 14px;
63    font-weight: bold;
64    color: #0000FF;
65    text-decoration: none;
66}
67.title {
68    font-family: Arial, Helvetica, sans-serif;
69    font-size: 18px;
70    font-weight: normal;
71    color: #000099;
72    text-decoration: none;
73}
74.newgame {
75    font-family: Arial, Helvetica, sans-serif;
76    font-size: 10px;
77    color: #000099;
78}
79-->

80</style>
81</head>
82<body>
83<table width="100%" border="0" class="textformat">
84 <tr>
85 <td align="center"><!--Title area -->
86     <span class="title">Number guessing game</span>
87    </td>
88 </tr>
89 <tr>
90 <td align="center"><!--Title area -->
91     <p>
92    </td>
93 </tr>
94 <tr>
95 <td><!--Data Area -->
96
97
98<cfif guess is ''>
99<table width="100%" border="0" class="textformat">
100 <tr>
101 <td align="center">Welcome to the number guessing game. Please select a number between 1 and 100. Once you have your number selected, please click Start.</td>
102 </tr>
103 <tr>
104 <td align="center"><a href="index.cfm?guess=new" class="start">Start</a></td>
105 </tr>
106</table>
107
108
109
110<cfelse>
111
112
113<cfif guess is 'correct'>
114<table width="100%" border="0" class="textformat">
115 <tr>
116 <td align="center">I guessed your number within <cfoutput>#counter#</cfoutput> tries.</td>
117 </tr>
118 <tr>
119 <td align="center"><a href="index.cfm?guess=new" class="start">Play Again</a></td>
120 </tr>
121</table>
122
123
124
125<cfelse>
126
127
128<cfif numcurrent gte 0>
129
130
131<table width="100%" border="0" cellpadding="0" cellspacing="0" class="textformat">
132 <tr>
133 <td colspan="100" align="center">
134        <cfoutput>
135            My current guess is the number is <span class="style2">#numcurrent#</span>
136            <p> Is this number
137            <cfif numcurrent is numhigh>
138 <span class="style1"> Low</span>
139            <cfelse>
140            <a href="index.cfm?numcurrent=#numcurrent#&numhigh=#numhigh#&numlow=#numlow#&guess=low&counter=#counter#" class="guess">Low</a>
141            </cfif>
142            :
143            <a href="index.cfm?numcurrent=#numcurrent#&numhigh=#numhigh#&numlow=#numlow#&guess=correct&counter=#counter#" class="guess">Correct</a>
144             :
145             <cfif numcurrent is numlow>
146 <span class="style1"> High</span>
147             <cfelse>
148             <a href="index.cfm?numcurrent=#numcurrent#&numhigh=#numhigh#&numlow=#numlow#&guess=high&counter=#counter#" class="guess">High</a>
149             </cfif>
150        </cfoutput>
151    </td>
152 </tr>
153 <tr>
154 <td colspan="100" align="center"><hr /></td>
155 </tr>
156 <tr>
157 <td colspan="100" align="center">Current guess range</td>
158 </tr>
159 <tr>
160 <td colspan="100" align="center">&nbsp;</td>
161 </tr>
162 <tr>
163 <cfloop from="1" to="100" index="numtest" step="1">
164     <cfif numtest gte numlow and numtest lte numhigh>
165        <td width="1%" bgcolor="#00FF00">&nbsp;</td>
166     <cfelse>
167        <td width="1%" bgcolor="#FF0000">&nbsp;</td>
168     </cfif>
169
170 </cfloop>
171 </tr>
172 <cfoutput>
173 <cfset colspannum=100 - numlow>
174 <tr>
175     <td colspan="#numlow#" align="right">#numlow#</td>
176
177     <td colspan="#colspannum#"></td>
178 </tr>
179    <cfset colspannum=100 - numhigh>
180 <tr>
181     <td colspan="#numhigh#" align="right">#numhigh#</td>
182     <td colspan="#colspannum#"></td>
183 </tr>
184 <tr>
185 <td align="center" class="newgame" colspan="100"></td>
186 </tr>
187 <tr>
188 <td align="center" class="newgame" colspan="100"><a href="index.cfm?guess=new" class="newgame">Start new game</a></td>
189 </tr>
190<!--- <tr>
191 <td colspan="100" align="center">Low:#numlow# <br /> High: #numhigh# <br /> Current: #numcurrent# <br /> Counter: #counter#</td>
192 </tr>--->

193 </cfoutput>
194</table>
195
196</cfif>
197</cfif>
198</cfif>
199
200
201
202</td>
203 </tr>
204
205</table>
206</body>
207</html>
208 </span>

So - let's talk about it. The first thing that struct me was the graphical representation of the guesses. I love this. I wasn't concerned about the design of these entries (I'm an 'advanced' programmer but can't design my way out of a paper bag), but this is a simple little thing that I thought was just plain cool. You can actually see the computer narrowing down it's choices. Nice.

Now it's time to get nasty. Like the first entry, this entry does not make use of RAM based variables in order to store information. All information is passed via URL parameters. One problem I have with the code is that he does not use the URL scope. This isn't a bug per se, but it is generally accepted as best practice to specify the scope. (Note my comments from the first entry.) The fact that he uses URL variables also makes them easy to change. One of the first things I did was change a URL variable, numhigh, to an invalid value ("apple"), and the application broke. This is a typical mistake for beginner programmers, and is something I covered in my Macrochat. You must perform validation before working with any variables from an outside source. In this case, he could have used isNumeric, and then check for integer (don't forget that 3.14159 is a number), and lastly check to ensure it was between one and a hundred. Similar validation must be added to all the URL variables he used. I was actually able to get the application to go into an infinite loop by playing with the URL values. (I modified the code on the live version so this wouldn't happen - hopefully.) This is one more reason why using the full scope would help. It gives you a visual cue that the variable is a URL value and cannot be trusted.

One thing I liked about his entry was how he guessed a new number. This is not the best way. The best way, as far as I know, is to make guesses exactly in the middle. I.e., first guess 50, and if too low, then 75, etc. However, his randomized guess is more fun. One of the issues game designers run into is "dumbing down" the computer. If they didn't do this, the computer would either win every time, or perform the exact same actions every time. I don't know if this was the author's intention, but I'm going to assume it was.

In general, I don't have much else to say. I'm not happy with his formatting, but I've yet to find two developers who would actually agree on the same code formatting style (unless they have no choice). Does anyone else have a comment? (And remember, be nice!)

Comments

[Add Comment] [Subscribe to Comments]

I was able to get it to loop infinitely just by repeatedly pressing low then high. Obviously this assumes someone isn't playing the game honestly, but I would think it should know that if the choices have been narrowed to two numbers and one I state is high, that it has to be the other...and end there. I do like the graphical representation as well, but I was struck by the same thing as you, that it worked off random guesses rather than by halving the options.
When you say struck, you mean that in a good way, right? Just checking because it sounds negative, and I definitely meant my comment as praise. :)
Maybe a better word choice would have been surprised since it wasn't really positive or negative on my end. It just had not occurred to me to solve it that way as it isn't the quickest means of getting the answer. However, your contest entry never stated this as a requirement, so it was really a matter of my reading things into the requirements (which can be a bad habit).
Cool. As it stands, my rules are always a bit flexible. ;) The first enty did things the opposite way, but I'm still happy with it.
i like the randomness of the guesses. Makes you feel like the computer is interacting with you rather than going about it in a cold "logical" way.

As for the fact that two contestants haven't really used the session scope it might be because of the parameters you setup for them early on. You told them there was to be no setup involved. just unzip and run. Well one could NOT assume then that you had sessions turned on, or that the files would be unzipped into a proper folder for a application.cfm file could be used.

just playing devils advocate here for the sake of the contestants :)
I did encounter one thing that I considered a problem. I picked the number 49. As it narrowed down it actually guessed 48, then 50, then back to 48, then 50 again, before it finally figured out that 49 was the number.

I haven'te really looked too close at the code but I'm guessing it would need to track the previous two guesses and not allow them as new guesses.
Thank you for the feedback and will defiantly remember what you said about the passing info in the URL. I felt using the random number would give a better feeling about the computer actually trying. The display of the guesses also aid in this. Rick, the code just checks the last number, otherwise it’s totally random.

-Chris
Same problem as Rick. When the computer guesses 48, and you say it is too low, it appears that it doesn't rule 48 out from being guessed again, but only rules out the numbers below 48.

Looking at the code this bug is confirmed.

I too like the visual bar.
"I guessed your number within 17 tries."

I think there is a algorithm problem. :)
Oguz, why do you say that?
I just tried second entry and it could found on 17th try. I think there would be a better algorithm to solve this problem. As I guess max. ~ 8-9 try must be enough.
Ah, I think you missed my comments. I pointed out that this is NOT the most effecient way of finding the answer, but it is -better- since it makes a more enjoyable game.
Ok. I just have seen this part. :)

I have to say that I am a computer engineer and have had lots of data structures lessons and bored enough. Sorry this one was just a quick reply from an engineer perspective. :)
Hi Ray. I never submitted my code for your contest, but I really enjoy the post mortem's! I actually started coding something like your first entry, and later read the spec more finely. All-in-all, from reading the spec to actually coding something, I really learned a lot from this. thanks, and I hope you post another contest soon.
A couple of things are bugging me...
The first being that the code is not XHTML 1.0 Transitional, despite what the header claims. (But at least it uses a header, and isn't HTML4)
The second thing bugging me is the use a big messy table when it is not needed. The guessing range is a nice touch, but a more elegant way would have been to simply use three SPANs with an appropriate width value set.
"Now it's time to get nasty. Like the first entry, this entry does not make use of RAM based variables in order to store information. All information is passed via URL parameters."

What's so wrong with URL control parameters as long as you validate that you are actually getting what you expect and that the user is allowed to see what they have asked for?

In terms of Portlets (well the ones that we develop), this is usually one of the only ways possible to pass control parameters about. We could not do it with RAM based vars.
dc - I think you are misreading me. I didn't say the use of URL vars is bad, in fact, after you stop quoting me, I go on to say I'm compling about his lack of use of the _scope_ URL in naming his variable. i.e., url.x, not just x. I then go on to say he didn't validate his url variables. I don't believe I said the use of url variables alone was bad.
sorry Ray, I get it now, you are saying that he _doesn't_ use RAM based variables so that means that he needs to scope and validate.

sorry for the confusion, guess I shouldn't flash read things and then comment on them :)
Your right. You shouldn't do that. Because I never do. Um. Really. Wow that's a big bolt of lightning...

[Add Comment] [Subscribe to Comments]