What the Knight’s Tour might look like in XSLT 3.0?

At the time of writing XSL Transformations (XSLT) Version 3.0 (W3C Working Draft 10 July 2012) is still a working draft. I can’t test this, but this is my estimate of what a solution for the Knight’s tour might look like in XSLT 3.0  .d

First we build a generic package for solving any kind of tour over the chess board. Here it is…
(Updated 31-Oct-2012)

<br />&lt;xsl:package xsl:version="3.0"<br />  xmlns:xsl=&amp;amp;quot;http://www.w3.org/1999/XSL/Transform&amp;amp;quot;<br />  xmlns:xs=&amp;amp;quot;http://www.w3.org/2001/XMLSchema&amp;amp;quot;<br />  xmlns:fn=&amp;amp;quot;http://www.w3.org/2005/xpath-functions&amp;amp;quot;<br />  xmlns:tour=&amp;amp;quot;http://www.seanbdurkin.id.au/tour&amp;amp;quot;<br />  name=&amp;amp;quot;tour:tours&amp;amp;quot;&amp;amp;gt;<br />&amp;amp;lt;xsl:stylesheet&amp;amp;gt;<br />  &amp;amp;lt;xsl:function name=&amp;amp;quot;tour:manufacture-square&amp;amp;quot;<br />       as=&amp;amp;quot;element(square)&amp;amp;quot; visibility=&amp;amp;quot;public&amp;amp;quot;&amp;amp;gt;<br />    &amp;amp;lt;xsl:param name=&amp;amp;quot;rank&amp;amp;quot; as=&amp;amp;quot;xs:integer&amp;amp;quot; /&amp;amp;gt;<br />    &amp;amp;lt;xsl:param name=&amp;amp;quot;file&amp;amp;quot; as=&amp;amp;quot;xs:integer&amp;amp;quot; /&amp;amp;gt;<br />    &amp;amp;lt;square file=&amp;amp;quot;$file&amp;amp;quot; rank=&amp;amp;quot;$rank&amp;amp;quot; /&amp;amp;gt;<br />  &amp;amp;lt;/xsl:function&amp;amp;gt;<br /><br />  &amp;amp;lt;xsl:function name=&amp;amp;quot;tour:on-board&amp;amp;quot; as=&amp;amp;quot;xs:boolean&amp;amp;quot; visibility=&amp;amp;quot;public&amp;amp;quot;&amp;amp;gt;<br />    &amp;amp;lt;xsl:param name=&amp;amp;quot;rank&amp;amp;quot; as=&amp;amp;quot;xs:integer&amp;amp;quot; /&amp;amp;gt;<br />    &amp;amp;lt;xsl:param name=&amp;amp;quot;file&amp;amp;quot; as=&amp;amp;quot;xs:integer&amp;amp;quot; /&amp;amp;gt;<br />    &amp;amp;lt;xsl:copy-of select=&amp;amp;quot;($rank ge 1) and ($rank le 8) and<br />                         ($file ge 1) and ($file le 8)&amp;amp;quot; /&amp;amp;gt;<br />  &amp;amp;lt;/xsl:function&amp;amp;gt;<br /><br />  &amp;amp;lt;xsl:function name=&amp;amp;quot;tour:solve-tour&amp;amp;quot; as=&amp;amp;quot;item()*&amp;amp;quot; visibility=&amp;amp;quot;public&amp;amp;quot;&amp;amp;gt;<br />    &amp;amp;lt;!-- Solves the tour for any specified piece. --&amp;amp;gt;<br />    &amp;amp;lt;!-- Outputs either a full solution of 64 squares, of if fail,<br />         a copy of the $state input. --&amp;amp;gt;<br />    &amp;amp;lt;xsl:param name=&amp;amp;quot;state&amp;amp;quot; as=&amp;amp;quot;item()+&amp;amp;quot; /&amp;amp;gt;<br />    &amp;amp;lt;xsl:variable name=&amp;amp;quot;compute-possible-moves&amp;amp;quot;<br />      select=&amp;amp;quot;$state[. instance of function(*)]&amp;amp;quot;<br />	  as=&amp;amp;quot;function(element(square)) as element(square)*&amp;amp;quot;&amp;amp;gt;<br />    &amp;amp;lt;xsl:variable name=&amp;amp;quot;way-points&amp;amp;quot; select=&amp;amp;quot;$state/self::square&amp;amp;quot; /&amp;amp;gt;<br />    &amp;amp;lt;xsl:choose&amp;amp;gt;<br />      &amp;amp;lt;xsl:when test=&amp;amp;quot;count($way-points) eq 64&amp;amp;quot;&amp;amp;gt;<br />        &amp;amp;lt;xsl:sequence =&amp;amp;quot;$state&amp;amp;quot; /&amp;amp;gt;<br />      &amp;amp;lt;/xsl:when&amp;amp;gt;<br />      &amp;amp;lt;xsl:otherwise&amp;amp;gt;<br />        &amp;amp;lt;xsl:sequence select=&amp;amp;quot;<br />	  let $try-move := function( $state as item()*, $move as item()) as item()*)<br />	        {<br />	         if $state/self::square[@file=$move/@file]<br />	                               [@rank=$move/@rank]<br />	           then $state<br />	           else tour:solve-tour( ( $state, $move) )<br />                },<br />              $possible-moves := $compute-possible-moves( $way-points[last()])<br />	      return if empty( $possible-moves) then $state<br />                     else fn:fold-left( $try-move, $state, $possible-moves)&amp;amp;quot; /&amp;amp;gt;<br />      &amp;amp;lt;/xsl:otherwise&amp;amp;gt;<br />    &amp;amp;lt;/xsl:choose&amp;amp;gt;<br />  &amp;amp;lt;/xsl:variable&amp;amp;gt;&amp;amp;lt;/xsl:function&amp;amp;gt;<br />&amp;amp;lt;/xsl:stylesheet&amp;amp;gt;<br /><br />&amp;amp;lt;xsl:expose component=&amp;amp;quot;function&amp;amp;quot;<br />  names=&amp;amp;quot;tour:manufacture-square tour:on-board tour:solve-tour&amp;amp;quot;<br />  visibility=&amp;amp;quot;public&amp;amp;quot; /&amp;amp;gt;<br /><br />&amp;amp;lt;/xsl:package&amp;amp;gt;<br />
The Knight's Tour

