Skip to main content

Use XForms to create your own Sudoku game, Part 2: Create the game

Validate data and Load and save local files using XForms

Nicholas Chase (ibmquestions@nicholaschase.com), Freelance writer, Backstop Media
Nicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the Chief Technology Officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams).

Summary:  It's no secret that Sudoku is one of the hottest new trends around. This number game can easily be played on a computer or on paper, and because you can easily analyze the data in a form using XPath, it would not be impractical for you to use XForms to create a form that enables you to play Sudoku. This two-article series shows you how to create a game client that requests new games from the server, detects legal and illegal moves and the end of the game, and saves the current game for later. It also shows you how to generate new games for the user to play. Part 2 looks at loading and saving games.

View more content in this series

Date:  13 Mar 2007
Level:  Intermediate
Activity:  1890 views

This article assumes that you're familiar with the basics of XForms. For a refresher, see the Resources for links to content to get you started. The code has been written for and tested on the Mozilla Firefox XForms extensions, but the concepts apply to any implementation. To follow along with this article, you'll need a browser that supports XForms -- this article was written using Mozilla and the XForms extension -- and a server that supports PHP. To generate new Sudoku puzzles, you'll also need to have Python installed, and the Python Sudoku program.

Nick Chase in a developerWorks podcast

Hear the author discuss his obsession with Sudoku in this developerWorks podcast!

How you got here

In Part 1, you created the basic game, which enabled the user to play Sudoku using simple pulldown menus. The Submit button didn't appear until the user succeeded in solving the puzzle. The structure of the actual XForms document looked like Listing 1.


Listing 1. The current page

<?xml version="1.0"?>
<html xmlns="http://www.w3.org/1999/xhtml"       
      xmlns:xhtml="http://www.w3.org/1999/xhtml"
      xmlns:ev="http://www.w3.org/2001/xml-events"
      xmlns:xforms="http://www.w3.org/2002/xforms"
      xmlns:svg="http://www.w3.org/2000/svg" 
      xmlns:s="http://www.example.com/sudoku"
      xmlns:b="http://www.example.com/board">

  <head>
    <title>Sudoku</title>

<xforms:model>

  <xforms:instance id="content">
    <s:game>

      <s:row><s:box ro="yes">6</s:box><s:box></s:box>
<s:box></s:box><s:box></s:box><s:box></s:box>
<s:box ro="yes">9</s:box><s:box></s:box><s:box></s:box>
<s:box ro="yes">1</s:box></s:row>
...
      
<s:square><s:box>0</s:box><s:box>0</s:box><s:box>0</s:box>
<s:box>0</s:box><s:box>0</s:box><s:box>0</s:box><s:box>0
</s:box>
<s:box>0</s:box><s:box>0</s:box></s:square>
...
      <s:submitButtonElement>Submit</s:submitButtonElement>
      <s:correctRows>no</s:correctRows>

    </s:game>
  </xforms:instance>

  <xforms:bind nodeset="//s:row//s:box[@ro='yes']" readonly="true()" />

  <xforms:bind nodeset="//s:submitButtonElement"  
                             relevant="/s:game/s:correctRows = 27" />

  <xforms:bind nodeset="//s:correctRows" calculate=
     "count(/s:game/s:row[s:box = '1'][s:box = '2'][s:box = '3']
[s:box = '4'][s:box = '5'][s:box = '6'][s:box = '7'][s:box = '8']
[s:box = '9']) +
      count(/s:game[s:row[s:box[1]='1']][s:row[s:box[1]='2']]
[s:row[s:box[1]='3']][s:row[s:box[1]='4']][s:row[s:box[1]='5']]
[s:row[s:box[1]='6']][s:row[s:box[1]='7']][s:row[s:box[1]='8']]
[s:row[s:box[1]='9']]) +
...
      count(/s:game/s:square[s:box = '1'][s:box = '2']
[s:box = '3'][s:box = '4'][s:box = '5'][s:box = '6']
[s:box = '7'][s:box = '8'][s:box = '9'])" />

  <xforms:instance id="templates">
    <b:template>
      <b:entry><b:sendvalue>0</b:sendvalue>
               <b:display></b:display></b:entry>
      <b:entry><b:sendvalue>1</b:sendvalue>
               <b:display>1</b:display></b:entry>
      <b:entry><b:sendvalue>2</b:sendvalue>
               <b:display>2</b:display></b:entry>
