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

    <!-- xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx -->
    <!--                                            -->
    <!-- A self-reproducing XSLT implementation of  -->
    <!--  the Game of Life.                         -->
    <!-- by Roger L. Costello                       -->
    <!--                                            -->
    <!-- This implementation interacts with a       -->
    <!-- population monitor XSLT program. If the    -->
    <!-- population monitor instructs this Game of  -->
    <!-- Life to increase population then the Game  -->
    <!-- modifies its rules to encourage growth     -->
    <!-- (more live cells).  If the population      -->
    <!-- monitor instructs this Game of Life to     -->
    <!-- decrease population then the Game modifies -->
    <!-- its rules to discourage growth (less live  -->
    <!-- cells).                                    -->
    <!-- Normally if a cell is dead but there are   -->
    <!-- exactly 3 live neighbors then the cell     -->
    <!-- becomes live.  However, if the population  -->
    <!-- control indicates increase then the rule   -->
    <!-- is modified (expanded) to create a live    -->
    <!-- cell if there are 2,3,4 live neighbors.    -->
    <!-- If the population control indicates still  -->
    <!-- more increase then the rule is modified    -->
    <!-- further to 1,2,3,4,5.  Eventually, the     -->
    <!-- rule may expand up to 1,2,3,4,5,6,7,8.     -->
    <!-- If the population control indicates        -->
    <!-- decrease then the rule goes the other      -->
    <!-- direction (shrinks).                       -->
    <!--                                            -->
    <!-- Many thanks to Didier Martin, Len Bullard, -->
    <!-- Tom Passin, and Mike Kurras for their      -->
    <!-- outstanding support and suggestions.       -->
    <!--                                            -->
    <!-- Normal 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:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

    <xsl:variable name="rowcount" select="count(/grid/row)"/>
    <xsl:variable name="columncount" select="count(/grid/row[1]/column)"/>
    <xsl:variable name="current-value-of-required-live-neighbors-for-birth" select="'3'"/>
    <xsl:variable name="required-live-neighbors-for-birth">
        <xsl:call-template name="compute-required-live-neighbors-for-birth"/>
    </xsl:variable>
   
    <xsl:template match="grid">
<xsl:message>
    current-value-of-required-live-neighbors-for-birth = #<xsl:value-of select="$current-value-of-required-live-neighbors-for-birth"/>#
    required-live-neighbors-for-birth = #<xsl:value-of select="$required-live-neighbors-for-birth"/>#
