Posted in ColdFusion | Posted on 03-25-2011 | 3,042 views
Meet Joe. Joe runs a local car wash and is notorious for having an odd smell and being notoriously cheap. So cheap in fact that he pays his employees the littlest possible and therefore has the laziest employees in existence. This causes many problems for Joe as he has to ensure each and every task he gives them is as simple and as direct as possible. No critical thinking allowed here. You're going to write a program for Joe (in exchange for 2 free car washes, except on days that end in Y) to help Joe with a particular problem: Signage.
Joe has one of those signs where you can put messages up one letter at a time. Not one of those fancy electronic ones. Of course not - that would cost too much. No - this is one of those signs where you have to use the 30 foot long hook and place up one letter at a time. This makes changing the message a real pain in the rear. Your program is going to help make this problem easier. Here's the basic idea.
Given a message, your code will:
a) Return each unique letter and the number of instances. This will tell the employee how many As they have to bring, how many Bs, etc.
b) Given a width attribute that represents how many "slots" are available per row. For now, don't worry about the number of rows (it's a tall sign). But assuming that each row is N slots wide, you need to determine which words will fit per row.
So all in all your API is something like this: getSignInfo(message,width) and returns a structure of two complex values - the results detailed in A and B.
So - I actually have a real prize to offer for this. By writing a Blackberry Playbook app (Hangman, I'm going to sell it for free but get rich on volume), I was awarded a copy of ColdFusion Builder and Flash Builder Pro. I'll be selecting the winner from comments posted to the blog entry by 5PM CST. Please note this contest is 100% arbitrary so unabashed flattery is a bonus. Have fun with it. I'd recommend Pastebin for your code samples.


Here's my crack at it: http://pastebin.com/Vfyib49T
http://pastebin.com/XJjR1Htm
http://pastebin.com/8QQXby0H
*joking*
<cffunction name="getSignInfo" returntype="Struct">
<cfargument name="message" type="string" required="true">
<cfargument name="width" type="numeric" required="true">
<cfargument name="includeSpaces" type="boolean" required="false" default="false"/>
<cfargument name="fixWidthIssues" type="boolean" required="false" default="true">
<cfset var signDetails = {}/>
<cfset var adjustedMessage = trim(arguments.message)/>
<cfset var charArr = listtoARray(adjustedMessage,'')/>
<cfset var wordArr = listtoARray(adjustedMessage,' ')/>
<cfset var i = ""/>
<cfset var wordLength = ""/>
<cfset var currentRow = 1/>
<cfset var slotsFilled = 0/>
<!---
Examine each word in the message.
If a word is too long for the width of the sign, we'll add spaces to adjust the message (Basically creating a "word wrap" feature)
Optionally, we can throw an error when this happens.
--->
<cfloop from="1" to="#arraylen(wordArr)#" index="i">
<cfset wordLength = len(wordarr[i])/>
<cfif wordLength gt arguments.width>
<cfif arguments.fixWidthIssues>
<cfset wordArr[i] = left(wordArr[i],arguments.width) & " " & mid(wordArr[i],arguments.width,wordLength)/>
<cfelse>
<cfthrow message="Oh noes! One of your words is too long for the sign!"/>
</cfif>
</cfif>
</cfloop>
<cfset adjustedMessage = arrayToList(wordArr," ")/>
<!--- Loop and count each letter. We can also return the number of spaces if desired --->
<cfset signDetails.letterData = {}/>
<cfloop array="#charArr#" index="i">
<cfif i eq " " && !arguments.includeSpaces>
<cfcontinue/>
</cfif>
<cfif !structkeyexists(signDetails.letterData,i)>
<cfset signDetails.letterData[i] = 0/>
</cfif>
<cfset signDetails.letterData[i] += 1/>
</cfloop>
<cfset signDetails.rowData = {}/>
<cfset signDetails.rowData["row1"] = ""/>
<!--- Let's fill those rows --->
<cfloop list="#adjustedMessage#" index="i" delimiters=" ">
<cfif (wordlength + slotsFilled) gt arguments.width> <!--- No more room, next row please. --->
<cfset currentRow++/>
<cfset signDetails.rowData["row" & currentRow] = ""/>
<cfset slotsFilled = 0/>
</cfif>
<cfset signDetails.rowData["row" & currentRow] &= i/>
<cfset slotsFilled += wordLength/>
<cfif slotsFilled lt arguments.width>
<cfset signDetails.rowData["row" & currentRow] &= " "/> <!--- Add spaces between wods on the same row --->
</cfif>
</cfloop>
<cfreturn signDetails/>
</cffunction>
http://pastebin.com/B2e60KxP
http://pastebin.com/hfPVdGJ0
http://pastebin.com/MmmdA2K3
http://pastebin.com/pE541YL5
You lose 5000 points for using the local scope.
I am used to loosing lots of points for no reason so at least this time there is a reason.
However, Don't be a hater it still works.
Showoff
:-)
http://pastebin.com/4PnGCWCa
You can test it out at: http://edbartram.com/FridayPuzzler/JoesCarWash.cfm...
http://jsfiddle.net/sFXLq/3/
It comes with a test string so you can just click run. I think a little more undistracted time, I could get this running in a lot less LOC.
Wasn't returning anything, fixed http://jsfiddle.net/sFXLq/5/
CF is Java. Your argument is invalid.
Go away.
So... in my opinion - this is a non issue.
http://pastebin.com/NvPjRYi9
M
1) Jeremy Battle - you used this.* to call methods in your CFC. Avoid that. It acts like an outside call in terms of security and will fail if the method is private. Instead of this.foo(), just do foo().
You also missed var scoping X in your loop iterator. Watch out for that. ;)
Also, you init your arrays like this: var tempArray = [""]; Which is interesting - but incorrect. This creates a new array with one item, an empty string. You probably (I assume?) wanted an empty array to start off with: var tempArray=[];
2) All - those who used tag based CFCs, don't forget your output=false.
3) AXL - I like how you didn't do it all in one UDF - but don't like the use of script. If your going to write it mostly in script, go 100%. But that's just my opinion. :)
4) Ed - this is awesome: <cfset structSign.unabashedFlattery = "Ray is awesome!">
5) Drew - thank you for using jsfiddle. I've been hearing about it but haven't seen an example. It's awesome and now I'm going to try it myself. :)
6) Connor - nice nick name on the pastebin. ;) Lack of var scoping though. Ditto MikeG on the cool pastebin nick.
<cfset entries = ["Todd Sharp","Robert Gatti","Robert Gatti","Danny","Joe Bodell","Jeremy Battle","Michael Mongeau","Dave Ferguson sucks at COD","AXL","Ed Bartram","Ed Bartram","Connor Middleton"]>
<cfset picked = randRange(1,arrayLen(entries))>
<cfoutput>Winner(winning)=#entries[picked]#</cfoutput>
And the winner was...
Ok -sorry folks - leaving off the winner WAS intentional and I assumed people would notice and yell but I guess everyone is out. ;)
The winner is... Connor Middleton.
Connor - send me an email and I'll get you instructions on how to get your software.
http://pastebin.com/AJjxb1wq
[Add Comment] [Subscribe to Comments]