<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
  <title>Minesweeper in XForms</title>
  <link rel="stylesheet" href="projection.css" />
  <link rel="alternate stylesheet" title="Overview" href="overview.css" />
  <meta name="generator" content="amaya 9.4, see http://www.w3.org/Amaya/" />
  <style type="text/css">
    .source {text-align: right}
iframe {width: 90%; height: 60ex; border: none}</style>
</head>

<body>

<div>
<h1>Minesweeper in XForms</h1>

<p><a href="http://www.cwi.nl/~steven/">Steven Pemberton</a>, <a
href="http://www.cwi.nl/">CWI</a>, <a
href="http://www.cwi.nl/~steven/amsterdam.html">Amsterdam</a></p>

<p><img src="hamleeet.jpg" alt="The author" /></p>
</div>

<div>
<h2>The Board</h2>

<p>We're going to program for a 10×10 board of cells.We could just write the
board out wholesale:</p>
<pre>&lt;instance&gt;
  &lt;game xmlns=""&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
    &lt;row&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;c/&gt;&lt;/row&gt;
  &lt;/game&gt;
&lt;/instance&gt;</pre>
<p>But we won't.</p>
</div>

<div>
<h2>Start with a 1 cell board</h2>
<pre>&lt;instance&gt;
  &lt;game xmlns=""&gt;
    &lt;row&gt;&lt;c/&gt;&lt;/row&gt;
  &lt;/game&gt;
&lt;/instance&gt;</pre>

<p>and grow it by responding to the <code>xforms-ready</code> event:</p>
<pre>&lt;action ev:event="<strong>xforms-ready</strong>"&gt;
  ...
&lt;/action&gt;</pre>

<p></p>
</div>

<div>
<h2>Insert</h2>

<p>The simplest form of the <code>&lt;insert/&gt;</code> action just duplicates
the last element of a (non-empty) list. So starting with </p>
<pre>&lt;row&gt;&lt;c/&gt;&lt;/row&gt;</pre>

<p>the action</p>
<pre>&lt;insert ref="row/c"/&gt;</pre>

<p>gives</p>
<pre>&lt;row&gt;&lt;c/&gt;<strong>&lt;c/&gt;</strong>&lt;/row&gt;</pre>

</div>

<div>
<h2>Insert</h2>

<p>So we just do that until we have ten cells in the row, and then the same for
the rows, giving us a 10×10 board:</p>
<pre>&lt;insert ref="row/c" <strong>while="count(//c) &amp;lt; 10"</strong>/&gt;
&lt;insert ref="row" while="count(//row) &amp;lt; 10"/&gt;</pre>
</div>

<div>
<h2>Mines</h2>

<p>Place 10 mines at random locations:</p>
<pre>&lt;setvalue
   ref="row[round(random()*9)+1]/c[round(random()*9)+1]"
   while="count(//c[.='💣']) &amp;lt; 10"&gt;💣&lt;/setvalue&gt;</pre>
</div>

<div>
<h2>Display</h2>
<pre>&lt;repeat ref="row"&gt; 
    &lt;repeat ref="c"&gt;
        &lt;output value="."/&gt;
    &lt;/repeat&gt;
&lt;/repeat&gt;</pre>

<p>adding some suitable CSS:</p>
</div>

<div>
<h2>Result</h2>
<iframe src="../../../forms/examples/minesweeper/minesweeper1.xhtml">
</iframe>
</div>

<div>
<h2>Counting</h2>

<p>Fill each non-mine cell with the count of its mine-filled neighbours:</p>
<pre>&lt;bind ref="//c[.!='💣']" 
      calculate="count(...something here...)"/&gt;</pre>
</div>

<div>
<h2>Neighbours</h2>
<pre>../preceding-sibling::row[1]/c[2+count(context()/preceding-sibling::c)] |
../preceding-sibling::row[1]/c[1+count(context()/preceding-sibling::c)] |
../preceding-sibling::row[1]/c[  count(context()/preceding-sibling::c)] |
   preceding-sibling::c[1] | 
   following-sibling::c[1] |
