Tough Problem 4 (VBA)

One interesting solution (or enhancement to the posted solutions) would be a closed path, the 64th movement would get us back to the starting point.

This solution would be interesting because we could choose any square on the board and visit all the other squares touching them only once, and this with one unique path.
 

Excel Facts

How can you turn a range sideways?
Copy the range. Select a blank cell. Right-click, Paste Special, then choose Transpose.
This is an example of a closed path solution.

Notice that after the 63 movements (number 64 in the table) you end up in B3. In the next jump you can go back to A1 and close the path.

With this solution you can start on whatever position you want and you have always 2 solutions to visit all the other squares in 63 movements, just follow the closed path in one of the 2 possible directions.

Since no one posted another solution I'll try to post one myself today or tomorrow. Since my first solution was similar to the one Andrew posted, I'll It try a brute force one but without recursion, using arrays to store the necessary information to do the backtracking.


<TABLE style="BORDER-TOP-WIDTH: 2px; BORDER-LEFT-WIDTH: 2px; FONT-SIZE: 10pt; BORDER-LEFT-COLOR: #cccccc; BACKGROUND: #fff; BORDER-BOTTOM-WIDTH: 2px; BORDER-BOTTOM-COLOR: #cccccc; BORDER-TOP-COLOR: #cccccc; FONT-FAMILY: Arial,Arial; BORDER-COLLAPSE: collapse; BORDER-RIGHT-WIDTH: 2px; BORDER-RIGHT-COLOR: #cccccc" cellPadding=1 border=1><TBODY><TR><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>A</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>B</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>C</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>D</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>E</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>F</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>G</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>H</TH><TH style="BORDER-TOP-WIDTH: 1px; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; BORDER-TOP-COLOR: #888888; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888" width=30>I</TH></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">1</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">1</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">12</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">9</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">6</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">3</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">14</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">17</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">20</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">2</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">10</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">7</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">2</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">13</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">18</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">21</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">4</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">15</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">3</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">33</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">64</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">11</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">8</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">5</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">16</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">19</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">22</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">4</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">28</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">25</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">34</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">63</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">40</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">23</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">56</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">61</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">5</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">35</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">32</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">27</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">24</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">57</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">62</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">39</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">44</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">6</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">26</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">29</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">50</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">41</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">38</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">45</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">60</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">55</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">7</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">51</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">36</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">31</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">48</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">53</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">58</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">43</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">46</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">8</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">30</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">49</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">52</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">37</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">42</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">47</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">54</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888">59</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #000000; BACKGROUND: #9cf; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #000000; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #000000; PADDING-TOP: 0.4em; TEXT-ALIGN: center; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #000000">9</TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD><TD style="BORDER-TOP-WIDTH: 1px; PADDING-RIGHT: 0.5em; PADDING-LEFT: 0.5em; BORDER-LEFT-WIDTH: 1px; BORDER-LEFT-COLOR: #888888; BORDER-BOTTOM-WIDTH: 1px; BORDER-BOTTOM-COLOR: #888888; PADDING-BOTTOM: 0.25em; BORDER-TOP-COLOR: #888888; PADDING-TOP: 0.4em; TEXT-ALIGN: right; BORDER-RIGHT-WIDTH: 1px; BORDER-RIGHT-COLOR: #888888"></TD></TR><TR><TD style="PADDING-LEFT: 1em; BACKGROUND: #9cf" colSpan=10>[Chess.xlsb]Closed loop</TD></TR></TBODY></TABLE>
 
One interesting solution (or enhancement to the posted solutions) would be a closed path

