<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0">

    <!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
    <!--                                            -->
    <!-- An XSLT implementation of the Game of Life -->
    <!-- by Roger L. Costello                       -->
    <!--                                            -->
    <!-- Many thanks to Tom Passin, Len Bullard,    -->
    <!-- Didier Martin, and Mike Champion for their -->
    <!-- outstanding insights and suggestions.      -->
    <!--                                            -->
    <!-- Rules of the Game of Life:                 -->
    <!-- 1. The game is played on a board that      -->
    <!--    extends infinitely in both directions.  -->
    <!-- 2. A dead cell with exactly 3 live neigh-  -->
    <!--    bors becomes a live cell (birth).       -->
    <!-- 3. A live cell with 2-3 live neighbors     -->
    <!--    stays alive (survival).                 -->
    <!-- 4. In all other cases, a cell dies or      -->
    <!--    remains dead (overcrowding or lonliness)-->
    <!-- See http://www.math.com/students/wonders/life/life.html for details. -->
    <!--                                            -->
    <!-- My implementation:                         -->
    <!-- 1. The input XML document contains the     -->
    <!--    current state of the cells.             -->
    <!-- 2. A live cell is denoted with a value of  -->
    <!--    1; a dead cell with a value of 0.       -->
    <!-- 3. To simplify implementation I surround   -->
    <!--    the cells with 2 rows/columns of dead   -->
    <!--    cells.                                  -->
    <!-- 4. The output is an XML document that      -->
    <!--    shows the state of the cells after 1    -->
    <!--    iteration.                              -->
    <!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
 
    <xsl:output method="xml"/>

    <xsl:variable name="rowcount" select="count(/grid/row)"/>
    <xsl:variable name="columncount" select="count(/grid/row[1]/column)"/>
   
    <xsl:template match="grid">
        <xsl:variable name="expand">
            <xsl:call-template name="shouldGridBeExpanded"/>
        </xsl:variable>

        <grid>
        <row>
            <xsl:for-each select="/grid/row[1]/column">
                <column>
                    <value>0</value>
                </column>
            </xsl:for-each>
            <xsl:if test="contains($expand, 'expand')">
                <column>
                    <value>0</value>
                </column>
                <column>
                    <value>0</value>
                </column>
            </xsl:if>
        </row> 
        <xsl:if test="contains($expand, 'expand')">
            <row>
                <xsl:for-each select="/grid/row[1]/column">
                    <column>
                        <value>0</value>
                    </column>
                </xsl:for-each>
                <column>
                    <value>0</value>
                </column>
                <column>
                    <value>0</value>
                </column>
            </row> 
        </xsl:if>

        <xsl:for-each select="row">
            <xsl:variable name="r" select="position()"/>
            <xsl:if test="($r &gt; 1) and ($r &lt; $rowcount)">
                <row>
                <column>
                    <value>0</value>
                </column>
                <xsl:if test="contains($expand, 'expand')">
                    <column>
                        <value>0</value>
                    </column>
                </xsl:if>
                <xsl:for-each select="column">
                    <xsl:variable name="c" select="position()"/>
                    <xsl:if test="($c &gt; 1) and ($c &lt; ($columncount))">
                        <xsl:variable name="liveNeighbors" select="//row[$r - 1]/column[$c - 1]/value +
                                                                   //row[$r - 1]/column[$c]/value +
                                                                   //row[$r - 1]/column[$c + 1]/value +
                                                                   //row[$r]/column[$c + 1]/value +
                                                                   //row[$r + 1]/column[$c + 1]/value +
                                                                   //row[$r + 1]/column[$c]/value +
                                                                   //row[$r + 1]/column[$c - 1]/value +
                                                                   //row[$r]/column[$c - 1]/value"/>
                        <xsl:choose>
                            <xsl:when test="value=0">
                                <xsl:choose>
                                    <xsl:when test="$liveNeighbors=3">
                                        <column>
                                            <value>1</value>
                                        </column>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <column>
                                            <value>0</value>
                                        </column>
                                    </xsl:otherwise>
                                </xsl:choose>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:choose>
                                    <xsl:when test="($liveNeighbors=2) or ($liveNeighbors=3)">
                                        <column>
                                            <value>1</value>
                                        </column>
                                    </xsl:when>
                                    <xsl:otherwise>
                                        <column>
                                            <value>0</value>
                                        </column>
                                    </xsl:otherwise>
                                </xsl:choose>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:if>
                </xsl:for-each>
                <column>
                    <value>0</value>
                </column>
                <xsl:if test="contains($expand, 'expand')">
                    <column>
                        <value>0</value>
                    </column>
                </xsl:if>
                </row>
            </xsl:if>
        </xsl:for-each>

        <row>
            <xsl:for-each select="/grid/row[1]/column">
                <column>
                    <value>0</value>
                </column>
            </xsl:for-each>
            <xsl:if test="contains($expand, 'expand')">
                <column>
                    <value>0</value>
                </column>
                <column>
                    <value>0</value>
                </column>
            </xsl:if>
        </row> 
        <xsl:if test="contains($expand, 'expand')">
            <row>
                <xsl:for-each select="/grid/row[1]/column">
                    <column>
                        <value>0</value>
                    </column>
                </xsl:for-each>
                <column>
                    <value>0</value>
                </column>
                <column>
                    <value>0</value>
                </column>
            </row> 
        </xsl:if>
        </grid>

    </xsl:template>

    <xsl:template name="shouldGridBeExpanded">

        <xsl:for-each select="/grid/row[2]/column">
            <xsl:variable name="r" select="2"/>
            <xsl:variable name="c" select="position()"/>
            <xsl:variable name="liveNeighbors" select="//row[$r - 1]/column[$c - 1]/value +
                                                       //row[$r - 1]/column[$c]/value +
                                                       //row[$r - 1]/column[$c + 1]/value +
                                                       //row[$r]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c]/value +
                                                       //row[$r + 1]/column[$c - 1]/value +
                                                       //row[$r]/column[$c - 1]/value"/>
            <xsl:if test="$liveNeighbors=3">
                <xsl:text>expand</xsl:text>
            </xsl:if>            
        </xsl:for-each>

        <xsl:for-each select="/grid/row[$rowcount - 1]/column">
            <xsl:variable name="r" select="$rowcount - 2"/>
            <xsl:variable name="c" select="position()"/>
            <xsl:variable name="liveNeighbors" select="//row[$r - 1]/column[$c - 1]/value +
                                                       //row[$r - 1]/column[$c]/value +
                                                       //row[$r - 1]/column[$c + 1]/value +
                                                       //row[$r]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c]/value +
                                                       //row[$r + 1]/column[$c - 1]/value +
                                                       //row[$r]/column[$c - 1]/value"/>
            <xsl:if test="$liveNeighbors=3">
                <xsl:text>expand</xsl:text>
            </xsl:if>            
        </xsl:for-each>

        <xsl:for-each select="/grid/row[(position &gt; 1) and (position &lt; last())]">
            <xsl:variable name="r" select="position()"/>
            <xsl:variable name="c" select="2"/>
            <xsl:variable name="liveNeighbors" select="//row[$r - 1]/column[$c - 1]/value +
                                                       //row[$r - 1]/column[$c]/value +
                                                       //row[$r - 1]/column[$c + 1]/value +
                                                       //row[$r]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c]/value +
                                                       //row[$r + 1]/column[$c - 1]/value +
                                                       //row[$r]/column[$c - 1]/value"/>
            <xsl:if test="$liveNeighbors=3">
                <xsl:text>expand</xsl:text>
            </xsl:if>            
        </xsl:for-each>

        <xsl:for-each select="/grid/row[(position &gt; 1) and (position &lt; last())]">
            <xsl:variable name="r" select="position()"/>
            <xsl:variable name="c" select="$columncount - 2"/>
            <xsl:variable name="liveNeighbors" select="//row[$r - 1]/column[$c - 1]/value +
                                                       //row[$r - 1]/column[$c]/value +
                                                       //row[$r - 1]/column[$c + 1]/value +
                                                       //row[$r]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c + 1]/value +
                                                       //row[$r + 1]/column[$c]/value +
                                                       //row[$r + 1]/column[$c - 1]/value +
                                                       //row[$r]/column[$c - 1]/value"/>
            <xsl:if test="$liveNeighbors=3">
                <xsl:text>expand</xsl:text>
            </xsl:if>            
        </xsl:for-each>

    </xsl:template>

</xsl:stylesheet>