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)
Nguồn: viblo.asia