Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at cf.Objective() 2011 (Minneapolis, MN) with:

Using Contextual SMS Short Code Messages With TextMarks And ColdFusion

By Ben Nadel on
Tags: ColdFusion

Yesterday, I explored the free SMS short code and web integration functionality provided by TextMarks. As I demonstrated, TextMarks acts as a proxy between cellular users and your web-based application. Because TextMarks uses a single, shared SMS short code, routing to your particular web-based application has to be done through a keyword which must be the leading piece of data in each TextMarks SMS request. The use of this routing keyword can be quite cumbersome; so, to alleviate this requirement, TextMarks provides "contextual responses".

When a user makes an SMS request using your keyword, that keyword takes over that user's context. Once the context is set, the user can then make subsequent requests without your routing keyword and TextMarks will assume your keyword based on the existing context. The huge caveat here, however, is that the subsequent requests must contain a minimal amount of data like a single digit or a character or a zip code. While this might seem silly, it's the only way to make sure that a subsequent request and a new routing directive are not confused.

NOTE: The most critical shortcoming of TextMarks' contextual response limitations is that the response, "Y" is not valid. If you want to use a single character response, you can only use characters "A" through "T". This removes the ability to do the most basic, most intuitive (Y)Yes / (N)No responses. As such, I had to fall back on the numerical digits 1/0 rather that Y/N to represent yes and no responses.

To explore this functionality, I came up with a very basic proof of concept: Blackjack. In the card game, Blackjack, the user must Hit or Stand in an attempt to get as close to 21 as possible without going bust. Once the cards are dealt, the user must make subsequent SMS requests back to TextMarks to submit his or her choice. Rather than sending the keyword "blackjack" with each subsequent request, TextMarks allows the user to use simple, one-digit responses to leverage the current context.

 
 
 
 
 
 
 
 
 
 

Before we get into the code, I just want to make it clear that this is a proof of concept and is not meant to be the most well designed web application.

Because a cell phone does not pass any cookies across with its SMS messages, session management takes on a different paradigm. Rather than letting ColdFusion manage the sessions implicitly, we are going to be creating and caching sessions explicitly in the Application scope. The unique ID used for the session caching and retrieval is passed into our web-application by TextMarks as part of our URL configuration.

Application.cfc

  • <cfcomponent
  • output="false"
  • hint="I define the application settings and event handlers.">
  •  
  • <!--- Define the application. --->
  • <cfset this.name = hash( getCurrentTemplatePath() ) />
  • <cfset this.applicationTimeout = createTimeSpan( 0, 1, 0, 0 ) />
  •  
  • <!--- Define page request settings. --->
  • <cfsetting showdebugoutput="false" />
  •  
  •  
  • <cffunction
  • name="onApplicationStart"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I initialize the application.">
  •  
  • <!---
  • Create a struct to hold the active sessions. We will
  • need this since there is no way for the cell phone to
  • maintain session accross the API requests.
  • --->
  • <cfset application.phoneSessions = {} />
  •  
  • <!---
  • Create a constant array of the cards in our deck
  • so that we can always duplicate it when we need
  • a new deck.
  • --->
  • <cfset application.newCardDeck = listToArray(
  • repeatString( "A,K,Q,J,10,9,8,7,6,5,4,3,2,", 4 )
  • ) />
  •  
  • <!--- Return true so the request is processed. --->
  • <cfreturn true />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="onRequestStart"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I initialize the request.">
  •  
  • <!---
  • Check to see if we are manually resetting the
  • application (for debugging purposes).
  • --->
  • <cfif structKeyExists( url, "reset" )>
  •  
  • <!--- Manually initialize the application. --->
  • <cfset this.onApplicationStart() />
  •  
  • </cfif>
  •  
  • <!--- Return true so the request is processed. --->
  • <cfreturn true />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="onRequest"
  • access="public"
  • returntype="void"
  • output="true"
  • hint="I execute a rendering template.">
  •  
  • <!--- Include the UDF library. --->
  • <cfinclude template="./udf.cfm" />
  •  
  • <!---
  • No matter what page was requested, just include our
  • front controller.
  • --->
  • <cfinclude template="./index.cfm" />
  •  
  • <!--- Return out. --->
  • <cfreturn />
  • </cffunction>
  •  
  • </cfcomponent>

