/tutorial/knight.e

http://github.com/tybor/Liberty · Specman e · 185 lines · 148 code · 21 blank · 16 comment · 14 complexity · 97ee68e0dea92b0da2affb34c984322a MD5 · raw file

  1. class KNIGHT
  2. --
  3. -- The classic KNIGHT problem on a N times N square chessboard. The knight have to pass on
  4. -- all places of the chessboard once a time. For instance, here is solution for a 7 X 7
  5. -- chessboard, knight starting at position <1,1>:
  6. --
  7. -- 1 28 37 24 3 26 17
  8. -- 36 39 2 27 18 11 4
  9. -- 29 42 23 38 25 16 9
  10. -- 40 35 30 19 10 5 12
  11. -- 43 22 41 32 15 8 47
  12. -- 34 31 20 45 48 13 6
  13. -- 21 44 33 14 7 46 49
  14. --
  15. insert
  16. ARGUMENTS
  17. redefine print_on
  18. end
  19. create {ANY}
  20. make
  21. feature {}
  22. make
  23. local
  24. size, line, column: INTEGER
  25. do
  26. if argument_count >= 1 and then argument(1).is_integer then
  27. size := argument(1).to_integer
  28. end
  29. if not size.in_range(chess_minimum, chess_maximum) then
  30. size := ask("Chess-board size: ", chess_minimum, chess_maximum)
  31. end
  32. if argument_count >= 2 and then argument(2).is_integer then
  33. line := argument(2).to_integer
  34. end
  35. if not line.in_range(1, size) then
  36. line := ask("Start line: ", 1, size)
  37. end
  38. if argument_count >= 3 and then argument(3).is_integer then
  39. column := argument(3).to_integer
  40. end
  41. if not column.in_range(1, size) then
  42. column := ask("Start column: ", 1, size)
  43. end
  44. knight(size, line, column)
  45. end
  46. chess_minimum: INTEGER 3
  47. chess_maximum: INTEGER 24
  48. chessboard: ARRAY2[INTEGER]
  49. nb_tries: INTEGER
  50. line_move: FAST_ARRAY[INTEGER]
  51. once
  52. Result := {FAST_ARRAY[INTEGER] << -2, -1, 1, 2, 2, 1, -1, -2 >> }
  53. end
  54. column_move: FAST_ARRAY[INTEGER]
  55. once
  56. Result := {FAST_ARRAY[INTEGER] << 1, 2, 2, 1, -1, -2, -2, -1 >> }
  57. end
  58. knight (size, line, column: INTEGER)
  59. require
  60. size >= 3
  61. 1 <= line
  62. line <= size
  63. 1 <= column
  64. column <= size
  65. do
  66. create chessboard.make(1, size, 1, size)
  67. chessboard.put(1, line, column)
  68. if solution(line, column) then
  69. Current.print_on(std_output)
  70. else
  71. io.put_string("Sorry, there is no solution.%N")
  72. end
  73. io.put_string("%NNumber of tries : ")
  74. io.put_integer(nb_tries)
  75. io.put_new_line
  76. end
  77. solution (line, column: INTEGER): BOOLEAN
  78. local
  79. value, i: INTEGER
  80. do
  81. if chessboard.count = chessboard.item(line, column) then
  82. Result := True
  83. else
  84. from
  85. i := line_move.lower
  86. value := chessboard.item(line, column)
  87. until
  88. Result or else i > line_move.upper
  89. loop
  90. Result := try(line + line_move.item(i), column + column_move.item(i), value)
  91. i := i + 1
  92. end
  93. end
  94. end
  95. try (line, column, value: INTEGER): BOOLEAN
  96. -- Try to place the knight by used cross back-tracking method.
  97. do
  98. nb_tries := nb_tries + 1
  99. if chessboard.valid_index(line, column) then
  100. if chessboard.item(line, column) = 0 then
  101. chessboard.put(value + 1, line, column)
  102. Result := solution(line, column)
  103. if not Result then
  104. chessboard.put(0, line, column)
  105. end
  106. end
  107. end
  108. end
  109. ask (s: STRING; min, max: INTEGER): INTEGER
  110. -- Ask for question `s' until the answer is in range `min' `max'.
  111. local
  112. stop: BOOLEAN
  113. do
  114. from
  115. until
  116. stop
  117. loop
  118. io.put_string(s)
  119. io.flush
  120. io.read_integer
  121. Result := io.last_integer
  122. if Result < min then
  123. io.put_string("Value too small.%N")
  124. elseif max < Result then
  125. io.put_string("Value too big.%N")
  126. else
  127. stop := True
  128. end
  129. end
  130. end
  131. feature {ANY}
  132. print_on (file: OUTPUT_STREAM)
  133. -- Display the chessboard.
  134. local
  135. line, column: INTEGER; separator: STRING
  136. do
  137. from
  138. create separator.make_filled(' ', 3 * chessboard.upper1 + 1)
  139. separator.fill_with('-')
  140. separator.extend('%N')
  141. file.put_string(separator)
  142. line := chessboard.lower1
  143. until
  144. line > chessboard.upper1
  145. loop
  146. from
  147. column := chessboard.lower2
  148. until
  149. column > chessboard.upper2
  150. loop
  151. if chessboard.item(line, column) < 10 then
  152. file.put_string("| ")
  153. else
  154. file.put_character('|')
  155. end
  156. file.put_integer(chessboard.item(line, column))
  157. column := column + 1
  158. end
  159. file.put_string("|%N")
  160. file.put_string(separator)
  161. line := line + 1
  162. end
  163. end
  164. end -- class KNIGHT