Number guessing game

Adapted from Tony Collen's GettingStartedWithFlow page on the Cocoon wiki.

In this example, an HTML form is shown repeatedly, until the user guesses the correct number.

Start the game here.

The sitemap

At the sitemap level, Flowscript applications need four things:

The corresponding excerpts of our sitemap are shown below.

Flowscript declaration

Note that this already contains the declaration of the next example's Flowscript.

<map:flow id="flow" language="javascript">
<map:script src="number-guess/guess-number.js"/>
<map:script src="multi-page/multi-page.js"/>
<map:script src="java-shapes/java-shapes.js"/>
</map:flow>

map:call function

Here we use variables to allow any Flowscript function to be called, with a simple security restriction: the function name must start with the public_ prefix.

The maxValue parameter is used by our Flowscript public_startGuessNumber function, but doesn't hurt if it is passed to other functions (like in the next example).

<map:match id="start" pattern="*/start*">
<map:call function="public_start{2}">
<map:parameter name="maxValue" value="10"/>
</map:call>
</map:match>

map:call continue

This activates a Flowscript continuation when an URL ending with a continuation ID and the .continue suffix is received.

<map:match id="continue" pattern="**/*.continue">
<map:call continuation="{2}"/>
</map:match>

View pipeline using JXTemplageGenerator

To be able to include data provided by Flowscript in our forms and views, we use the Flowscript-aware JXTemplateGenerator

Here's the pipeline

<map:match id="views" pattern="*/views/*">
<map:generate src="{1}/{2}.xml" type="file"/>
<map:transform type="jx"/>
<map:call resource="html"/>
</map:match>

Which uses this resource to convert the page to HTML

<map:resource id="html" name="html">
<map:transform src="../intro/presentation/page2html.xsl"/>
<map:serialize type="html"/>
</map:resource>

And here's the JXTemplate component declaration

<map:generators id="generators" default="file">
<map:generator name="jx" src="org.apache.cocoon.generation.JXTemplateGenerator" label="content" logger="sitemap.generator.jx"/>
</map:generators>

Flowscript code

Here's the complete Flowscript code that drives the number-guessing game. (sorry about the lost indentation, the Slop block, which generates these listings, has been improved in the meantime).

guess-number.js
0001 /*
0002 * Copyright 1999-2004 The Apache Software Foundation.
0003 *
0004 * Licensed under the Apache License, Version 2.0 (the "License");
0005 * you may not use this file except in compliance with the License.
0006 * You may obtain a copy of the License at
0007 *
0008 * http://www.apache.org/licenses/LICENSE-2.0
0009 *
0010 * Unless required by applicable law or agreed to in writing, software
0011 * distributed under the License is distributed on an "AS IS" BASIS,
0012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013 * See the License for the specific language governing permissions and
0014 * limitations under the License.
0015 */

0017 // simple number guessing game in Flowscript
0018 // based on the Cocoon Flow tutorial:
0019 // http://cocoon.apache.org/2.1/userdocs/flow/tutor.html

0021 function public_startGuessNumber() {
0022 var max = cocoon.parameters["maxValue"];
0023 var toGuess = Math.round(Math.random() * max);
0024 if(toGuess == 0) toGuess = 1;
0025 var hint = "Guess a number between 1 and " + max;
0026 var tries = 0;

0028 // show and process input form, until correct answer is given
0029 while (true) {
0030 cocoon.sendPageAndWait("number-guess/views/guess", {"toGuess" : toGuess, "hint" : hint, "tries" : tries});
0031 var answer = parseInt( cocoon.request.get("answer") );

0033 tries++;

0035 if(answer) {
0036 if(answer > toGuess) {
0037 hint = "The number you entered (" + answer + ") is too big";
0038 } else if(answer < toGuess) {
0039 hint = "The number you entered (" + answer + ") is too small";
0040 } else {
0041 break;
0042 }
0043 }
0044 }

0046 cocoon.sendPage("number-guess/views/success", {"toGuess" : toGuess, "answer" : answer, "tries" : tries} );
0047 }

JXTemplate view

The JXTemplateGenerator makes Flowscript variables (like the toGuess and hint attributes of the sendPageAndWait call above) accessible using a simple substitution syntax.

Here's the page definition for our number-guessing form. JXTemplate codes like ${cocoon.continuation.id}, will by replaced by values provided in the Flowscript sendPageAndWait function call.

<page id="page">
<title> Flow example: Guess a number </title>
<content>
<h2> ${hint} </h2>
<form method="post" action="${cocoon.continuation.id}.continue">
<input type="text" name="answer"/>
<input type="submit"/>
</form>
<p class="footer">
<a href="../docs/index.html"> Flow examples </a>
</p>
</content>
</page>

That's it!

We have now seen the complete code of our Flowscript application:

We didn't have to write much code to implement this, and more importantly all the code that we wrote is application-specific. The Cocoon framework provides all the infrastructure.