As you can see, the Application scope has a cache for our phone sessions (our explicit session management) and a fresh deck of cards. The deck of cards is represented by an array of 52 items - 4 sets of suitless cards. I'm keeping a deck of cards in the application scope so that I can easily duplicate it later when I need a fresh deck.

The bulk of the processing happens in the front-controller, index.cfm. When a user interacts with the Blackjack application, there are essentially two phases that any game can be in: New, in which the cards are dealt or Active, in which the user is making Hit / Stand decisions. Once a game is over (a winner is selected), any subsequent request to the Blackjack application deals a new hand in the user's session.

Index.cfm

  • <!---
  • Param the request data. In TextMarks, we are going to
  • set up "smsdata" to contain the "\0" data, which is the
  • entire request made by the user.
  • --->
  • <cfparam name="url.smsdata" type="string" default="" />
  •  
  • <!---
  • This is the unique ID of the cell phone making the request.
  • This ID is supplied by TextMarks and is garanteed to be a
  • unique numeric value.
  • --->
  • <cfparam name="url.uid" type="numeric" default="0" />
  •  
  • <!---
  • This is the phone number of the user placeing the request.
  • We don't really need it for this, but I just wanted to see
  • how the number came across in the demo.
  • --->
  • <cfparam name="url.number" type="string" default="" />
  •  
  •  
  • <!---
  • Check to see if this SMS user already has an active session
  • in the application cache. If so, we need to grab it. If not,
  • then we will need to create a new one.
  • --->
  • <cfif structKeyExists( application.phoneSessions, url.uid )>
  •  
  • <!--- Grab the cached user session. --->
  • <cfset phoneSession = application.phoneSessions[ url.uid ] />
  •  
  • <cfelse>
  •  
  • <!---
  • Create a new user session for this cell user. This will
  • contain information about the current game.
  • --->
  • <cfset phoneSession = {
  • cardDeck = [],
  • userHand = [],
  • dealerHand = [],
  • gameStatus = "",
  • previousResponse = ""
  • } />
  •  
  • <!--- Cache the user session. --->
  • <cfset application.phoneSessions[ url.uid ] = phoneSession />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • ASSERT: At this point, no matter whether a cell user made
  • their first SMS request or a subsequent request, we now have
  • a valid phone session variable.
  • --->
  •  
  •  
  •  
  • <!---
  • Check to see if we need to take action on the current game
  • based on it's status.
  •  
  • NOTE: We are doing this if the game is fresh or if it is
  • over. Therefore, we will never truly have a valid "over"
  • state in the proceeding logic (seeing as the status will
  • be switched over to "new" right now).
  • --->
  • <cfif (
  • (phoneSession.gameStatus eq "") ||
  • (phoneSession.gameStatus eq "over")
  • )>
  •  
  • <!--- Reset the game status. --->
  • <cfset phoneSession.gameStatus = "new" />
  •  
  • <!--- Reset the player hands. --->
  • <cfset phoneSession.userHand = [] />
  • <cfset phoneSession.dealerHand = [] />
  •  
  • <!--- Create a new deck of cards. --->
  • <cfset phoneSession.cardDeck = duplicate(
  • application.newCardDeck
  • ) />
  •  
  • <!--- Shuffle the cards. --->
  • <cfset createObject( "java", "java.util.Collections" ).shuffle(
  • phoneSession.cardDeck
  • ) />
  •  
  • <!--- Clear the previous response. --->
  • <cfset phoneSession.previousResponse = "" />
  •  
  • </cfif>
  •  
  •  
  •  
  • <!---
  • Now that we have the SMS data, let's break it up into
  • an array so that we can start to treat it like actions.
  • --->
  • <cfset tokens = listToArray( trim( url.smsdata ), " ,*-" ) />
  •  
  •  
  • <!---
  • Wrap the processing in a try/catch so if something does
  • go wrong, we can catch it and return a response.
  • --->
  • <cftry>
  •  
  • <!---
  • Only certain tokens will be available in certain phases
  • of the game. Therefore, we will break this down by game
  • status before we check token.
  •  
  • NOTE: We never check for the status of "OVER" as this is
  • not really a valid status. Any game with status "over"
  • will be updated above and converted to "NEW".
  • --->
  • <cfswitch expression="#phoneSession.gameStatus#">
  •  
  • <cfcase value="new">
  •  
  • <!--- Deal two cards to the user. --->
  • <cfset phoneSession.userHand[ 1 ] = phoneSession.cardDeck[ 1 ] />
  • <cfset phoneSession.userHand[ 2 ] = phoneSession.cardDeck[ 2 ] />
  •  
  • <!--- Deal two cards to the dealer. --->
  • <cfset phoneSession.dealerHand[ 1 ] = phoneSession.cardDeck[ 3 ] />
  • <cfset phoneSession.dealerHand[ 2 ] = phoneSession.cardDeck[ 4 ] />
  •  
  • <!--- Remove top four cards. --->
  • <cfset arrayDeleteAt( phoneSession.cardDeck, 1 ) />
  • <cfset arrayDeleteAt( phoneSession.cardDeck, 1 ) />
  • <cfset arrayDeleteAt( phoneSession.cardDeck, 1 ) />
  • <cfset arrayDeleteAt( phoneSession.cardDeck, 1 ) />
  •  
  • <!--- Update the status of the game. --->
  • <cfset phoneSession.gameStatus = "active" />
  •  
  • <!--- Build the response. --->
  • <cfsavecontent variable="responseData">
  • <cfoutput>
  •  
  • Dealer: ---<br />
  • #phoneSession.dealerHand[ 1 ]# *<br />
  • .<br />
  • You: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.userHand#"
  • >#card# </cfloop
  • ><br />
  • .<br />
  • Hit? (1=Y/0=N)
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • </cfcase>
  •  
  •  
  • <!--- ---------------------------------------------- --->
  • <!--- ---------------------------------------------- --->
  •  
  •  
  • <cfcase value="active">
  •  
  • <!---
  • Check to see how the user responded to the
  • request to HIT. They could only respond with "1"
  • (yes) or "0" (no).
  •  
  • Param the value such that if it is not met, it
  • will throw an exception - we'll let the exception
  • handling just repopulate the current screen.
  • --->
  • <cfparam
  • name="tokens[ 1 ]"
  • type="regex"
  • pattern="(1|0)"
  • />
  •  
  • <!--- Check to see if the user wants to hit. --->
  • <cfif (tokens[ 1 ] eq 1)>
  •  
  • <!--- User wants to hit. --->
  •  
  • <!--- Grab the next card off the deck. --->
  • <cfset arrayAppend(
  • phoneSession.userHand,
  • phoneSession.cardDeck[ 1 ]
  • ) />
  •  
  • <!---
  • Delete the card from the deck so that it
  • cannot be used on subsequent hits.
  • --->
  • <cfset arrayDeleteAt( phoneSession.cardDeck, 1 ) />
  •  
  • <!---
  • Now that the user has taken another card,
  • let's check to see if the user is bust (hand
  • is over 21). If so, then the game is over.
  • --->
  • <cfif !isHandBust( phoneSession.userHand )>
  •  
  • <!---
  • The user hand is valid. They can still
  • go again. Present the current cards and
  • the choice to go again.
  • --->
  • <cfsavecontent variable="responseData">
  • <cfoutput>
  •  
  • Dealer: ---<br />
  • #phoneSession.dealerHand[ 1 ]# *<br />
  • .<br />
  • You: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.userHand#"
  • >#card# </cfloop
  • ><br />
  • .<br />
  • Hit? (1=Y/0=N)
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • <cfelse>
  •  
  • <!---
  • The user busted; update the status of the
  • game to be over (this will trigger a new
  • game on the next request).
  • --->
  • <cfset phoneSession.gameStatus = "over" />
  •  
  • <!---
  • The user hand is bust. Display the game
  • over screen and allow user to start a
  • new game.
  • --->
  • <cfsavecontent variable="responseData">
  • <cfoutput>
  •  
  • Dealer: ---<br />
  • #phoneSession.dealerHand[ 1 ]# *<br />
  • .<br />
  • You: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.userHand#"
  • >#card# </cfloop
  • ><br />
  • BUSTED!! (#getHandTotal( phoneSession.userHand )#)<br />
  • .<br />
  • Play Again? (1=Y/0=N)
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • </cfif>
  •  
  • <cfelse>
  •  
  • <!---
  • The user wants to "Stand". Now, no matter what
  • the outcome, the game is over - update the
  • status of the game to "over". This will trigger
  • a new game on the next request.
  • --->
  • <cfset phoneSession.gameStatus = "over" />
  •  
  • <!---
  • User wants to stand. Now, it's the dealer's
  • turn to go. The dealer has to keep taking
  • cards until they are over a sum of 17.
  • --->
  • <cfloop
  • condition="dealerMustHit( phoneSession.dealerHand )">
  •  
  • <!--- Grab the next card off the deck. --->
  • <cfset arrayAppend(
  • phoneSession.dealerHand,
  • phoneSession.cardDeck[ 1 ]
  • ) />
  •  
  • <!---
  • Delete the card from the deck so that it
  • cannot be used on subsequent hits.
  • --->
  • <cfset arrayDeleteAt(
  • phoneSession.cardDeck,
  • 1
  • ) />
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Now that we have populated the dealer's hand,
  • let's check to see if it is bust.
  • --->
  • <cfif isHandBust( phoneSession.dealerHand )>
  •  
  • <!---
  • The dealer hand is bust. Display the game
  • over screen and allow user to start a
  • new game.
  • --->
  • <cfsavecontent variable="responseData">
  • <cfoutput>
  •  
  • Dealer: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.dealerHand#"
  • >#card# </cfloop
  • ><br />
  • BUSTED!! (#getHandTotal( phoneSession.dealerHand )#)<br />
  • .<br />
  • You: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.userHand#"
  • >#card# </cfloop
  • ><br />
  • .<br />
  • Play Again? (1=Y/0=N)
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • <!---
  • If the dealer is not bust, check to see if
  • their hand is greater than the user's hand.
  • --->
  • <cfelseif (getHandTotal( phoneSession.dealerHand ) gte getHandTotal( phoneSession.userHand ))>
  •  
  • <!--- Dealer wins! --->
  • <cfsavecontent variable="responseData">
  • <cfoutput>
  •  
  • Dealer: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.dealerHand#"
  • >#card# </cfloop
  • ><br />
  • WINNER!!<br />
  • .<br />
  • You: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.userHand#"
  • >#card# </cfloop
  • ><br />
  • .<br />
  • Play Again? (1=Y/0=N)
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • <!---
  • If the dealer is not bust and the dealer's
  • hand is not as good as the user's hand then
  • the user has won.
  • --->
  • <cfelse>
  •  
  • <!--- User wins! --->
  • <cfsavecontent variable="responseData">
  • <cfoutput>
  •  
  • Dealer: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.dealerHand#"
  • >#card# </cfloop
  • ><br />
  • .<br />
  • You: ---<br />
  • <cfloop
  • index="card"
  • array="#phoneSession.userHand#"
  • >#card# </cfloop
  • ><br />
  • WINNER!!<br />
  • .<br />
  • Play Again? (1=Y/0=N)
  •  
  • </cfoutput>
  • </cfsavecontent>
  •  
  • </cfif>
  •  
  • </cfif>
  •  
  • </cfcase>
  •  
  • </cfswitch>
  •  
  •  
  • <!--- Catch any exception. --->
  • <cfcatch>

  • <!---
  • Check to see if we have a previous output we
  • could try resending.
  • --->
  • <cfif len( phoneSession.previousResponse )>
  •  
  • <!---
  • Use the previous response as the current
  • response. This way, they may have a chance
  • to recheck their inputs.
  • --->
  • <cfset responseData = phoneSession.previousResponse />
  •  
  • <cfelse>
  •  
  • <!--- An error occurred. Alert the user and. --->
  • <cfsavecontent variable="responseData">
  •  
  • Ooops<br />
  • An error occurred.<br />
  • Check your inputs.<br />
  •  
  • </cfsavecontent>
  •  
  • </cfif>
  •  
  • </cfcatch>
  •  
  • </cftry>
  •  
  •  
  • <!---
  • Store the current response into the previous output
  • variable. This way, if something goes wrong, we can
  • return the previous screen.
  • --->
  • <cfset phoneSession.previousResponse = responseData />
  •  
  •  
  • <!---
  • At this point, we should have a valid response in our
  • respondData variable. Now, we need to clean it up for
  • SMS response. Let strip out the extra white space,
  • including the leading / trailing line spaces.
  •  
  • NOTE: TextMarks will automatically take care of stripping
  • out our <BR /> tags and replacing them with text-valid
  • line breaks.
  • --->
  • <cfset responseData = reReplace(
  • trim( responseData ),
  • "(?m)(^[ \t]+|[ \t]+$)",
  • "",
  • "all"
  • ) />
  •  
  •  
  • <!---
  • Convert the respond data into a binary variable so that we
  • can easily stream it back using CFContent without having to
  • be fanatical about clearing the content buffer.
  • --->
  • <cfset binaryResponse = toBinary( toBase64( responseData ) ) />
  •  
  • <!--- Set headers. --->
  • <cfheader
  • name="content-length"
  • value="#arrayLen( binaryResponse )#"
  • />
  •  
  • <!---
  • Stream content back as HTML. By using the Variable
  • attribute, we are ensuring that no extra white space is
  • being passed back.
  • --->
  • <cfcontent
  • type="text/html"
  • variable="#binaryResponse#"
  • />

Because cell phone SMS requests do not pass cookies, I am manually managing the sessions based on the unique phone ID passed in from TextMarks. The first thing I do in the request is check to see if the current user already has an active session. If they do, I get a reference to it; if they do not, I create one and then cache if for subsequent requests. Once this is done, the rest of the page logic can refer to the current user's "phoneSession" which will be persisted from request to request.

The rest of the code is fairly top-down self-explanatory. Each game gets a new deck of cards, which is duplicated from the application-cached deck and then shuffled. As each user hits, a card is popped off of the deck and added to the given hand such that it cannot be used in subsequent hits.

The code above makes use of a user-defined function library which is included right before the front-controller. This library has some utility methods used to help count the sum of each hand and determine if the hand is bust.

UDF.cfm

  • <cffunction
  • name="dealerMustHit"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I determine if the given dealer hand must hit (less than 17).">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="hand"
  • type="array"
  • required="true"
  • hint="I am the dealer hand being checked for hit requirement."
  • />
  •  
  • <!--- Return true if the hand sum is less than 17. --->
  • <cfreturn (getHandTotal( arguments.hand ) lt 17) />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="getHandTotal"
  • access="public"
  • returntype="numeric"
  • output="false"
  • hint="I get the total sum of the cards in the given blackjack hand.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="hand"
  • type="array"
  • required="true"
  • hint="I am the blackjack hand being counted (summed)."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var local = {} />
  •  
  • <!--- Create a running total for the cards. --->
  • <cfset local.sum = 0 />
  •  
  • <!---
  • Loop over cards to get the initial count. On the first
  • pass, the Aces (A) will be counted as 11. If the hand
  • is bust, they will be re-tallied with Ace being 2.
  • --->
  • <cfloop
  • index="local.card"
  • array="#arguments.hand#">
  •  
  • <!--- Check to see what kind of card we have. --->
  • <cfif isNumeric( local.card )>
  •  
  • <!--- Simply add given value. --->
  • <cfset local.sum += local.card />
  •  
  • <cfelseif (toString( local.card ) eq "A")>
  •  
  • <!--- On the first pass, add the Ace as an 11. --->
  • <cfset local.sum += 11 />
  •  
  • <cfelse>
  •  
  • <!---
  • All other cards will be face cards at this time,
  • which will 10.
  • --->
  • <cfset local.sum += 10 />
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Now that we have summed the cards for the first time,
  • check to see if the hand is bust.
  • --->
  • <cfif (local.sum lte 21)>
  •  
  • <!--- The hand is not bust, so return sum. --->
  • <cfreturn local.sum />
  •  
  • </cfif>
  •  
  •  
  • <!---
  • The first pass resulted in a busted hand. This may or may
  • not have been due to the way we counted Aces. As such,
  • let's reset the sum and run through summing process again,
  • this time with the Ace counting for 2.
  • --->
  • <cfset local.sum = 0 />
  •  
  • <!--- Loop over cards a second time. --->
  • <cfloop
  • index="local.card"
  • array="#arguments.hand#">
  •  
  • <!--- Check to see what kind of card we have. --->
  • <cfif isNumeric( local.card )>
  •  
  • <!--- Simply add given value. --->
  • <cfset local.sum += local.card />
  •  
  • <cfelseif (local.card eq "A")>
  •  
  • <!--- On the second pass, add the Ace as an 2. --->
  • <cfset local.sum += 2 />
  •  
  • <cfelse>
  •  
  • <!---
  • All other cards will be face cards at this time,
  • which will 10.
  • --->
  • <cfset local.sum += 10 />
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  •  
  • <!--- Now, no matter what sum we have, just return it. --->
  • <cfreturn local.sum />
  • </cffunction>
  •  
  •  
  • <cffunction
  • name="isHandBust"
  • access="public"
  • returntype="boolean"
  • output="false"
  • hint="I determine if the given hand is bust (over 21).">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="hand"
  • type="array"
  • required="true"
  • hint="I am the blackjack hand being checked for bust."
  • />
  •  
  • <!--- Return true if the hand sum is over 21. --->
  • <cfreturn (getHandTotal( arguments.hand ) gt 21) />
  • </cffunction>

I know that I'm not giving a lot of explanation as to how the code works, but hopefully you can look at the code and the comments and figure out what's going on. This post was more to explore the contextual response functionality that TextMarks provides rather than to explore Blackjack game architecture. One of the nice things about "contextual responses" is that your application doesn't have to know about it - the "context" is used in the TextMarks proxy and a normal request is made to your web-based application. The only thing that your web application needs to do is maintain some sort of session information across requests such that the contextual responses do have a valid meaning within your application.



Looking For A New Job?

100% of job board revenue is donated to Kiva. Loans that change livesFind out more »

Reader Comments

@Ben Great post, interesting idea on how to keep the phone in a session. I found the post was very easy to follow and very interesting.

I am interested on how the number did actually show up and where that interface from your video is available if it is for testing like that.

Reply to this Comment

@Daniel,

The testing interface is actually provided by TextMarks itself on the TextMarks website. It's really easy to use - it acts just like a real phone. You might have to be logged-in, however because it send across your phone number.

The number shows up as something like:
+9175551234

Reply to this Comment

Ben, nice experiment!

This won't work if more than one people are playing this game, right? How to make it work for multiple independent gamers?

Reply to this Comment

@john,

From they way he has it set up it should be able to work with multiple users at the same time. Since phones can't keep track of their sessions he uses the application.phoneSessions[] variable to keep track of them for the phones. As he stated the unique id is what is used to tell the phones apart.

Reply to this Comment

@John,

@Daniel is correct - each phone gets its own session so they will get their own version of the game.

Reply to this Comment

Just found this. Great job Ben. I'm new to SMS stuff in general. I'm really interested in how the phone number is matched up to the unique id. Is that a CF thing? Where is that being handled? Maybe I missed something in the code. Apologies in advance.

Reply to this Comment

@Alex,

The Phone number to unique ID pairing is handled by the TextMarks people. I am not sure how they are doing it; but apparently, each phone is guaranteed to be unique. Maybe it's something that the phone sends with SMS meta-data or something behind the scenes?

Reply to this Comment

Hello, I can't get mine to work. How did you get yours to work? You can send GameGoal to the 41411. Please tell me what I am doing wrong so I can correct it.

Thanks

Reply to this Comment

@Matthew,

There are many things that could be going wrong; there's no way I would be able to tell the one thing that is going wrong.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.