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

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

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;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_SetCommon_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_Direct_Threat (Foreseen_App_State) > 1 then
               Computer_Move := Foreseen_User_Move;
            end if;
         end if;
      end loop;
   end Block_Double_Threat;

   function Count_Direct_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_Direct_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_Direct_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)

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 đầ