PageRenderTime 57ms CodeModel.GetById 52ms app.highlight 1ms RepoModel.GetById 1ms app.codeStats 0ms

/tutorial/knight.e

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