cws/cw02.tex
changeset 50 9891c9fac37e
parent 48 7a6a75ea9738
child 59 8e866d0af03a
equal deleted inserted replaced
49:fdc2c6fb7a24 50:9891c9fac37e
    14 
    14 
    15 \mbox{}\\[-18mm]\mbox{}
    15 \mbox{}\\[-18mm]\mbox{}
    16 
    16 
    17 \section*{Coursework 7 (Scala, Knight's Tour)}
    17 \section*{Coursework 7 (Scala, Knight's Tour)}
    18 
    18 
    19 This coursework is about searching and backtracking, and worth
    19 This coursework is worth 10\%. It is about searching and
    20 10\%. The first part is due on 23 November at 11pm; the second, more
    20 backtracking. The first part is due on 23 November at 11pm; the
    21 advanced part, is due on 30 November at 11pm. You are asked to
    21 second, more advanced part, is due on 30 November at 11pm. You are
    22 implement Scala programs that solve various versions of the
    22 asked to implement Scala programs that solve various versions of the
    23 \textit{Knight's Tour Problem} on a chessboard. Make sure the files
    23 \textit{Knight's Tour Problem} on a chessboard. Make sure the files
    24 you submit can be processed by just calling \texttt{scala
    24 you submit can be processed by just calling \texttt{scala
    25   <<filename.scala>>}.
    25   <<filename.scala>>}.\bigskip
       
    26 
       
    27 \noindent
       
    28 \textbf{Important:} Do not use any mutable data structures in your
       
    29 submissions! They are not needed. This excluded the use of
       
    30 \texttt{ListBuffer}s, for example. Do not use \texttt{return} in your
       
    31 code! It has a different meaning in Scala, than in Java.  Feel free to
       
    32 copy any code you need from files \texttt{knight1.scala},
       
    33 \texttt{knight2.scala} and \texttt{knight3.scala}. Make sure the
       
    34 functions you submit are defined on the ``top-level'' of Scala, not
       
    35 inside a class or object.
    26  
    36  
    27 \subsection*{Disclaimer}
    37 \subsection*{Disclaimer}
    28 
    38 
    29 It should be understood that the work you submit represents
    39 It should be understood that the work you submit represents
    30 your own effort. You have not copied from anyone else. An
    40 your own effort. You have not copied from anyone else. An
    76 A knight's tour is called \emph{closed}, if the last step in the tour
    86 A knight's tour is called \emph{closed}, if the last step in the tour
    77 is within a knight's move to the beginning of the tour. So the above
    87 is within a knight's move to the beginning of the tour. So the above
    78 knight's tour is \underline{not} closed (it is open) because the last
    88 knight's tour is \underline{not} closed (it is open) because the last
    79 step on field $(0, 4)$ is not within the reach of the first step on
    89 step on field $(0, 4)$ is not within the reach of the first step on
    80 $(4, 4)$. It turns out there is no closed knight's tour on a $5\times
    90 $(4, 4)$. It turns out there is no closed knight's tour on a $5\times
    81 5$ board. But there are on a $6\times 6$ board and bigger, for example
    91 5$ board. But there are on a $6\times 6$ board and on bigger ones, for
       
    92 example
    82 
    93 
    83 \chessboard[maxfield=e5, 
    94 \chessboard[maxfield=e5, 
    84             pgfstyle= {[base,at={\pgfpoint{0pt}{-0.5ex}}]text},
    95             pgfstyle= {[base,at={\pgfpoint{0pt}{-0.5ex}}]text},
    85             text = \small 10, markfield=Z5,
    96             text = \small 10, markfield=Z5,
    86             text = \small  5, markfield=a5,
    97             text = \small  5, markfield=a5,
   144             markfields={a4, c4, Z3, d3, Z1, d1, a0, c0},
   155             markfields={a4, c4, Z3, d3, Z1, d1, a0, c0},
   145             color=red!50,
   156             color=red!50,
   146             markfields={f5, e6},
   157             markfields={f5, e6},
   147             setpieces={Ng7, Nb2}]
   158             setpieces={Ng7, Nb2}]
   148 
   159 
   149 \subsection*{Part 1 (6 Marks)}
   160 \subsection*{Part 1 (7 Marks)}
   150 
   161 
   151 You are asked to implement the knight's tour problem such that the
   162 You are asked to implement the knight's tour problem such that the
   152 dimension of the board can be changed.  Therefore most functions will
   163 dimension of the board can be changed.  Therefore most functions will
   153 take the dimension as an argument.  The fun with this problem is that
   164 take the dimension of the board as an argument.  The fun with this
   154 even for small chessbord dimensions it has already an incredably large
   165 problem is that even for small chessbord dimensions it has already an
   155 search space---finding a tour is like finding a needle in a
   166 incredably large search space---finding a tour is like finding a
   156 haystack. In the first task we want to see far we get with
   167 needle in a haystack. In the first task we want to see how far we get
   157 exhaustively exploring the complete search space for small
   168 with exhaustively exploring the complete search space for small
   158 chessboards.\medskip
   169 chessboards.\medskip
   159 
   170 
   160 \noindent
   171 \noindent
   161 Let us first fix the basic datastructures for the implementation.  The
   172 Let us first fix the basic datastructures for the implementation.  The
   162 board dimension is an integer (we will never go boyond board sizes of
   173 board dimension is an integer (we will never go boyond board sizes of
   181 
   192 
   182 
   193 
   183 \subsubsection*{Tasks (file knight1.scala)}
   194 \subsubsection*{Tasks (file knight1.scala)}
   184 
   195 
   185 \begin{itemize}
   196 \begin{itemize}
   186 \item[(1a)] Implement a is-legal-move function that takes a dimension, a path
   197 \item[(1a)] Implement an is-legal-move function that takes a
   187 and a position as argument and tests whether the position is inside
   198   dimension, a path and a position as argument and tests whether the
   188 the board and not yet element in the path. \hfill[1 Mark]
   199   position is inside the board and not yet element in the
       
   200   path. \hfill[1 Mark]
   189 
   201 
   190 \item[(1b)] Implement a legal-moves function that calculates for a
   202 \item[(1b)] Implement a legal-moves function that calculates for a
   191   position all legal onward moves. If the onward moves are
   203   position all legal onward moves. If the onward moves are
   192   placed on a circle, you should produce them starting from
   204   placed on a circle, you should produce them starting from
   193   ``12-oclock'' following in clockwise order.  For example on an
   205   ``12-oclock'' following in clockwise order.  For example on an
   194   $8\times 8$ board for a knight on position $(2, 2)$ and otherwise
   206   $8\times 8$ board for a knight on position $(2, 2)$ and otherwise
   195   empty board, the legal-moves function should produce the onward
   207   empty board, the legal-moves function should produce the onward
   196   positions
   208   positions in this order:
   197 
   209 
   198   \begin{center}
   210   \begin{center}
   199   \texttt{List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4))}
   211   \texttt{List((3,4), (4,3), (4,1), (3,0), (1,0), (0,1), (0,3), (1,4))}
   200   \end{center}
   212   \end{center}
   201 
   213 
   202   in this order.  If the board is not empty, then maybe some of the
   214   If the board is not empty, then maybe some of the moves need to be
   203   moves need to be filtered out from this list.  For a knight on field
   215   filtered out from this list.  For a knight on field $(7, 7)$ and an
   204   $(7, 7)$ and an empty board, the legal moves are
   216   empty board, the legal moves are
   205 
   217 
   206   \begin{center}
   218   \begin{center}
   207   \texttt{List((6,5), (5,6))}
   219   \texttt{List((6,5), (5,6))}
   208   \end{center}
   220   \end{center}
   209   \mbox{}\hfill[1 Mark]
   221   \mbox{}\hfill[1 Mark]
   210 
   222 
   211 \item[(1c)] Implement two recursive functions (count-tours and
   223 \item[(1c)] Implement two recursive functions (count-tours and
   212   enum-tours). They each take a dimension and a path as
   224   enum-tours). They each take a dimension and a path as
   213   arguments. They exhaustively search for \underline{\bf open} tours
   225   arguments. They exhaustively search for {\bf open} tours starting
   214   starting from the given path. The first function counts all possible
   226   from the given path. The first function counts all possible open
   215   open tours (there can be none for certain board sizes) and the second
   227   tours (there can be none for certain board sizes) and the second
   216   collects all open tours in a list of paths.\hfill[2 Marks]
   228   collects all open tours in a list of paths.\hfill[2 Marks]
   217 \end{itemize}
   229 \end{itemize}
   218 
   230 
   219 \noindent \textbf{Test data:} For the marking, the functions in (1c)
   231 \noindent \textbf{Test data:} For the marking, the functions in (1c)
   220 will be called with board sizes up to $5 \times 5$. If you only search
   232 will be called with board sizes up to $5 \times 5$. If you search
   221 for open tours on $5 \times 5$ board starting from field $(0, 0)$,
   233 for open tours on a $5 \times 5$ board starting only from field $(0, 0)$,
   222 there are 304 of them. If you try out every field of a $5 \times
   234 there are 304 of tours. If you try out every field of a $5 \times
   223 5$-board as a starting field and add up all open tours, you obtain
   235 5$-board as a starting field and add up all open tours, you obtain
   224 1728. A $6\times 6$ board is already too large to be searched
   236 1728. A $6\times 6$ board is already too large to be searched
   225 exhaustively.\footnote{For your interest, the number of open tours on
   237 exhaustively.\footnote{For your interest, the number of open tours on
   226   $6\times 6$, $7\times 7$ and $8\times 8$ are 6637920, 165575218320,
   238   $6\times 6$, $7\times 7$ and $8\times 8$ are 6637920, 165575218320,
   227   19591828170979904, respectively.}
   239   19591828170979904, respectively.}
   229 \subsubsection*{Tasks (file knight2.scala)}
   241 \subsubsection*{Tasks (file knight2.scala)}
   230 
   242 
   231 \begin{itemize}
   243 \begin{itemize}
   232 \item[(2a)] Implement a first-function. This function takes a list of
   244 \item[(2a)] Implement a first-function. This function takes a list of
   233   positions and a function $f$ as arguments. The function $f$ takes a
   245   positions and a function $f$ as arguments. The function $f$ takes a
   234   position as argument and produces an optional path. The idea behind
   246   position as argument and produces an optional path. So its type is
   235   the first-function is as follows:
   247   \texttt{Pos => Option[Path]}. The idea behind the first-function is
       
   248   as follows:
   236 
   249 
   237   \[
   250   \[
   238   \begin{array}{lcl}
   251   \begin{array}{lcl}
   239   \textit{first}(\texttt{Nil}, f) & \dn & \texttt{None}\\  
   252   \textit{first}(\texttt{Nil}, f) & \dn & \texttt{None}\\  
   240   \textit{first}(x\!::\!xs, f) & \dn & \begin{cases}
   253   \textit{first}(x\!::\!xs, f) & \dn & \begin{cases}
   243                               \end{cases}
   256                               \end{cases}
   244   \end{array}
   257   \end{array}
   245   \]
   258   \]
   246 
   259 
   247   \noindent That is, we want to find the first position where the
   260   \noindent That is, we want to find the first position where the
   248   result of $f$ is not \texttt{None}.\newline\mbox{}\hfill[1 Mark]
   261   result of $f$ is not \texttt{None}, if there is one.\mbox{}\hfill[1 Mark]
   249   
   262   
   250 \item[(2b)] Implement a first-tour function. Using the first-function
   263 \item[(2b)] Implement a first-tour function that uses the
   251   from (2a), search recursively for an open tour.  As there might not
   264   first-function from (2a), and searches recursively for an open tour.
   252   be such a tour at all, the first-tour function needs to return an
   265   As there might not be such a tour at all, the first-tour function
   253   \texttt{Option[Path]}.\hfill[2 Marks]
   266   needs to return an \texttt{Option[Path]}.\hfill[2 Marks]
   254 \end{itemize}
   267 \end{itemize}
   255 
   268 
   256 \noindent
   269 \noindent
   257 \textbf{Testing} The first tour function will be called with board
   270 \textbf{Testing} The first tour function will be called with board
   258 sizes of up to $8 \times 8$. 
   271 sizes of up to $8 \times 8$. 
   259 
   272 
   260 
   273 
   261 \subsection*{Part 2 (4 Marks)}
   274 \subsection*{Part 2 (3 Marks)}
   262 
   275 
   263 As you should have seen in Part 1, a naive search for open tours
   276 As you should have seen in Part 1, a naive search for open tours
   264 beyond $8 \times 8$ boards and also for searching for closed tours
   277 beyond $8 \times 8$ boards and also searching for closed tours
   265 takes too much time. There is a heuristic (called Warnsdorf's rule)
   278 takes too much time. There is a heuristic (called Warnsdorf's rule)
   266 that can speed up finding a tour. This heuristice states that a knight
   279 that can speed up finding a tour. This heuristic states that a knight
   267 is moved so that it always proceeds to the square from which the
   280 is moved so that it always proceeds to the field from which the
   268 knight will have the \underline{fewest} onward moves.  For example for
   281 knight will have the \underline{fewest} onward moves.  For example for
   269 a knight on field $(1, 3)$, the field $(0, 1)$ has the fewest possible
   282 a knight on field $(1, 3)$, the field $(0, 1)$ has the fewest possible
   270 onward moves, namely 2.
   283 onward moves, namely 2.
   271 
   284 
   272 \chessboard[maxfield=g7,
   285 \chessboard[maxfield=g7,
   279             text = \small 2, markfield=Z1,
   292             text = \small 2, markfield=Z1,
   280             setpieces={Na3}]
   293             setpieces={Na3}]
   281 
   294 
   282 \noindent
   295 \noindent
   283 Warnsdorf's rule states that the moves on the board above sould be
   296 Warnsdorf's rule states that the moves on the board above sould be
   284 tried out in the order
   297 tried in the order
   285 
   298 
   286 \[
   299 \[
   287 (0, 1), (0, 5), (2, 1), (2, 5), (3, 4), (3, 2)
   300 (0, 1), (0, 5), (2, 1), (2, 5), (3, 4), (3, 2)
   288 \]
   301 \]
   289 
   302 
   293 do not count moves that revisit any field already visited.
   306 do not count moves that revisit any field already visited.
   294 
   307 
   295 \subsubsection*{Tasks (file knight3.scala)}
   308 \subsubsection*{Tasks (file knight3.scala)}
   296 
   309 
   297 \begin{itemize}
   310 \begin{itemize}
   298 \item[(3a)] orderered-moves
   311 \item[(3a)] Write a function ordered-moves that calculates a list of
   299 
   312   onward moves like in (1b) but orders them according to the
   300 \item[(3b)] first-closed tour heuristics; up to $6\times 6$
   313   Warnsdorf’s rule. That means moves with the fewest legal onward moves
   301 
   314   should come first (in order to be tried out first).
   302 \item[(3c)] first tour heuristics; up to $50\times 50$
   315   
       
   316 \item[(3b)] Implement a first-closed-tour-heuristic function that searches for a
       
   317   \textbf{closed} tour on a $6\times 6$ board. It should use the
       
   318   first-function from (2a) and tries out onwards moves according to
       
   319   the ordered-moves function from (3a). It is more likely to find
       
   320   a solution when started in the middle of the board (that is
       
   321   position $(dimension / 2, dimension / 2)$).
       
   322 
       
   323 \item[(3c)] Implement a first-tour-heuristic function for boards up to $50\times 50$.
       
   324   It is the same function  as in (3b) but searches for \textbf{open} tours.
   303 \end{itemize}  
   325 \end{itemize}  
   304 
   326 
   305 \end{document}
   327 \end{document}
   306 
   328 
   307 %%% Local Variables: 
   329 %%% Local Variables: