Thủ tục cuối cùng trong lượt di chuyển của User
là cập nhật trạng thái của ván cờ Update_Match_Status;
. Thủ tục này cũng sẽ được sử dụng lại ở lượt di chuyển của Computer
giống như Put_Chess_Board;
. Như vậy là chúng ta viết code rẽ nhánh bao gồm tất cả các trạng thái tiềm năng của Match_Status
đã định nghĩa bởi kiểu Status
:
- Sẽ là
USER_WIN
- nếuUser_Set
có ít nhất một bộ số thắng cuộc. - Hoặc
COMPUTER_WIN
- nếuComputer_Set
có ít nhất một bộ số thắng cuộc. - Hoặc
DRAW
- nếuCommon_Set
không còn giá trị nào có ý nghĩa và bàn cờ đã hết ô trống. - Hoặc
PLAYING
- nếu tất cả các trường hợp ở trên đều chưa hiện diện.
Do đó chúng ta sẽ có thêm các function
hỗ trợ là Found_Wining (Move_Set);
và Found_Empty (Move_Set);
để kiểm tra xem một *_Set
bất kỳ có chứa bộ số thắng cuộc không, và kiểm tra một *_Set
bất kỳ có đang ở trạng thái trống rỗng không.
package App_Model is subtype Digit is Integer range 0 .. 9; type Digit_Array is array (1 .. 9) of Digit; type Status is (PLAYING, DRAW, USER_WIN, COMPUTER_WIN); type State is record Common_Set : Digit_Array; User_Set : Digit_Array; Computer_Set : Digit_Array; Match_Status : Status; end record; procedure Init (App_State : out State) with Post => Areas_Are_Unique (App_State) and Sets_Are_Complement (App_State); procedure Update_User_Set (App_State : out State; User_Move : in Digit) with Post => Areas_Are_Unique (App_State) and Sets_Are_Complement (App_State); procedure Update_Match_Status (App_State : in out State); -- - new function Areas_Are_Unique (App_State : State) return Boolean; function Sets_Are_Complement (App_State : State) return Boolean; function Found (Area : Digit; Move_Set : Digit_Array) return Boolean; function Found_Winning (Move_Set : Digit_Array) -- - new return Boolean; function Found_Empty (Move_Set : Digit_Array) -- - new return Boolean;
end App_Model;
Update_Match_Status;
package body App_Model is -- ... procedure Update_Match_Status (App_State : in out State) is -- local begin if Found_Winning (App_State.User_Set) then App_State.Match_Status := USER_WIN; elsif Found_Winning (App_State.Computer_Set) then App_State.Match_Status := COMPUTER_WIN; elsif Found_Empty (App_State.Common_Set) then App_State.Match_Status := DRAW; else App_State.Match_Status := PLAYING; end if; end Update_Match_Status; end App_Model;
Found_Winning;
Thao kiểm tra sự hiện điện của ít nhất một bộ số thắng cuộc bất kỳ trong User_Set
hoặc Computer_Set
có thể được thực hiện bằng những cách khác nhau:
- Liệt kê các bộ số thắng cuộc sau đó kiểm tra sự hiện diện của từng bộ số đó trong
Move_Set
được truyền vàofunction
. - Hoặc lấy ra lần từng bộ số trong
Move_Set
để kiểm tra tổng giá trị. Nếu có ít nhất một bộ số cho kết quả tổng là 15 thì trả về giá trị làTRUE
.
Phép kiểm tra đầu tiên có thể áp dụng với mọi cách thức đánh số các ô trên bàn cờ. Còn cách làm thứ hai thì chỉ có thể áp dụng nếu như bàn cờ được đánh số như chúng ta đang sử dụng hiện tại.
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| 6 | 1 | 8 |
+ - - + - - + - - +
Mỗi đường thẳng bất kỳ giữa hai biên đối diện của bàn cờ trong trường hợp này sẽ luôn đi qua các ô tạo thành một bộ số có tổng là 15
.
package body App_Model is -- ... function Found_Winning (Move_Set : Digit_Array) return Boolean is -- local Total : Digit; Result : Boolean := FALSE; begin for I1 in 1 .. 7 loop for I2 in 2 .. 8 loop for I3 in 3 .. 9 loop Total := Move_Set (I1) + Move_Set (I2) + Move_Set (I3); if Total = 15 and Move_Set (I1) /= Move_Set (I2) then Result := TRUE; end if; end loop; end loop; end loop; -- return Result; end Found_Winning; end App_Model;
Found_Empty;
Hàm kiểm tra một Move_Set
được truyền vào có đang ở trạng thái rỗng hay không.
package body App_Model is -- ... function Found_Empty (Move_Set : Digit_Array) return Boolean is -- local Result : Boolean := TRUE; begin for Index in Move_Set'Range loop if Move_Set (Index) /= 0 then Result := FALSE; end if; end loop; -- return Result; end Found_Empty; end App_Model;
Main;
Và cuối cùng là code sử dụng ở Main
, chúng ta sẽ thử Update_User_Move;
thêm vài bước đi để kiểm tra hoạt động của Update_Match_Status;
with Ada.Text_IO; use Ada.Text_IO;
with App_Model; use App_Model;
with Console_IO; use Console_IO; procedure Main is User_Symbol : Symbol; App_State : State; User_Move : Digit;
begin Put_Symbol_Menu; Get (User_Symbol); Init (App_State); Put_Chess_Board (App_State, User_Symbol); -- loop for I in 1 .. 3 loop Get (User_Move, App_State); Update_User_Set (App_State, User_Move); -- Update_Match_Status (App_State); Put_Line (Status'Image (App_State.Match_Status) & " ..."); -- Put_Chess_Board (App_State, User_Symbol); end loop; -- -- 9. Get_Computer_Move; -- 10. Update_Computer_Set; -- 11. Update_Match_Status; -- 12. Put_Chess_Board; -- -- exit when App_State.Match_Status /= PLAYING; -- end loop
end Main;
alr run Choose your Symbol ... 1. Letter 'X' 2. Letter 'O'
Your choice: 1
You've chosen: X
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| 6 | 1 | 8 |
+ - - + - - + - - +
Your move: 1
PLAYING ...
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
Your move: 5
PLAYING ...
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
Your move: 9
USER_WIN ...
+ - - + - - + - - +
| 2 | X | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
(chưa đăng tải) [Procedural Programming + Ada] Bài 22 - Console Tic-Tac-Toe App (tiếp theo)