Như vậy là để Computer
có thể cân bằng kết quả ván cờ thì chúng ta cần bổ sung thêm logic chặn bước đi tạo cơ hội kép của User
. Trong trường hợp này thì procedure
mới sẽ có mức độ ưu tiên thấp hơn so với Get_Prioritized;
. Vì vậy nên ở code sử dụng tại Get (Computer_Move, App_State);
, chúng ta sẽ đặt procedure
mới bổ sung ở giữa Get_Prioritized;
và Block_Direct_Winning;
.
with Ada.Text_IO; use Ada.Text_IO; package body AI_Mockup is procedure Get ( Computer_Move : out Digit ; App_State : in State ) is begin Get_Prioritized (Computer_Move, App_State); Block_Double_Threat (Computer_Move, App_State); Block_Direct_Winning (Computer_Move, App_State); -- Put_Line ("Computer move:" & Digit'Image (Computer_Move)); end Get; -- Get_Prior... end AI_Mockup;
Và để định nghĩa cho Computer
về bước đi tạo cơ hội kép của User
thì chúng ta vẫn sẽ thực hiện thao tác lặp để tạo ra các trạng thái tiên đoán của User_Set
và Common_Set
, sau đó dựa trên trạng thái tiên đoán này lại tiếp tục tính toán số lượng bước đi thắng cuộc ở lượt tiếp theo nữa.
Nếu như số lượng bước đi thắng cuộc ở lượt sau cùng nhiều hơn 1
thì có nghĩa là bước đi tiên đoán trước đó là một bước đi tạo Double_Threat
, và chúng ta cần gán giá trị của bước đi tiên đoán này cho Computer_Move
để chặn lại.
with Ada.Text_IO; use Ada.Text_IO; package body AI_Mockup is -- ... procedure Block_Double_Threat ( Computer_Move : in out Digit ; App_State : in State ) is -- local Foreseen_App_State : State; Foreseen_User_Move : Digit; begin for Index in App_State.Common_Set'Range loop Foreseen_User_Move := App_State.Common_Set (Index); if Foreseen_User_Move /= 0 then Copy (Foreseen_App_State, App_State); Update_User_Set (Foreseen_App_State, Foreseen_User_Move); if Count_Threat (Foreseen_App_State) > 1 then Computer_Move := Foreseen_User_Move; end if; end if; end loop; end Block_Double_Threat; function Count_Threat (App_State : State) return Integer is -- local Foreseen_User_Set : Digit_Array; Counter : Integer := 0; begin for Index in App_State.Common_Set'Range loop Foreseen_User_Set (1 .. 9) := App_State.User_Set; Foreseen_User_Set (Index) := App_State.Common_Set (Index); if Found_Winning (Foreseen_User_Set) then Counter := Counter + 1; end if; end loop; -- return Counter; end Count_Threat; end AI_Mockup;
Cuối cùng là chúng ta cần đảm bảo các procedure
đều được khai báo đầy đủ trong tệp cấu hình của package AI_Mockup
.
with App_Model; use App_Model; package AI_Mockup is procedure Get (Computer_Move : out Digit; App_State : in State); procedure Get_Prioritized (Computer_Move : out Digit; App_State : in State); procedure Block_Direct_Winning (Computer_Move : in out Digit; App_State : in State); procedure Block_Double_Threat (Computer_Move : in out Digit; App_State : in State); function Count_Threat (App_State : State) return Integer; end AI_Mockup;
Để xem Computer
đã có thể cân bằng được kết quả ván cờ trong tình huống trước đó hay chưa.
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: 6 PLAYING ...
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| X | 1 | 8 |
+ - - + - - + - - +
Computer move: 5 PLAYING ...
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | O | 3 |
+ - - + - - + - - +
| X | 1 | 8 |
+ - - + - - + - - +
Your move: 4 PLAYING ...
+ - - + - - + - - + + - - + - - + - - +
| 2 | 9 | X | => | | | X |
+ - - + - - + - - + + - - + - - + - - +
| 7 | O | 3 | => | | O | |
+ - - + - - + - - + + - - + - - + - - +
| X | 1 | 8 | => | X | | |
+ - - + - - + - - + + - - + - - + - - +
Computer move: ... PLAYING ...
+ - - + - - + - - +
| | | X |
+ - - + - - + - - +
| | O | |
+ - - + - - + - - +
| X | | O |
+ - - + - - + - - +
Oh... Như vậy là ở đây khi User: X
chọn trước góc phía dưới bên trái và góc phía trên bên phải thì các góc còn lại vẫn đang để trống và đều là bước đi có thể tạo Double_Threat
. Nếu vậy cho dù Computer
có chặn bước đi nào thì cũng đều chưa thể cân bằng được kết quả ván cờ. Có lẽ là chúng ta vẫn cần bổ sung thêm một logic xử lý nữa có mức độ ưu tiên cao hơn so với Block_Double_Threat;
.
[Functional Programming + Haskell] Bài 25 - Console Tic-Tac-Toe App (tiếp theo)