...
    </b:template>
  </xforms:instance>

  <xforms:submission id="submitgame" action="" method="post"/>

</xforms:model>

<style type="text/css">

   div > * {display: inline;}

   *:read-only { color: red }
 
</style>

</head>
  <body>

    <img src="images/showlayout.gif" style="float:left;height: 64px; width: 64px;" />

    <h1 align="center">Sudoku</h1>

    <br clear="left" />

    <div>
      <xforms:repeat id="gamerow" nodeset="instance('content')/s:row">

        <xforms:repeat id="gamebox" nodeset="s:box">
        
          <span class="test"><xforms:select1 ref=".">
             <xforms:itemset nodeset="instance('templates')/b:entry">
                <xforms:label ref="b:display"/>
                <xforms:value ref="b:sendvalue"/>
             </xforms:itemset>
          </xforms:select1></span>
        </xforms:repeat>
      </xforms:repeat>
    </div>

    Correct Rows: <xforms:output ref="//s:correctRows" /><br />

    <xforms:trigger style="display:block">
          <xforms:label>Check it!</xforms:label>
          <xforms:action ev:event="DOMActivate">

          <xforms:setvalue ref="/s:game/s:square[1]/s:box[1]" 
                                value="/s:game/s:row[1]/s:box[1]" />
          <xforms:setvalue ref="/s:game/s:square[1]/s:box[2]" 
                                 value="/s:game/s:row[1]/s:box[2]" />
...
          </xforms:action>
      </xforms:trigger>

      <xforms:submit ref="/s:game/s:submitButtonElement" 
                     submission="submitgame">
         <xforms:label>Submit</xforms:label>	
      </xforms:submit>

  </body>
</html>

To recap, the instance includes a row element for each row of the grid, and square elements that help to emulate rows for calculating the 3x3 squares on the grid. (See Part 1 if you need a refresher in the rules.) Bind the correctRows element to a calculation that lets you know how many rows, columns, and boxes have been correctly solved. When the total hits 27, the Submit button appears.

To create the grid, loop through each row, and for each box, create a drop-down list by looping through each of the entry elements in the templates instance. If the box element has a value, that value is selected by default. Also, if the original instance provides a number, that square on the grid is read-only.

The board looks like Figure 1.


Figure 1. The current game
The current game

Now let's move on.


Enhancing the interface

Now, after you play this game for a while, you're probably going to get tired of using the pulldown menus. Instead, it'd be easier to just plug in the right number. To let users do that, you have to not only restructure the form, but also provide a way to keep them from entering invalid values.

Let's start by stripping out the pulldown menus (see Listing 2).


Listing 2. Replacing the pulldown menus with text boxes

...
<xforms:model>

  <xforms:instance id="content">
    <s:game xmlns:s="http://www.example.com/sudoku">
      <s:row><s:box s:ro="yes">6</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box s:ro="yes">9</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box s:ro="yes">1</s:box></s:row>
...
      
<s:square><s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box><s:box>.
</s:box>
<s:box>.</s:box><s:box>.</s:box></s:square>
...
      <s:submitButtonElement>Submit</s:submitButtonElement>
      <s:correctRows>no</s:correctRows>

    </s:game>
  </xforms:instance>

