Xopus plays Tic-Tac-Toe

Usually Xopus keeps you within the bounds and rules of a structured document: bold is allowed in a paragraph, but not in a header, or a header must be followed by the name of the author.

A game like Tic-Tac-Toe has similar rules: cross and circle can only be put in an empty square, when a player puts a cross in one of the squares, that is followed by putting a circle in one of the other squares, etc.

By teaching Xopus these rules in much the same way as you would with document rules, Xopus can respond to a move. When a player (author) puts (inserts) a circle, Xopus knows it should respond (the document is not valid). Xopus will respond by putting (inserting) a cross in the right (valid) location.

Play Tic-Tac-Toe against Xopus!
(tested in IE6 and 7 and Firefox 2 and 3)

Hint: if you can't win, try undo.

How did we do it?

There are four key ingredients needed to teach Xopus to play this game:

  1. XSD describing the valid games states.
  2. XML document which contains the initial (empty) game state.
  3. XSL stylesheet to convert the game state to HTML.
  4. A few lines of Javascript.

The main intelligence is contained in the XSD. This contains the valid game states, Xopus will use this to calculate the transition from one valid game state to the next. The XSD was generated and tweaked so that Xopus is worthy opponent.

The XML starts out like this:

<games />

The XSL is fairly straightforward:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:template match="/games">
    <xsl:apply-templates />
    <div class="game">
      <span class="at22">
        <img src="newgame.jpg" onclick="addElement(node, 'game')" />
      </span>
    </div>
  </xsl:template>
  
  <xsl:template match="game">
    <div class="game">
      <xsl:apply-templates />
    </div>
  </xsl:template>

  <xsl:template 
       match="at11|at21|at31|at12|at22|at32|at13|at23|at33">
    <span class="{name()}" style="z-index: {count(ancestor::*)}">
      <xsl:if test="not(O|X)">
        <!--  
          Make a move if the square is empty and 
          this game has no winner. 
        -->
        <xsl:attribute name="onclick">
          if (!node.hasChildNodes() &amp;&amp; 
              !node.selectSingleNode("ancestor::game//O_has_won|" +
                "ancestor::game//X_has_won"))
          { 
            addElement(node, 'O')
          }
        </xsl:attribute>
        <img src="_.jpg" style="cursor: pointer"/>
      </xsl:if>
      <xsl:apply-templates select="O|X" />
    </span>
    <xsl:apply-templates select="O/*|X/*" />
  </xsl:template>
  
  <xsl:template match="O">
    <img src="O.jpg" />
  </xsl:template>

  <xsl:template match="X">
    <img src="X.jpg" />
  </xsl:template>

  <xsl:template match="O_has_won">
    <div class="message">You have won!</div>
  </xsl:template>

  <xsl:template match="X_has_won">
    <div class="message">Xopus has won!</div>
  </xsl:template>

  <xsl:template match="draw">
    <div class="message">This game is a draw...</div>
  </xsl:template>
</xsl:stylesheet>

Then there is a little bit of Javascript to glue the components together. The new game button will call:

addElement(node, "game")

Where node is the games root element. Clicking an empty square to make a move will call:

addElement(node, "O")

Where node is the square that was clicked. The addElement function looks like this:

function addElement(parent, name) 
{ 
  var node = parent.getOwnerDocument().createElement(name); 
  parent.appendChild(node); 
  node.makeValid(); 
}

appendChild is used to either insert a new game or insert an O.
The magic is in makeValid which will initialize the game or make the next move according to the rules in the XSD.

That's all for now. We have to continue our work on Xopus 4.

Modified: July 10th 2008
By: Laurens van den Oever

ChrisEidhof
anonymous user
July 25th 2008
Haha, totally awesome! What's next, a FPS in Xopus? If it could be done performance-wise, that would be awesome. Use XSL to render your game-state into canvas-objects. Or SVG.
Bhavna
anonymous user
March 10th 2010
The developers wrote a schema that essentially describes the valid states of a tic-tac-toe game. When you click in a square, Xopus validates the document, and finding it “invalid”, responds (via javascript) by putting an X in another square. And so it goes until the game is over. There’s an XSL to render the game in the browser. It’s pretty neat. And the best part: if you find yourself about to lose a game of tic-tac-toe to an XSD schema (how embarassing!) you can cheat and Undo. I don’t know yet how useful Xopus will be to me for real work, but this is easily the most fun application of an XML authoring tool I’ve seen.
http://www.liste-de-casino.fr/
HTML will be shown as HTML code. Linebreaks and links starting with http:// are automatically resolved.