I took your challenge, and have succeeded in modifying Colin_L's solution, forcing it to reject open tours, try again until it finds a closed tours, and changed the rules to make the closed tour more likely. While open tours far outnumber closed tours, there are still millions of such tours. Colin's randomizing feature remains active, so run after run you get a unique closed tour. I started by cheating a little: realizing that by starting in the corner, we had only one candidate for "final move" (the possible "move #1" that wasn't taken), I decided to shift the start position to there. Warnsdorff's algorithm will send you into the corner automatically as move #1 anyway, and this gave me five candidates for "final move". Then, after much manual trial and error with various rules, I came up with two simple (thank goodness) rules that work almost every time. #1: In cases where the Warnsdorff algorithm results in a tie, before randomly breaking the tie you reject any candidates which are also "last move" candidates. If the tie is between two "last move" candidates, you'll have to pick one at random. (You want to save the "last move" candidates, using them up only when you have no other legal moves.) #2: Once you have used up all but one "last move" candidate, you avoid that square at all costs, even if it is the move with the lowest second-move score. Once I got it working, I opened up the random first-square selector to allow a starting square anywhere on the board.

I want to thank both Colin_L and Andrew Fergus for your solutions, I have learned a lot by picking apart what you did and modifying it.

Code:
Option Explicit
 
'grid rows and columns representing dimensions of the chess board
'change dimensions to suit (a traditional board is 8x8):
Const mlROW_COUNT As Long = 8
Const mlCOL_COUNT As Long = 8
 
'the maximum number of permissable attempts to solve the puzzle
'change max number of attempts to suit:
Const mlMAX_ATTEMPTS As Long = 10

'we will use C3 as the top left cell so that no moves can
'take us off the worksheet
Const msTOP_LEFT_CELL As String = "C3"
 
'a range representing a chess board
Dim mrngChessBoard As Range
Dim firstsquare As Range    'JDG: a range representing the knight's starting position
Dim finaleight As Range  'JDG: these are the eight squares to which the last move may go to acheive a closed tour
Dim finaleightcount As Integer  'JDG: how many of those eight squares are still available
Dim i As Integer

 
'the main sub to run to try to solve the puzzle
Public Sub Main()
    
    Dim lAttempts As Long  'a counter to monitor how many tries the algorithm has had
    Dim sMsg As String        'a report message
 
    'get a reference to a range which represents our chess board
        'In a new sheet:
        'Set mrngChessBoard = Worksheets.Add.Range(msTOP_LEFT_CELL).Resize(mlROW_COUNT, mlCOL_COUNT)
    
        'In the existing sheet:
        Set mrngChessBoard = ActiveSheet.Range(msTOP_LEFT_CELL).Resize(mlROW_COUNT, mlCOL_COUNT)
 
    'try to solve the puzzle
    Do
        'we must start with an empty board
        'mrngChessBoard.Clear
        clear_board
        mrngChessBoard.ClearContents
        lAttempts = lAttempts + 1
    Loop While KnightMoves <> (mlROW_COUNT * mlCOL_COUNT) And lAttempts < mlMAX_ATTEMPTS
    
    'tidy up the chess board presentation however you need to....
    mrngChessBoard.Columns.AutoFit
 
    'create a report message for the end user
    sMsg = "solved after " & lAttempts & " attempt": If lAttempts > 1 Then sMsg = sMsg & "s"
 
    'did we solve it? if not then adjust the report message....
    If lAttempts = mlMAX_ATTEMPTS Then sMsg = "NOT " & sMsg
 
    MsgBox sMsg
 
    'clean up
    Set mrngChessBoard = Nothing
    Set firstsquare = Nothing
 
End Sub
Sub clear_board()
'
' Macro4 Macro
' Macro recorded 1/23/2009 by John Gardner
'

'
    Range("C3").Interior.ColorIndex = xlNone
    Range("D3").Interior.ColorIndex = 15
    Range("C3:D3").Copy
    Range("E3:J3").PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
    Application.CutCopyMode = False
    Range("D3:E3").Copy
    Range("C4:J4").PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
    Application.CutCopyMode = False
    Range("C3:J4").Copy
    Range("C5:J10").PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
    Application.CutCopyMode = False
    Range("A1").Select
End Sub

 
'a function which moves the knight around the board and tracks the number of moves
Private Function KnightMoves() As Double
    Dim rngCurrent As Range     'a range representing the current position of the knight
    Dim rngSquare As Range
    
    'If we're repeating from a failed attempt, use the same starting square
    If Not firstsquare Is Nothing Then
        Set rngCurrent = firstsquare
    
    'otherwise let's take any random square on the board as our starting point
    Else
        Set rngCurrent = GetStartingSquare
        Set firstsquare = rngCurrent
    End If
    
    KnightMoves = 1
 
      'mark the starting square yellow
      With rngCurrent
        .Value = KnightMoves
        .Interior.Color = vbYellow
    End With
    
'Determine the cells from which a move to cell #1 is possible
'A closed tour must end on one of these cells.
Set finaleight = GetLegalMoves(rngCurrent)
finaleightcount = finaleight.Areas.Count

    'mark the final eight candidates green
    For Each rngSquare In finaleight.Areas
        With rngSquare
            .Interior.Color = vbGreen
        End With
    Next rngSquare

    'move the knight around the board until we run out of available squares
    Do
    
        Set rngCurrent = GetNextMove(rngCurrent)
    
        If Not rngCurrent Is Nothing Then
            KnightMoves = KnightMoves + 1
            rngCurrent.Value = KnightMoves
            If Not Intersect(rngCurrent, finaleight) Is Nothing Then finaleightcount = finaleightcount - 1
        Else
            Exit Do
        End If
    
    Loop
    
End Function
 
 
'use Warnsdorff's algorithm to determine the next move:
'--> we always move to the next square which itself has the
'least number of possible legal moves, unless it is the final member of the finaleight.
'In that case, we move to the second-least moves square.
'Ties are broken first by artificially inflating the number of legal moves of any
'finaleight candidate by 1/2 move (1/2 chosen to avoid creating a new tie), then by random selection.
'If we have used up all eight of the finaleight before move #64, start over.

Private Function GetNextMove(ByRef Square As Range) As Range
    Const bytMAXMOVES As Byte = 8 'the largest number of squares a knight can move to is 8
 
    Dim rngMove1 As Range   'looking one move ahead
    Dim rngMove2 As Range   'looking two moves ahead
    Dim rngSquare As Range  'a cell counter
    Dim bytNextMoveCounter As Byte 'track the least number of subsequent legal moves
    Dim thatcellmove As Double  'allow 1/2 move penalty for membership in finaleight
    Dim tiebreaker As Double  'to avoid last finaleight cell until no longer possible
 
    Set rngMove1 = GetLegalMoves(Square)
 
    'if there are no legal first moves then do nothing
    If rngMove1 Is Nothing Then
    'if used up all final eight possibilites then do nothing
    ElseIf finaleightcount = 0 Then
    'if there is only one legal move then we have to move there
    ElseIf rngMove1.Areas.Count = 1 Then
        
        Set GetNextMove = rngMove1
 
    'if there are multiple legal moves we have to determine
    'which is the best
    
    Else
 
        bytNextMoveCounter = bytMAXMOVES
 
        'loop through all the squares which are legal 1st moves
        For Each rngSquare In rngMove1.Areas
 
            'determine all the possible legal 2nd moves from the 1st move
            Set rngMove2 = GetLegalMoves(rngSquare)
 
            If Not rngMove2 Is Nothing Then
                With rngMove2.Areas
 
                    'if there are less 2nd moves from that square than
                    'any others we have checked then we want it
                    tiebreaker = 0.5
                    If finaleightcount = 1 Then tiebreaker = 8  'forces avoidance of last finaleight memeber
                    
                    thatcellmove = .Count
                    If Not Intersect(rngSquare, finaleight) Is Nothing Then thatcellmove = thatcellmove + tiebreaker
                    
                    'If .Count < bytNextMoveCounter Then
                    If thatcellmove < bytNextMoveCounter Then
                        bytNextMoveCounter = .Count
                        Set GetNextMove = rngSquare
 
                    'ElseIf .Count = bytNextMoveCounter Then
                    ElseIf thatcellmove = bytNextMoveCounter Then
 
                        'if two squares are equally viable let's randomly pick one
                        'so that our algorithm produces different results each time
                        Randomize
                        If Rnd >= 0.5 Then Set GetNextMove = rngSquare
 
                    End If
                
                End With
            End If
        Next rngSquare
 
    End If
 
 
End Function
 
'A function to get all the legal moves the knight can make
Private Function GetLegalMoves(ByRef Square As Range) As Range
    Dim rngCell As Range
    
    For Each rngCell In GetAllMoves(Square)
        If IsMoveLegal(rngCell) Then
 
            If GetLegalMoves Is Nothing Then
                Set GetLegalMoves = rngCell
            Else
                Set GetLegalMoves = Union(GetLegalMoves, rngCell)
            End If
 
        End If
    Next rngCell
    
End Function
 
'A function to determine if a move to a square is allowed
Private Function IsMoveLegal(ByRef Square As Range) As Boolean
    'has the square been visited yet?
    If IsEmpty(Square) Then
 
            'is the square on the chess board?
            If Not Intersect(Square, mrngChessBoard) Is Nothing Then IsMoveLegal = True
 
    End If
 
End Function
 
'A function to determine all the possible moves (legal or not) a knight could make
Private Function GetAllMoves(ByRef Square As Range) As Range
    With Square
        Set GetAllMoves = Union( _
                            .Offset(-2, -1), _
                            .Offset(-2, 1), _
                            .Offset(-1, -2), _
                            .Offset(-1, 2), _
                            .Offset(1, -2), _
                            .Offset(1, 2), _
                            .Offset(2, -1), _
                            .Offset(2, 1) _
                                )
    End With
End Function
 
'a function to determine a square on the chess board to start from
    
Private Function GetStartingSquare() As Range
 
    With mrngChessBoard
        'Full randomizer
        Dim sqrow As Integer
        Dim sqcol As Integer
        Randomize
        sqrow = Int(8 * Rnd) + 1
        Randomize
        sqcol = Int(8 * Rnd) + 1
        Set GetStartingSquare = .Cells(sqrow, sqcol)
        
    End With

End Function
 
Here are some samples of the closed tours generated. First, three unique solutions coming out of the same corner:
Knights Tour by Colin L, Closed by JDG.xls
ATAUAVAWAXAYAZBABBBCBDBEBFBGBHBIBJBKBLBMBNBOBPBQBRBS
3524114920331672872643309344522752452492855
4131053421581932252229835443110514623861542510
5405112213455617627245342334651621585344275629
6112263544318315623402136495211324750376257601126
7503946356257445205564154475061205485936433041
82364495845286130392374857601512492353863401512
938472253659427419645514176259419643314174231
10124374832629601383186358131613431839321316
Sheet43


Next, three solutions starting at random places on the board:
Knights Tour by Colin L, Closed by JDG.xls
ATAUAVAWAXAYAZBABBBCBDBEBFBGBHBIBJBKBLBMBNBOBPBQBRBS
122414196439141733013383320151852239543201756
135201401518633812412311417342140254216055219
14423446148591613294394237321916236593853185716
15216475245623758401146144512235264124615851481
162443224960511233528435061365752762335237641550
177282546533457361047845645560233427426332491247
18262330950553211276496225585356438293645103114
1929827543110355648926754632459283544930134611
Sheet43
 
If you tried to solve the Knights Tour problem manually I suspect that if you applied the logic of selecting the path with the least number of available moves, based on Colin's solution, then you could solve the puzzle at your first or second attempt.....it might be worth a go!
 
My rules that work "almost every time" -- well, that's on the standard 8x8 board. I played with it on higher order boards last night, and while it will generate solutions for boards up to a 32x32, it almost always requires multiple attempts. The 8x8 almost never does. On the 32x32 it sometimes takes up to twenty attempts to find a closed tour. I tried a 64x64, and after an hour and thousands of attempts, no solution. Here are examples of 16x16 and 24x24 solved by the macro:

3222220607_3b068e60a1.jpg


3223075242_25162942dd.jpg


I think that for a higher-order board, the avoidance routine needs to look deeper than the "last move" candidates (n-0), maybe as far as n-3 or n-4. Watching the 64x64 run, what is happening is it fills in seven of the eight "last move" candidates very quickly, then while avoiding the last one it fills in all the squares surrounding it, rendering it unreachable.
 
If you tried to solve the Knights Tour problem manually I suspect that if you applied the logic of selecting the path with the least number of available moves, based on Colin's solution, then you could solve the puzzle at your first or second attempt.....it might be worth a go!

Hi Andrew

You are right. I hadn't tried it manually, I thought it would very difficult.
I've just tried it in the site provided by Stephan in post 3, and using Colin's rule of thumb. I did it at the 3rd attempt. This rule of thumb is really efficient!

Cheers
Pedro
 
Hi gardnertoo

I can only say: great job!!!

I tried the code several times and got the result in under a second. I haven't been able to study Colin's solution and yours but i'll surely do it in the next days. I really think this is a very interesting method and it's worth understanding exactly how it works, who knows if it won't come in handy in another completely different context.

I think that for a higher-order board, the avoidance routine needs to look deeper than the "last move" candidates (n-0), maybe as far as n-3 or n-4.

I agree with you. This is also what I'd try.

Cheers
Pedro
 
Well, we've already got great solutions in this thread and it's time to make some comments.

- Andrew's solution is a good example of a brute force solution using recursion and this is the quickest and simplest way to get to the result if you just need to run the code a few times and can't or don't want to spend the time necessary to figure out a non brute force solution. This was also my first solution, recursion really comes in handy for this type of problems.

- Colin's and gardnertoo's solutions using Warnsdorff's algorithm show how studying a problem and figuring out a non brute force method can dramatically improve the response time. This is what you'll do if you need a solution that will be used lots of times by lots of people. In such a case it may be not acceptable to wait 1 minute to get the response and it pays to have someone studying the problem to figure out an efficient method that will reduce the code response time.

I will post a different type of solution. This is a minimalist solution. If you didn't know or understand recursion and didn't know any specific method to solve the problem you still could write code to solve the problem using brute force with just 1 loop.

Code:
Option Explicit
 
Const lRows As Long = 6       ' board number of rows
Const lColumns As Long = 6   ' board number of columns
Const lTotal As Long = lRows * lColumns
 
Sub Knight()
Dim lMov As Long
Dim lR As Long, lC As Long
Dim lMovArr(1 To lRows, 1 To lColumns) As Long         ' number of the move when visiting square
Dim lPos(1 To lTotal, 1 To 2) As Long                       ' position on the board in move n
Dim lOff(1 To lTotal) As Long                                  ' offset index in move
Dim vNext                                                           ' offsets to the next positions
 
lMovArr(1, 1) = 1
lPos(1, 1) = 1                                                      ' starts from top left
lPos(1, 2) = 1                                                      ' starts from top left
lMov = 2
 
vNext = [{-2,-1;-2,1;-1,-2;-1,2;1,-2;1,2;2,-1;2,1}]
 
Do
    If lOff(lMov) < 8 Then
        lOff(lMov) = lOff(lMov) + 1                                   ' try next offsets
        lR = lPos(lMov - 1, 1) + vNext(lOff(lMov), 1)            ' row in next move
        lC = lPos(lMov - 1, 2) + vNext(lOff(lMov), 2)            ' column in next move
 
        If (lR >= 1 And lR <= lRows) And (lC >= 1 And lC <= lColumns) Then ' inside the board
            If lMovArr(lR, lC) = 0 Then                                                    ' if square is free
                lMovArr(lR, lC) = lMov
                lPos(lMov, 1) = lR
                lPos(lMov, 2) = lC
                If lMov = lTotal Then Range("A1").Resize(lRows, lColumns).Value = lMovArr ' success
                lMov = lMov + 1
            End If
        End If
    Else                                                                                ' no moves possible
        lOff(lMov) = 0
        lMov = lMov - 1
        lMovArr(lPos(lMov, 1), lPos(lMov, 2)) = 0
    End If
Loop While (lMov <> 1) And (lMov <= lTotal)
If lMov = 1 Then MsgBox "Failed"
End Sub

I thank everyone that contributed to this thread. I really think we have very good solutions here.

Cheers
Pedro
 
Last edited:
It turns out that on a 64x64 board, I had to project backwards to move n-16 to reliably find a solution in fewer than ten attempts. On the 32x32 board, n-8 will get there in five or fewer attempts, with n-12 usually requiring only one or two tries. Here's the code, and I promise I'm done:

Code:
Option Explicit
 
'grid rows and columns representing dimensions of the chess board
'change dimensions to suit (a traditional board is 8x8):
Const mlROW_COUNT As Long = 32
Const mlCOL_COUNT As Long = 32
 
'the maximum number of permissable attempts to solve the puzzle
'change max number of attempts to suit:
Const mlMAX_ATTEMPTS As Long = 10

'the number of moves to look ahead
'change to suit:
Const levels As Integer = 12

'we will use C3 as the top left cell so that no moves can
'take us off the worksheet
Const msTOP_LEFT_CELL As String = "C3"
 
'a range representing a chess board
Dim mrngChessBoard As Range
Dim firstsquare As Range    'JDG: a range representing the knight's starting position
Dim finalsquares(levels) As Range  'JDG: these are the squares to which move n-x may go to acheive a closed tour
Dim finalsquarescount(levels) As Integer  'JDG: how many of those squares are still available
Dim finalsquarestemp(levels) As Range  'JDG: finalsquares set before removing overlap with lower levels
Dim i As Integer

 
'the main sub to run to try to solve the puzzle
Public Sub Main()
    
    Dim lAttempts As Long  'a counter to monitor how many tries the algorithm has had
    Dim sMsg As String        'a report message
    Dim exitMsg As String   'alert user to board size
    
    exitMsg = "Board size " & mlROW_COUNT & " x " & mlCOL_COUNT & ", looking ahead " & levels & " moves."
    If MsgBox(exitMsg, vbOKCancel, "WARNING") = vbCancel Then Exit Sub
    
 
    'get a reference to a range which represents our chess board
        'In a new sheet:
        'Set mrngChessBoard = Worksheets.Add.Range(msTOP_LEFT_CELL).Resize(mlROW_COUNT, mlCOL_COUNT)
    
        'In the existing sheet:
        Set mrngChessBoard = ActiveSheet.Range(msTOP_LEFT_CELL).Resize(mlROW_COUNT, mlCOL_COUNT)
 
    'try to solve the puzzle
    Do
        'we must start with an empty board
        'mrngChessBoard.Clear
        clear_board
        mrngChessBoard.ClearContents
        'Application.ScreenUpdating = False
        Range(Cells(101, 2), Cells((mlROW_COUNT * mlCOL_COUNT) + 101, 3)).Value = Range(Cells(101, 12), Cells((mlROW_COUNT * mlCOL_COUNT) + 101, 13)).Value
        Range(Cells(101, 12), Cells((mlROW_COUNT * mlCOL_COUNT) + 101, 13)).ClearContents
        lAttempts = lAttempts + 1
        
    Loop While KnightMoves <> (mlROW_COUNT * mlCOL_COUNT) And lAttempts < mlMAX_ATTEMPTS
        'Application.ScreenUpdating = True
    'tidy up the chess board presentation however you need to....
    'mrngChessBoard.Columns.AutoFit
    Range(Cells(101, 2), Cells((mlROW_COUNT * mlCOL_COUNT) + 101, 3)).Value = Range(Cells(101, 12), Cells((mlROW_COUNT * mlCOL_COUNT) + 101, 13)).Value
    'create a report message for the end user
    sMsg = "solved after " & lAttempts & " attempt": If lAttempts > 1 Then sMsg = sMsg & "s"
 
    'did we solve it? if not then adjust the report message....
    If lAttempts = mlMAX_ATTEMPTS Then sMsg = "NOT " & sMsg
 
    MsgBox sMsg
 
    'clean up
    Set mrngChessBoard = Nothing
    Set firstsquare = Nothing
    For i = 0 To levels
        Set finalsquares(i) = Nothing
        Set finalsquarestemp(i) = Nothing
    Next i
       
 
End Sub
Private Sub clear_board()
'
' Macro4 Macro
' Macro recorded 1/23/2009 by John Gardner
'

'
    Range("C3").Interior.ColorIndex = xlNone
    Range("D3").Interior.ColorIndex = 15
    Range("C3:D3").Copy
    Range(Cells(3, 5), Cells(3, mlCOL_COUNT + 2)).PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
    Application.CutCopyMode = False
    Range("D3:E3").Copy
    Range(Cells(4, 3), Cells(4, mlCOL_COUNT + 2)).PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
    Application.CutCopyMode = False
    Range(Cells(3, 2), Cells(4, mlCOL_COUNT + 2)).Copy
    Range(Cells(5, 2), Cells(mlROW_COUNT + 2, mlCOL_COUNT + 2)).PasteSpecial Paste:=xlPasteFormats, Operation:=xlNone, _
        SkipBlanks:=False, Transpose:=False
    Application.CutCopyMode = False
    Range("A1").Select
End Sub

 
'a function which moves the knight around the board and tracks the number of moves
Private Function KnightMoves() As Double
    Dim rngCurrent As Range     'a range representing the current position of the knight
    Dim rngSquare As Range
    
    'If we're repeating from a failed attempt, use the same starting square
    'If Not firstsquare Is Nothing Then
        'Set rngCurrent = firstsquare
    
    'otherwise let's take any random square on the board as our starting point
    'Else
        Set rngCurrent = GetStartingSquare
        Set firstsquare = rngCurrent
    'End If
    
    KnightMoves = 1
 
      'mark the starting square red
      With rngCurrent
        .Value = KnightMoves
        '.Interior.Color = vbRed
      End With
    
'Determine the cells from which a move to cell #1 is possible
'A closed tour must end on one of these cells.
For i = 0 To levels
    Set finalsquares(i) = Nothing
    Set finalsquarestemp(i) = Nothing
Next i
Set finalsquares(0) = firstsquare
Set finalsquarestemp(0) = finalsquares(0)
finalsquarescount(0) = 1
Set finalsquares(1) = GetLegalMoves(rngCurrent)
Set finalsquarestemp(1) = finalsquares(1)
finalsquarescount(1) = finalsquares(1).Areas.Count

'********************Lookahead*******************************
    For i = 1 To levels
    For Each rngSquare In finalsquarestemp(i - 1).Areas
        If finalsquarestemp(i) Is Nothing Then
            Set finalsquarestemp(i) = GetLegalMoves(rngSquare)
        Else
            Set finalsquarestemp(i) = Union(finalsquarestemp(i), GetLegalMoves(rngSquare))
        End If
    Next rngSquare
    
    For Each rngSquare In finalsquarestemp(i)
        If i > 1 Then
            If Intersect(finalsquarestemp(i - 2), rngSquare) Is Nothing Then
                If finalsquares(i) Is Nothing Then
                    Set finalsquares(i) = rngSquare
                Else
                    Set finalsquares(i) = Union(finalsquares(i), rngSquare)
                End If
            End If
        End If
    Next rngSquare
    'audit
    Cells(100 + i, 5).Value = finalsquares(i).Areas.Count
    
Next i
Dim colortouse As Integer
'color code the levels of lastmove(x) in the display
For i = 1 To levels
    colortouse = GetSquareColor(i)
    For Each rngSquare In finalsquares(i).Areas
    rngSquare.Interior.ColorIndex = colortouse
    Next rngSquare
Next i

        'color code the inner three, and outermost, levels of lastmove(x)
        'For i = 1 To 3
            'colortouse = GetSquareColor(i)
            'For Each rngSquare In finalsquares(i).Areas
            'rngSquare.Interior.ColorIndex = colortouse
            'Next rngSquare
        'Next i
        'For Each rngSquare In finalsquares(levels).Areas
            'rngSquare.Interior.ColorIndex = 9
        'Next rngSquare
        
'******************************************************************


    'move the knight around the board until we run out of available squares
    Do
        'data table for graphical move display
        Cells(KnightMoves + 100, 12) = rngCurrent.Column - 2
        Cells(KnightMoves + 100, 13) = rngCurrent.Row - 2
    
        'Set rngCurrent = GetNextMove(rngCurrent, levels)
        Set rngCurrent = GetNextMove(rngCurrent)
        
        If Not rngCurrent Is Nothing Then
            KnightMoves = KnightMoves + 1
            rngCurrent.Value = KnightMoves
            For i = 1 To levels
                If Not Intersect(rngCurrent, finalsquares(i)) Is Nothing Then finalsquarescount(i) = finalsquarescount(i) - 1
            Next i
        Else
            Exit Do
        End If
    Loop
    
End Function
 
 
'use Warnsdorff's algorithm to determine the next move:
'--> we always move to the next square which itself has the
'least number of possible legal moves, unless it is the final member of any finalsquares(x).
'In that case, we move to the second-least moves square.
'Ties are broken first by artificially inflating the number of legal moves of any
'finalsquares(x) candidate by larger amounts as the (x) decreases, then by random selection.
'If we have used up all eight of the finalsquares(1) before move #64, start over.

'Private Function GetNextMove(ByRef Square As Range, levels As Integer) As Range
Private Function GetNextMove(ByRef Square As Range) As Range

    Const bytMAXMOVES As Integer = 1000 'the largest number of squares a knight can move to is 8
 
    Dim rngMove1 As Range   'looking one move ahead
    Dim rngMove2 As Range   'looking two moves ahead
    Dim rngSquare As Range  'a cell counter
    Dim bytNextMoveCounter As Double 'track the least number of subsequent legal moves
    Dim thatcellmove As Double  'allow penalty for membership in finalsquares(x)
    Dim tiebreaker(levels) As Double  'to avoid last finalsquares(x) cell until no longer possible
 
    Set rngMove1 = GetLegalMoves(Square)
 
    'if there are no legal first moves then do nothing
    If rngMove1 Is Nothing Then
        Range("AB68").Value = "No legal moves"
    'if used up all final eight possibilites then do nothing
    ElseIf finalsquarescount(1) = 0 Then
        Range("AB68").Value = "All used up"
    'if there is only one legal move then we have to move there
    ElseIf rngMove1.Areas.Count = 1 Then
        Range("AB68").Value = "One legal move"
        Set GetNextMove = rngMove1
 
    'if there are multiple legal moves we have to determine
    'which is the best
    
    Else
        Range("AB68").Value = "Multiple legal moves"
        bytNextMoveCounter = bytMAXMOVES
 
        'loop through all the squares which are legal 1st moves
        For Each rngSquare In rngMove1.Areas
 
            'determine all the possible legal 2nd moves from the 1st move
            Set rngMove2 = GetLegalMoves(rngSquare)
 
            If Not rngMove2 Is Nothing Then
                With rngMove2.Areas
 
                    'if there are less 2nd moves from that square than
                    'any others we have checked then we want it
                    tiebreaker(1) = 0.5
                    If finalsquarescount(1) = 1 Then tiebreaker(1) = 6.5  'forces avoidance of last finalsquares(1) memeber
                    If Not Intersect(rngSquare, finalsquares(1)) Is Nothing Then thatcellmove = thatcellmove + tiebreaker(1)
                    
                    thatcellmove = .Count
                    'For i = 1 To levels
                    For i = levels To 1 Step -1
                        tiebreaker(i) = (0 + levels - i) / levels
                        If finalsquarescount(1) = 1 Then tiebreaker(i) = 6.5 + ((0 + levels - i) / levels)
                        If Not Intersect(rngSquare, finalsquares(i)) Is Nothing Then thatcellmove = .Count + tiebreaker(i)
                    Next i
                    
                    
                    If thatcellmove < bytNextMoveCounter Then
                        bytNextMoveCounter = thatcellmove
                        Set GetNextMove = rngSquare
 
                    ElseIf thatcellmove = bytNextMoveCounter Then
 
                        'if two squares are equally viable let's randomly pick one
                        'so that our algorithm produces different results each time
                        Randomize
                        If Rnd >= 0.5 Then Set GetNextMove = rngSquare
 
                    End If
                
                End With
            End If
        Range("AB68").Value = "Legal moves: " & rngMove1.Areas.Count
        Next rngSquare
        
    End If
 
End Function
 
'A function to get all the legal moves the knight can make
Private Function GetLegalMoves(ByRef Square As Range) As Range
    Dim rngCell As Range
    
    For Each rngCell In GetAllMoves(Square)
        If IsMoveLegal(rngCell) Then
 
            If GetLegalMoves Is Nothing Then
                Set GetLegalMoves = rngCell
            Else
                Set GetLegalMoves = Union(GetLegalMoves, rngCell)
            End If
 
        End If
    Next rngCell
    
End Function
 
'A function to determine if a move to a square is allowed
Private Function IsMoveLegal(ByRef Square As Range) As Boolean
    'has the square been visited yet?
    If IsEmpty(Square) Then
 
            'is the square on the chess board?
            If Not Intersect(Square, mrngChessBoard) Is Nothing Then IsMoveLegal = True
 
    End If
 
End Function
 
'A function to determine all the possible moves (legal or not) a knight could make
Private Function GetAllMoves(ByRef Square As Range) As Range
    With Square
        Set GetAllMoves = Union( _
                            .Offset(-2, -1), _
                            .Offset(-2, 1), _
                            .Offset(-1, -2), _
                            .Offset(-1, 2), _
                            .Offset(1, -2), _
                            .Offset(1, 2), _
                            .Offset(2, -1), _
                            .Offset(2, 1) _
                                )
    End With
End Function
 
'a function to determine a square on the chess board to start from
    
Private Function GetStartingSquare() As Range
 
    With mrngChessBoard
        'Full randomizer
        Dim sqrow As Integer
        Dim sqcol As Integer
        Randomize
        sqrow = Int(mlROW_COUNT * Rnd) + 1
        Randomize
        sqcol = Int(mlCOL_COUNT * Rnd) + 1
        Set GetStartingSquare = .Cells(sqrow, sqcol)
        'non random
        'Set GetStartingSquare = .Cells(mlROW_COUNT / 2, mlCOL_COUNT / 2)
        
    End With

End Function


Private Function GetSquareColor(ByRef level As Integer) As Integer
Dim x As Integer

    Select Case level
        Case 17
            x = 13
        Case 16
            x = 54
        Case 15
            x = 39
        Case 14
            x = 34
        Case 13
            x = 8
        Case 12
            x = 42
        Case 11
            x = 5
        Case 10
            x = 14
        Case 9
            x = 4
        Case 8
            x = 12
        Case 7
            x = 43
        Case 6
            x = 6
        Case 5
            x = 40
        Case 4
            x = 44
        Case 3
            x = 45
        Case 2
            x = 46
        Case 1
            x = 3
    End Select
GetSquareColor = x

End Function
 

Forum statistics

Threads
1,222,647
Messages
6,167,322
Members
452,110
Latest member
eui

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top