Để bổ sung logic ưu tiên chặn bước di chuyển thắng cuộc cho Computer
thì chúng ta có thể tư duy ở cấp độ Imperative
đó là sử dụng cấu trúc lệnh rẽ nhánh để lựa chọn giữa bước đi chặn USER_WIN
và bước đi ưu tiên các ô tiềm năng trên bàn cờ; Hoặc cũng có thể quan sát Computer_Move
từ cấp độ Procedural
và thực hiện ghi đè bước đi chăn USER_WIN
sau khi đã chọn ra một bước đi bằng logic ưu tiên ban đầu.
Tuy nhiên dù là chọn phương thức viết code nào thì chúng ta cũng sẽ cần phải tách logic lựa chọn bước đi về các procedure
phụ hỗ trợ cho Get (Computer_Move, App_State);
.
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); end AI_Mockup;
Ở đây mình sẽ chọn logic code ghi đè trạng thái của Computer_Move
bởi các procedure
có mức độ ưu tiên cao hơn và code sử dụng các procedure
hỗ trợ tại Get (Computer_Move, App_State);
trông sẽ như thế này.
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_Direct_Winning (Computer_Move, App_State); -- Put_Line ("Computer move:" & Digit'Image (Computer_Move)); end Get; -- procedure Get_Prioritized ... -- procedure Block_Direct_Winning ... end AI_Mockup;
Tức là đầu tiên Get_Prioritized;
sẽ thực hiện logic chọn ô có nhiều tiềm năng nhất trên bàn cờ mà chúng ta đã có trước đó. Sau đó, Block_Direct_Winning;
sẽ tiếp tục ghi đè Computer_Move
nếu nhìn thấy một bước đi thắng cuộc của User
ở lượt tiếp theo để ưu tiên việc chặn bước đi đó.
with Ada.Text_IO; use Ada.Text_IO; package body AI_Mockup is -- procedure Get (Computer_Move ... procedure Get_Prioritized ( Computer_Move : out Digit ; App_State : in State ) is -- local Prioritized_Set : Digit_Array; Area : Digit; begin Prioritized_Set := (5, 2, 4, 6, 8, 1, 3, 7, 9); -- for Index in Prioritized_Set'Range loop Area := Prioritized_Set (Index); if Found (Area, App_State.Common_Set) then Computer_Move := Area; exit; end if; end loop; end Get_Prioritized; procedure Block_Direct_Winning ( Computer_Move : in out Digit ; App_State : in State ) is -- local Foreseen_User_Set : Digit_Array; 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 Computer_Move := App_State.Common_Set (Index); end if; end loop; end Block_Direct_Winning; end AI_Mockup;
Logic xử lý chặn bước đi thắng cuộc của User
ở đây chỉ đơn giản là chúng ta lặp qua các ô trống còn lại trên bàn cờ và lần lượt sử dụng từng giá trị này để tạo ra các trạng thái tiên đoán Foreseen User_Set
; Sau đó kiểm tra các trạng thái tiên đoán của User_Set
ở lượt đi tiếp theo để tìm ra trường hợp của bước đi thắng cuộc và sử dụng luôn bước đi đó cho Computer_Move
để chặn lại.
Lưu ý nhỏ ở đây là phần tham số kết quả Computer_Move
của Block_Direct_Winning;
thì chúng ta cần sử dụng thêm từ khóa in
so với Get_Prioritized;
Lý do là vì từ khóa out
sẽ không cho phép code bên trong procedure
thực hiện thao tác đọc giá trị của Computer_Move
trước khi code ở đây thực hiện một thao tác gán giá trị vào tham số này.
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: 5 PLAYING ...
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | 1 | 8 |
+ - - + - - + - - +
Computer move: 2 PLAYING ...
+ - - + - - + - - +
| O | 9 | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | 1 | 8 |
+ - - + - - + - - +
Your move: 9 PLAYING ...
+ - - + - - + - - +
| O | X | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | 1 | 8 |
+ - - + - - + - - +
Computer move: 1 PLAYING ...
+ - - + - - + - - +
| O | X | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | O | 8 |
+ - - + - - + - - +
Your move: 6 PLAYING ...
+ - - + - - + - - +
| O | X | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| X | O | 8 |
+ - - + - - + - - +
Computer move: 4 PLAYING ...
+ - - + - - + - - +
| O | X | O |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| X | O | 8 |
+ - - + - - + - - +
Your move: 3 PLAYING ...
+ - - + - - + - - +
| O | X | O |
+ - - + - - + - - +
| 7 | X | X |
+ - - + - - + - - +
| X | O | 8 |
+ - - + - - + - - +
Computer move: 7 PLAYING ...
+ - - + - - + - - +
| O | X | O |
+ - - + - - + - - +
| O | X | X |
+ - - + - - + - - +
| X | O | 8 |
+ - - + - - + - - +
Your move: 8 DRAW ...
+ - - + - - + - - +
| O | X | O |
+ - - + - - + - - +
| O | X | X |
+ - - + - - + - - +
| X | O | X |
+ - - + - - + - - +
Như vậy là trong trường hợp chúng ta không tạo ra bước di chuyển kép thì Computer
đã có thể giữ cân bằng kết quả ván cờ. Tuy nhiên, chúng ta vẫn cần phải thử chạy lại phần mềm để kiểm tra trường hợp User
có khả năng tạo ra bước đi kép để xem Computer
đang chọn thế nào.
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: 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 |
+ - - + - - + - - +
| 7 | O | 3 |
+ - - + - - + - - +
| X | 1 | 8 |
+ - - + - - + - - +
Computer move: 2 PLAYING ...
+ - - + - - + - - +
| O | 9 | X |
+ - - + - - + - - +
| 7 | O | 3 |
+ - - + - - + - - +
| X | 1 | 8 |
+ - - + - - + - - +
Your move: 8 PLAYING ...
+ - - + - - + - - +
| O | 9 | X |
+ - - + - - + - - +
| 7 | O | 3 |
+ - - + - - + - - +
| X | 1 | X |
+ - - + - - + - - +
Computer move: 3 PLAYING ...
+ - - + - - + - - +
| O | 9 | X |
+ - - + - - + - - +
| 7 | O | O |
+ - - + - - + - - +
| X | 1 | X |
+ - - + - - + - - +
Your move: 1 USER_WIN ...
+ - - + - - + - - +
| O | 9 | X |
+ - - + - - + - - +
| 7 | O | O |
+ - - + - - + - - +
| X | X | X |
+ - - + - - + - - +
Như vậy là ở bước di chuyển sau khi đã lấy các góc đối diện nhau thì Computer
chưa thể nhìn ra bước đi thắng cuộc ở dạng Double_Threat
. Lý do là bởi vì thao tác kiểm tra bước đi thắng cuộc của chúng ta vẫn đang dừng ở logic kiểm tra đường thẳng hoàn chỉnh nối các cạnh đối diện của bàn cờ.
(chưa đăng tải) [Procedural Programming + Ada] Bài 24 - Console Tic-Tac-Toe App (tiếp theo)