[Procedural Programming + Ada] Bài 23 – Console Tic-Tac-Toe App (tiếp theo)

Để 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

Để 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)

Nguồn: viblo.asia

Bài viết liên quan

WebP là gì? Hướng dẫn cách để chuyển hình ảnh jpg, png qua webp

WebP là gì? WebP là một định dạng ảnh hiện đại, được phát triển bởi Google

Điểm khác biệt giữa IPv4 và IPv6 là gì?

IPv4 và IPv6 là hai phiên bản của hệ thống địa chỉ Giao thức Internet (IP). IP l

Check nameservers của tên miền xem website trỏ đúng chưa

Tìm hiểu cách check nameservers của tên miền để xác định tên miền đó đang dùn

Mình đang dùng Google Domains để check tên miền hàng ngày

Từ khi thông báo dịch vụ Google Domains bỏ mác Beta, mình mới để ý và bắt đầ