../following-sibling::row[1]/c[2+count(context()/preceding-sibling::c)] |
../following-sibling::row[1]/c[1+count(context()/preceding-sibling::c)] |
../following-sibling::row[1]/c[  count(context()/preceding-sibling::c)]</pre>
<p>So:</p>
<pre>&lt;bind ref="row/c[.!='💣']" 
      calculate="<strong>count(</strong>(<em>neighbours</em>)<strong>[.='💣'])</strong>"/&gt;</pre>
</div>

<div>
<h2>Result</h2>
<iframe src="../../../forms/examples/minesweeper/minesweeper2.xhtml">
</iframe>
</div>

<div>
  <h2>Interaction</h2>
  <p>Surround the output with a trigger that marks the cell as clicked:</p>
<pre>&lt;repeat ref="row"&gt; 
   &lt;repeat ref="cell" &gt;
      <strong>&lt;trigger appearance="minimal"&gt;
         &lt;label&gt;</strong>&lt;output value="."/&gt;<strong>&lt;/label&gt;
<strong>         &lt;setvalue ev:event="DOMActivate" ref="@clicked"&gt;yes&lt;/setvalue&gt;</strong>
      &lt;/trigger&gt;</strong>
   &lt;/repeat&gt;
&lt;/repeat&gt;</pre>

<p>Change the board:</p>
<pre>&lt;instance&gt;
  &lt;game size="10" mines="10" xmlns=""&gt;
    &lt;row&gt;&lt;c <strong>clicked=""</strong>/&gt;&lt;/row&gt;
  &lt;/game&gt;
&lt;/instance&gt;</pre>

<p></p>
</div>

<div>
<h2>Change the output</h2>

<p>Cells are hidden until clicked</p>
<pre><strong>&lt;output value="if(@clicked='', '□', .)"/&gt;</strong></pre>

<p>Zeros are displayed as a (non-breaking) space:</p>
<pre>&lt;output value="if(@clicked='', '□', <strong>if(.=0, '&amp;#x00A0;', .)</strong>)"/&gt;</pre>
</div>

<div>
  <h2>Result</h2>
  <p>(All examples are live, so you can click on them)</p>
<iframe src="../../../forms/examples/minesweeper/minesweeper3.xhtml">
</iframe>
</div>

<div>
<h2>Oil slick effect</h2>

<p>If you click on a zero cell, neighbouring zeros get revealed as well.</p>

<p>Change the board:</p>
<pre>&lt;instance&gt;
  &lt;game size="10" mines="10" xmlns=""&gt;
    &lt;row&gt;&lt;c clicked="" <strong>revealed=""</strong>/&gt;&lt;/row&gt;
  &lt;/game&gt;
&lt;/instance&gt;</pre>

<p>Change the output slightly:</p>
<pre>&lt;output value="if(<strong>not(@revealed)</strong>, '□', if(.=0, '&amp;#x00A0;', .))"/&gt;</pre>

<p>And specify what it means for a cell to be revealed:</p>
<pre>&lt;bind ref="row/c/@revealed" type="boolean"
      calculate="<strong>../@clicked='yes' or </strong><em>neighbours<strong></strong></em><strong>[@revealed and .=0]</strong>"/&gt;</pre>
</div>

<div>
<h2>Result</h2>
<iframe src="../../../forms/examples/minesweeper/minesweeper4.xhtml">
</iframe>
</div>

<div>
<h2>Bells and whistles</h2>

<p>Keep track of state of play. You lose if a mine has been revealed; you win if the number of non-revealed cells equals the number of mines:</p>
<pre>&lt;bind ref="@state"
      calculate="if(//c[.='💣' and @revealed], <strong>'lose'</strong>, 
      if(count(//c[not(@revealed)])=count(//c[.='💣']), <strong>'win'</strong>,
      ''))"/&gt;</pre>

<p>Keep count of remaining non-mine squares:</p>
<pre>&lt;bind ref="@count" calculate="count(//c[not(@revealed)])-/game/@mines"/&gt;</pre>

<p>Add some fancy CSS</p>
</div>

<div>
<h2>Result</h2>
<iframe src="../../../forms/examples/minesweeper/minesweeper5.xhtml">
</iframe>
<p>About 50 lines of XForms</p>
<p class="source"><a href="../../../forms/examples/minesweeper/minesweeper5.xhtml">Source</a> (may differ slightly from exposition above)</p>

</div>
</body>
</html>
