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.} |
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, |
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: |