Thao tác cập nhật User_Set
sau khi người dùng nhập vào bước đi muốn thực hiện trên bàn cờ chỉ đơn giản là chúng ta sẽ di chuyển giá trị User_Move
từ mảng Common_Set
tới vị trí tương ứng trong mảng User_Set
. Tuy nhiên chúng ta có lẽ sẽ muốn tạo ra một cơ chế để đảm bảo rằng sau bất kỳ thủ tục cập nhật nào thì các *_Set
vẫn sẽ bổ trợ lẫn nhau, và khi gộp các *_Set
lại thì chúng ta sẽ thu được chính xác vừa đủ một bộ số 1 .. 9
như mảng Common_Set
ban đầu:
Areas_Are_Unique (App_State);
- đảm bảo rằng mỗi giá trị có ý nghĩa (khác0
) là duy nhất và không bị lặp lại trong phạm vi bao gồm tất cả các*_Set
.Sets_Are_Complement (App_State);
- đảm bảo rằng tập các giá trị có ý nghĩa trong các*_Set
hoàn thiện lẫn nhau và thể hiện vừa đủ bộ số nguyên1 .. 9
.
Như vậy là trong package App_Model
, ngoài các type
tự định nghĩa thì chúng ta sẽ có thêm các procedure
là Init
và Update_User_Set
, và các function
hỗ trợ sau:
package App_Model is -- type ... 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); 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;
end App_Model;
Found (Area, Move_Set);
đã được định nghĩa trong bài trước để hỗ trợ cho thao tác kiểm tra bước đi User
muốn thực hiện vẫn đang có mặt trong Common_Set
. Các procedure
sử dụng tham số out State
có khả năng sẽ chỉnh sửa các *_Set
và chúng ta có thể khai báo gắn kèm contract Post
để đảm bảo rằng trong tổng bộ các *_Set
không có giá trị có nghĩa nào bị lặp hay bị mất đi so với tập 1 .. 9
ban đầu.
Areas_Are_Unique;
Để đảm bảo các giá trị thể hiện các ô area
là duy nhất và không bị lặp lại trong tổng bộ các *_Set
thì chúng ta có thể kiểm tra để loại trừ khả năng một giá trị xuất hiện trong nhiều hơn một *_Set
; Hoặc thực hiện nối nội dung các mảng concat
sau đó kiểm tra tần suất xuất hiện của mỗi phần từ của tập 1 .. 9
trong mảng Concatenated
.
package body App_Model is -- ... function Areas_Are_Unique (App_State : State) return Boolean is -- local Origin_Set : Digit_Array; Area : Digit; Found_Duplicated : Boolean; Result : Boolean := TRUE; begin Origin_Set := (1, 2, 3, 4, 5, 6, 7, 8, 9); -- for Index in Origin_Set'Range loop Area := Origin_Set (Index); Found_Duplicated := (Found (Area, App_State.Common_Set) and Found (Area, App_State.User_Set)) or (Found (Area, App_State.Common_Set) and Found (Area, App_State.Computer_Set)) or (Found (Area, App_State.User_Set) and Found (Area, App_State.Computer_Set)); if Found_Duplicated then Result := FALSE; end if; end loop; -- return Result; end Areas_Are_Unique; -- ...
end App_Model;
Sets_Are_Complement;
Để kiểm tra các giá trị có nghĩa trong tổng bộ các *_Set
vẫn hoàn thiện đủ tập giá trị 1 .. 9
thì chúng ta có thể thực hiện sát nhập mảng merge
. Thao tác gộp sẽ là một dạng ghi đè đối với các trường hợp có giá trị trùng lặp (nếu có).
package body App_Model is -- ... function Sets_Are_Complement (App_State : State) return Boolean is -- local Merged_Set : Digit_Array := (others => 0); Area : Digit := 0; Result : Boolean := TRUE; begin -- for Index in Merged_Set'Range loop Area := App_State.Common_Set (Index); if Area /= 0 then Merged_Set (Index) := Area; end if; -- Area := App_State.User_Set (Index); if Area /= 0 then Merged_Set (Index) := Area; end if; -- Area := App_State.Computer_Set (Index); if Area /= 0 then Merged_Set (Index) := Area; end if; end loop; -- for Index in Merged_Set'Range loop if Merged_Set (Index) = 0 then Result := FALSE; end if; end loop; -- return Result; end Sets_Are_Complement;
end App_Model; -- ...
end App_Model;
Update_User_Set;
Và với các contract Post
đã có thì nội dung của Update_User_Set
sẽ không có gì phải xử lý thêm ngoài việc chuyển giá trị tương tứng với User_Move
trong Common_Set
sang User_Set
.
package body App_Model is -- ... procedure Update_User_Set ( App_State : out State ; User_Move : in Digit ) is -- local Index : Integer := User_Move; begin App_State.Common_Set (Index) := 0; App_State.User_Set (Index) := User_Move; end Update_User_Set; -- ...
end App_Model;
Cuối cùng là code sử dụng tại Main
, chúng ta sẽ đặt thêm Put_Chess_Board;
ở lượt của Computer
để hiển thị kết quả hoạt động của Update_User_Set;
.
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); -- loop Put_Chess_Board (App_State, User_Symbol); Get (User_Move, App_State); Update_User_Set (App_State, User_Move); -- 6. Update_Match_Status -- Put_Chess_Board (App_State, User_Symbol); -- 8. Get_Computer_Move -- 9. Update_Computer_Set -- 10. Update_Match_Status -- -- 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: 0
Choice number should be in 1 .. 9
Your move: A
Choice number should be in 1 .. 9 and has not been taken.
Your move: 1
+ - - + - - + - - + | 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
(chưa đăng tải) [Procedural Programming + Ada] Bài 21 - Console Tic-Tac-Toe App (tiếp theo)