And now for the style-sheet to solve the Knight’s tour…

&amp;lt;xsl:stylesheet version=&amp;quot;3.0&amp;quot;
  xmlns:xsl=&amp;quot;http://www.w3.org/1999/XSL/Transform&amp;quot;
  xmlns:xs=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;
  xmlns:fn=&amp;quot;http://www.w3.org/2005/xpath-functions&amp;quot;
  xmlns:tour=&amp;quot;http://www.seanbdurkin.id.au/tour&amp;quot;
  exclude-result-prefixes=&amp;quot;xsl fn xs tour&amp;quot;&amp;gt;
&amp;lt;xsl:use-package name=&amp;quot;tour:tours&amp;quot; /&amp;gt;
&amp;lt;xsl:output indent=&amp;quot;yes&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; omit-xml-declaration=&amp;quot;yes&amp;quot; /&amp;gt;
&amp;lt;xsl:mode on-no-match=&amp;quot;shallow-copy&amp;quot; streamable=&amp;quot;yes&amp;quot;/&amp;gt;

&amp;lt;xsl:template match=&amp;quot;knight[square]&amp;quot;&amp;gt;
  &amp;lt;xsl:variable name=&amp;quot;error&amp;quot;&amp;gt;
    &amp;lt;error&amp;gt;Failed to find solution to Knight's Tour.&amp;lt;/error&amp;gt;
  &amp;lt;/xsl:variable&amp;gt;
  &amp;lt;xsl:copy&amp;gt;
    &amp;lt;xsl:copy-of select=&amp;quot;
    let $final-state := tour:solve-tour((
    function( $piece-position as element(square)) as element(square)*
      { (: This function defines a knight's move. :)
	    let $r0 := number( $piece-position/@rank),
	    let $f0 := number( $piece-position/@file),
	    for $r in -2..2, $f in -2..2 return
		  if (abs($r) + abs($f) eq 3) and
		     tour:on-board($r+$r0, $f+$f0) then
		    tour:manufacture-square($r+$r0, $f+$f0)
	      else ()
	  }
      , current()/square)),
     $solution := $final-state/self::square
    return if count($solution) eq 64 then $solution
           else $error/*&amp;quot; /&amp;gt;
  &amp;lt;/xsl:copy&amp;gt;
&amp;lt;/xsl:template&amp;gt;

&amp;lt;!-- Add templates for other piece types if you want to solve
     their tours too. Solve by calling tour:solve-tour() .    --&amp;gt;

&amp;lt;/xsl:stylesheet&amp;gt;

So an input like this…

&amp;lt;tt&amp;gt;
 &amp;lt;knight&amp;gt;
   &amp;lt;square file=&amp;quot;1&amp;quot; rank=&amp;quot;1&amp;quot; /&amp;gt;
 &amp;lt;/knight&amp;gt;
&amp;lt;/tt&amp;gt;

…should be transformed in something like this…

&amp;lt;tt&amp;gt;
 &amp;lt;knight&amp;gt;
   &amp;lt;square file=&amp;quot;1&amp;quot; rank=&amp;quot;1&amp;quot; /&amp;gt;
   &amp;lt;square file=&amp;quot;2&amp;quot; rank=&amp;quot;3&amp;quot; /&amp;gt;
   &amp;lt;square file=&amp;quot;1&amp;quot; rank=&amp;quot;5&amp;quot; /&amp;gt;
   ... etc for 64 squares.
 &amp;lt;/knight&amp;gt;
&amp;lt;/tt&amp;gt;
This entry was posted in XSLT 3.0 and tagged , . Bookmark the permalink.