</xsl:message>
        <xsl:variable name="expand">
            <xsl:call-template name="shouldGridBeExpanded"/>
        </xsl:variable>

        <grid>
        <adjust-population>none</adjust-population>
        <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="contains($required-live-neighbors-for-birth, string($liveNeighbors))">
                                        <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:result-document href="GameOfLife-offspring.xsl">
        <xsl:value-of disable-output-escaping="yes" select="'&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; 
                      xmlns:axsl=&quot;http://www.w3.org/1999/XSL/Transform/alias&quot;
                      xmlns:saxon=&quot;http://icl.com/saxon&quot;
                      extension-element-prefixes=&quot;saxon&quot;
                      version=&quot;1.0&quot;>'"/>
         
            <axsl:output method="xml"/>

            <axsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/>

            <axsl:variable name="rowcount" select="count(/grid/row)"/>
            <axsl:variable name="columncount" select="count(/grid/row[1]/column)"/>
            <axsl:variable name="current-value-of-required-live-neighbors-for-birth">
                <xsl:attribute name="select">'<xsl:value-of select="$required-live-neighbors-for-birth"/>'</xsl:attribute>
            </axsl:variable>
            <axsl:variable name="required-live-neighbors-for-birth">
                <axsl:call-template name="compute-required-live-neighbors-for-birth"/>
            </axsl:variable>   
  
            <xsl:variable name="self" select="document('')"/>
            <xsl:copy-of select="$self//xsl:template"/>
            
        <xsl:value-of disable-output-escaping="yes"  select="'&lt;/xsl:stylesheet>'"/>
        </xsl:result-document>

    </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="contains($required-live-neighbors-for-birth, string($liveNeighbors))">
                <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="contains($required-live-neighbors-for-birth, string($liveNeighbors))">
                <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="contains($required-live-neighbors-for-birth, string($liveNeighbors))">
                <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="contains($required-live-neighbors-for-birth, string($liveNeighbors))">
                <xsl:text>expand</xsl:text>
            </xsl:if>            
        </xsl:for-each>

    </xsl:template>

    <xsl:template name="compute-required-live-neighbors-for-birth">
        <xsl:choose>
            <xsl:when test="/grid/adjust-population = 'none'">
                <xsl:value-of select="$current-value-of-required-live-neighbors-for-birth"/>
            </xsl:when>
            <xsl:when test="/grid/adjust-population = 'increase'">
                <xsl:variable name="min">
                    <xsl:call-template name="find-min">
                        <xsl:with-param name="s" select="$current-value-of-required-live-neighbors-for-birth"/>
                    </xsl:call-template>
                </xsl:variable>
                <xsl:variable name="max">
                    <xsl:call-template name="find-max">
                        <xsl:with-param name="s" select="$current-value-of-required-live-neighbors-for-birth"/>
                    </xsl:call-template>
                </xsl:variable>
                <xsl:choose>
                    <xsl:when test="$max &lt; 7">
                        <xsl:value-of select="concat(number($min) - 1, ',', $current-value-of-required-live-neighbors-for-birth, ',', number($max) + 1)"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="concat('0,', $current-value-of-required-live-neighbors-for-birth, ',8')"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>
            <xsl:when test="/grid/adjust-population = 'decrease'">
                <xsl:variable name="tmp-value-of-required-live-neighbors-for-birth">
                    <xsl:call-template name="delete-min">
                        <xsl:with-param name="s" select="$current-value-of-required-live-neighbors-for-birth"/>
                    </xsl:call-template>
                </xsl:variable>
                <xsl:variable name="new-value-of-required-live-neighbors-for-birth">
                    <xsl:call-template name="delete-max">
                        <xsl:with-param name="s" select="$tmp-value-of-required-live-neighbors-for-birth"/>
                    </xsl:call-template>
                </xsl:variable>
                <xsl:value-of select="$new-value-of-required-live-neighbors-for-birth"/>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="find-min">
        <xsl:param name="s"/>
        <xsl:choose>
            <xsl:when test="not(contains($s, ','))">
                <xsl:value-of select="$s"/>
<xsl:message>
   min = #<xsl:value-of select="$s"/>#
</xsl:message>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="substring-before($s, ',')"/>
<xsl:message>
   min = #<xsl:value-of select="substring-before($s, ',')"/>#
</xsl:message>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="find-max">
        <xsl:param name="s"/>
        <xsl:choose>
            <xsl:when test="not(contains($s, ','))">
                <xsl:value-of select="$s"/>
<xsl:message>
   max = #<xsl:value-of select="$s"/>#
</xsl:message>
            </xsl:when>
            <xsl:otherwise>
                <xsl:call-template name="find-max">
                    <xsl:with-param name="s" select="substring-after($s, ',')"/>
                </xsl:call-template>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="delete-min">
        <xsl:param name="s"/>
        <xsl:choose>
            <xsl:when test="not(contains($s, ','))">
                <xsl:value-of select="'3'"/>
<xsl:message>
   min = #<xsl:value-of select="$s"/>#
</xsl:message>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select="substring-after($s, ',')"/>
<xsl:message>
   min = #<xsl:value-of select="substring-after($s, ',')"/>#
</xsl:message>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

    <xsl:template name="delete-max">
        <xsl:param name="s"/>
        <xsl:choose>
            <xsl:when test="not(contains($s, ','))">
                <xsl:value-of select="'3'"/>
<xsl:message>
   max = #<xsl:value-of select="$s"/>#
</xsl:message>
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="tmp" select="substring-after($s, ',')"/>
                <xsl:choose>
                    <xsl:when test="not(contains($tmp, ','))">
                        <xsl:value-of select="substring-before($s, ',')"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:variable name="tmp2">
                            <xsl:call-template name="delete-max">
                                <xsl:with-param name="s" select="substring-after($s, ',')"/>
                            </xsl:call-template>
                        </xsl:variable>
                        <xsl:value-of select="concat(substring-before($s, ','), ',', $tmp2)"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>

</xsl:stylesheet>