...
<style type="text/css">

 
   @namespace xforms url(http://www.w3.org/2002/xforms);

   div > * {display: inline;}

   *:read-only { color: red }

   xforms|input .xf-value, .input-value {width: 30px; 
                                         background-color: white;}

</style>

</head>
  <body>

    <img src="images/showlayout.gif" style="float:left;height: 64px; width: 64px;" />

    <h1 align="center">Sudoku</h1>

    <br clear="left" />

    <div>
      <xforms:repeat id="gamerow" nodeset="instance('content')/s:row">
        <xforms:repeat id="gamebox" nodeset="s:box">
            <span>
                <xforms:input ref="." />
            </span>
        </xforms:repeat>
      </xforms:repeat>
    </div>
...

Starting at the bottom, notice that the select1 element has been replaced with a simple input element, which will include as its value the contents of the box element. Normally, this would render much wider than you need it, so you'll then use Cascading Style Sheets to set the width of its value. Notice that you must first declare the xforms namespace alias and namespace.

Finally, a change to the actual data has been made. Before, you used zeroes to indicate boxes the user has to fill in, but because you're now putting the actual value in the box -- you no longer have the luxury of a label, as before -- you've changed it to a period (.) so that it's more visually obvious what's going on. You can see the results in Figure 2.


Figure 2. Using text inputs
Using text inputs

Now, the problem here is that there's nothing preventing a user from entering a nonsense value, such as "42" or "bleh." Fortunately, you can take care of that.


Enforcing constraints

XForms has schema validation built in, so it's easy for you to put constraints on what the user can enter in the text boxes. For example, you can specify that inputs must be integers (see Listing 3).


Listing 3. Constraining input to integers

...
  <xforms:instance id="content">
    <s:game xmlns:s="http://www.example.com/sudoku"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <s:row><s:box xsi:type="xsd:int"  
s:ro="yes">6</s:box><s:box xsi:type="xsd:int" 
>.</s:box><s:box xsi:type="xsd:int" >.</s:box>
<s:box xsi:type="xsd:int" >.</s:box><s:box 
xsi:type="xsd:int" >.</s:box><s:box xsi:type="xsd:int"
s:ro="yes">9</s:box><s:box xsi:type="xsd:int" >.</s:box>
<s:box xsi:type="xsd:int" >.</s:box><s:box xsi:type="xsd:int"  
s:ro="yes">1</s:box></s:row>
...
    </s:game>
  </xforms:instance>
...
    <div>
      <xforms:repeat id="gamerow" nodeset="instance('content')/s:row">
        <xforms:repeat id="gamebox" nodeset="s:box">
            <span>
                <xforms:input ref=".">

                   <xforms:action ev:event="xforms-invalid">
                       <xforms:setvalue ref=".">.</xforms:setvalue>
                       <xforms:message level="modal">Please 
                                 choose an integer from 1 to 
                                 9.</xforms:message> 
                   </xforms:action>

                </xforms:input>
            </span>
        </xforms:repeat>
      </xforms:repeat>
    </div>
...

First off, you are tying the instance in with the XML Schema namespace, and specifying that box elements must be integers. But there's no point in specifying that unless the form takes action if the data doesn't conform.

To get the form to take action, you can specify an action to be taken if the input element experiences the xforms-invalid event. When it does, the form set its value back to the simple period and shows a message.

You can test this out by adding a non-integer value, as you can see in Figure 3.


Figure 3. Entering invalid values
The empty page

Now, if you tested this out, you may have noticed that you actually got the message box twice. This is because you're setting the value to a non-integer, which is itself invalid.

Fortunately, there is another option. You can create a schema that specifies all of the allowable values (see Listing 4).


Listing 4. The schema

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
   targetNamespace="http://www.example.com/sudoku" 
   xmlns="http://www.example.com/sudoku">

  <xsd:element name="game" type="GameType"/>
  <xsd:element name="row" type="RowType"/>
  <xsd:element name="square" type="RowType"/>

  <xsd:element name="box" type="BoxType"/>
  
  <xsd:element name="submitButtonElement" type="ButtonType" />
  <xsd:element name="correctRows" type="CorrectRowsType" />

  <xsd:simpleType name="ButtonType">
     <xsd:restriction base="xsd:string" />
  </xsd:simpleType>
  <xsd:simpleType name="CorrectRowsType">
     <xsd:restriction base="xsd:int" />
  </xsd:simpleType>

<xsd:simpleType name='BoxType'>
    <xsd:restriction base="xsd:string">
        <xsd:enumeration value = "."/>
        <xsd:enumeration value = "1"/>
        <xsd:enumeration value = "2"/>
        <xsd:enumeration value = "3"/>
        <xsd:enumeration value = "4"/>
        <xsd:enumeration value = "5"/>
        <xsd:enumeration value = "6"/>
        <xsd:enumeration value = "7"/>
        <xsd:enumeration value = "8"/>
        <xsd:enumeration value = "9"/>
    </xsd:restriction>
</xsd:simpleType>

  <xsd:complexType name="RowType">
    <xsd:sequence>
      <xsd:element ref="box" minOccurs="9" maxOccurs="9" />
    </xsd:sequence>
  </xsd:complexType>

  <xsd:complexType name="GameType">
    <xsd:sequence>
      <xsd:element ref="row" minOccurs = "9" maxOccurs="9" />
      <xsd:element ref="square" minOccurs = "9" maxOccurs="9" />
      <xsd:element ref="submitButtonElement" minOccurs="1" 
                                             maxOccurs="1"  />
      <xsd:element ref="correctRows" minOccurs="1" maxOccurs="1" />
    </xsd:sequence>
  </xsd:complexType>

</xsd:schema>

Specifically, you specify the box element must be one of the integers from 1 through 9, or the period. You can then save this schema in a file, sudoku.xsd, and reference it from the form (see Listing 5).


Listing 5. Attaching the schema

...
  <head>
    <title>Sudoku</title>

<xforms:model schema="./sudoku.xsd">

  <xforms:instance id="content">
    <s:game xmlns:s="http://www.example.com/sudoku"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
      <s:row><s:box s:ro="yes">6</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box s:ro="yes">9</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box s:ro="yes">1</s:box></s:row>
...

Now, if you run the form, you'll still see the alert box, but only once, because the new value is allowable according to the schema.


Saving the current game

All right, now that you've got the interface tweaked, let's talk about managing the games you're presenting to the user.

The first step is to enable the user to save the current game. In a traditional HTML form, this would mean complicated scripts that accept the data and save it, then more scripts to retreive it again. Fortunately, XForms makes it much more simple.

XForms enables you to use HTTP's "PUT" method to save the instance data to a particular location. If your Web server is configured properly, you can save the instance there, but it's more common to save the data to the local hard drive (see Listing 6).


Listing 6. Saving to a local file

...
  <xforms:submission id="submitgame" action="" method="post"/>

  <xforms:submission id="savegame" action="file:///c:/sudoku.txt" 
        replace="instance" instance="content" method="put"/>

</xforms:model>
...
      <xforms:submit ref="/s:game/s:submitButtonElement" submission="submitgame">
         <xforms:label>Submit</xforms:label>	
      </xforms:submit>

      <xforms:submit submission="savegame">
         <xforms:label>Save current game</xforms:label>	
      </xforms:submit>

  </body>
</html>

Here you've created a new submission element that specifies the content instance, and tells the form to replace not the page, but just the instance, with any returned data. In this case, however, there isn't any returned data, because it also specifies the PUT method and a location for the file. This means that when you click the button, it simply saves the instance data to an XML file in the location you've specified.

If you save and load the form, you'll see the new button (see Figure 4).


Figure 4. The Save button
The save button

Change a few values and click the Save button. You should see a new XML file in the root directory of your C: drive containing the instance document as it existed when you saved it. Now let's look at getting it back.


Loading a saved game

Once you've saved a game, loading it back up is pretty straightfoward. What you want to do is have the form issue an HTTP request and place the data into the instance. You can do that by creating another submission (see Listing 7).


Listing 7. Loading the data

...
  <xforms:submission id="savegame" action="file:///c:/sudoku.txt" 
        replace="instance" instance="content" method="put"/>

  <xforms:submission id="loadgame" action="file:///c:/sudoku.txt" 
        replace="instance" instance="content" method="get"/>

</xforms:model>

<style type="text/css">
...
      <xforms:submit submission="savegame">
         <xforms:label>Save current game</xforms:label>	
      </xforms:submit>

      <xforms:submit submission="loadgame">
         <xforms:label>Load saved game</xforms:label>	
      </xforms:submit>

  </body>
</html>

In this case, you're issuing a GET request, which is what your browser does whenever you request a new Web page. When it gets the data back, it replaces just the contents of the content instance. To see this in action, save and load the form, then change a few values. Save the game, and then reload the form to bring it back to its original state. Click the Load saved game button to see your changes reappear.


Submitting a game

All right, now this one game is interesting and all, but how often can you play it? No, you need a way to enable the user to submit the current game to the server and get a new one. You'll look at the actual submission in a moment, but first you need to tweak your browser settings just a bit.

For security reasons, XForms can only load and save data from the server from which it was original downloaded. Now, you can solve part of the problem by uploading the form to the server from which you'll be requesting the data. But it doesn't solve all of your problems.

The difficulty lies in the fact that you're saving the data to a local file, which means it's not the original server. To solve that problem, you need to add the server to the list of "trusted servers" with regard to XForms.

To do that, select Tools->Options and make sure the checkbox for "Allow XForms to access other domains" is checked. Next, click the Allowed Sites button. Add the name of the server you're dealing with and check the Load and Save checkboxes. (See Figure 5.) Click the Add button and close the dialogue boxes. Restart the browser to get the changes to take effect.


Figure 5. The trusted sites
The trusted sites

Now you're ready to create the actual submission. Ultimately, you're going to be getting your new games from a PHP script called convertGame.php -- you'll have a look at that in a moment -- so let's go ahead and update the submission element (see Listing 8).


Listing 8. The complete submission

...
  </xforms:instance>

  <xforms:submission id="submitgame" 
        action="http://www.backstopmedia.com/sudoku/convertGame.php" 
        replace="instance" instance="content" method="post"/>

  <xforms:submission id="savegame" action="file:///c:/sudoku.txt" 
        replace="instance" instance="content" method="put"/>
...

As before, you've specified that you only want to replace the instance, rather than the whole page, and the instance that you want to replace. You've also added the URL for the script that will provided your new games.


Getting a new game

Unless you're a math whiz (or have way too much time on your hands) you're not going to want to generate these puzzles yourself. Fortunately, you don't have to.

Python Sudoku is an open-source application that both generates and solves Sudoku puzzles. (Check the Resources for the download URL.) It's intended for generating puzzles for paper and other applications, but you'll need to do a little tweaking -- and a host that supports Python scripting -- to get it to output puzzles directly to your form.

Instead, you're going to generate a number of puzzles offline and randomly return them to the form. To create these puzzles, unzip the Python Sudoku package and execute the following command from the newly extracted directory (see Listing 9).


Listing 9. Generate a new puzzle

>>>>>python pysdk.py -c game11.sdk
Creating sudoku... success!
 1  _  _    _  _  _    5  _  _
 _  _  _    6  _  _    9  _  _
 _  _  _    3  4  _    _  _  _

 _  _  _    _  _  _    _  1  _
 _  8  _    _  _  2    _  _  9
 7  9  2    _  _  5    _  _  _

 _  _  8    _  3  _    _  6  _
 _  _  _    _  _  _    _  _  _
 _  2  4    1  _  8    _  3  _

In this case, I've created a file called game11.sdk. Create a series of this puzzles and name them game1.sdk, game2.sdk, game3.sdk, and so on.

The files all use the same format (see Listing 10).


Listing 10. The generated game

# boardsize 3 x 3
  1  0  0    0  0  0    5  0  0
  0  0  0    6  0  0    9  0  0
  0  0  0    3  4  0    0  0  0

  0  0  0    0  0  0    0  1  0
  0  8  0    0  0  2    0  0  9
  7  9  2    0  0  5    0  0  0

  0  0  8    0  3  0    0  6  0
  0  0  0    0  0  0    0  0  0
  0  2  4    1  0  8    0  3  0

Once you've generated the games, move them to a server on which you can execute PHP. You'll create a PHP script, convertGame.php, which chooses a file at random and reads in the data to create an instance to return to the form.

This script looks like Listing 11.


Listing 11. The convertGame.php script

<?php

$nextGame = rand(1, 10);

$lines = file('game'.$nextGame.'.sdk');

echo '<s:game xmlns:s="http://www.example.com/sudoku">';

foreach ($lines as $line_num => $line) {
 
    $line = str_replace(" ", "", $line);
    $line = str_replace("\n", "", $line);

    if ($line_num > 0 && $line != '') {

       echo "<s:row>";

       for ($x = 0; $x < 9; $x++){
            $thisBox = substr($line, $x, 1);
            if ($thisBox == "0") {
                echo "<s:box>.</s:box>";
            } else {
                echo "<s:box s:ro='yes'>".$thisBox."</s:box>";
            }
       }

       echo "</s:row>";

    }


}

echo "      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:square><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box><s:box>.</s:box><s:box>.</s:box>
<s:box>.</s:box></s:square>
      <s:submitButtonElement>Submit</s:submitButtonElement>
      <s:correctRows>no</s:correctRows>";
echo '</s:game>';

?>

To start with, you need to choose the next game. Here, you're choosing a random integer between 1 and 10 (inclusive). You can then use that integer to create the file name for the game to return. From there, you can use the file() function to extract an array of each of the lines in the file.

You can then start outputting the instance, starting with the open tag for the root element, game. For each line, first extract all of the spaces and the line feed at the end of the line. Once you've done that, you can tell the difference between the lines that actually contain data and those that don't. For each line that does, you open a new row element and loop through each digit to create a box element. If the digit is a zero (0), you replace it with a period, but if it's not, you also include the read-only attribute (ro). At the end of each line, you close the row element.

Once you've taken care of the data in the game file, you need the additional data, such as the square elements and the submitButtonElement and correctRows elements. Finally, close the game element.

If you load the form, the schema, and the convertGame.php script to the server and call it in the browser, you can test it out. (To avoid having to solve each puzzle before submitting, comment out the bind element that hides the Submit button.) Click the Submit button repeatedly to see the puzzle change.

That's it!

Summary

In this two-article series, you created an XForms form that emulates a Sudoku game. In Part 1, you created the basic form, which enables the user to play the game using dropdown menus. The form calculates whether or not the puzzle has been solved and reacts accordingly. In Part 2, you changed the form to use text inputs, adding schema constraints to make sure users couldn't enter invalid data. You also gave the user the ability to save an existing game locally, and to load that saved game back into the current instance. Finally, you look at a way to create new games and provide them to the form.



Download

DescriptionNameSizeDownload method
Part 2 sample codexforms2_source.zip7KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Nicholas Chase has been involved in Web site development for companies such as Lucent Technologies, Sun Microsystems, Oracle, and the Tampa Bay Buccaneers. Nick has been a high school physics teacher, a low-level radioactive waste facility manager, an online science fiction magazine editor, a multimedia engineer, an Oracle instructor, and the Chief Technology Officer of an interactive communications company. He is the author of several books, including XML Primer Plus (Sams).

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML
ArticleID=201807
ArticleTitle=Use XForms to create your own Sudoku game, Part 2: Create the game
publish-date=03132007
author1-email=ibmquestions@nicholaschase.com
author1-email-cc=dwxed@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers