[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

Thay đổi Package Name của Android Studio dể dàng với plugin APR

Nếu bạn đang gặp khó khăn hoặc bế tắc trong việc thay đổi package name trong And

Lỗi không Update Meta_Value Khi thay thế hình ảnh cũ bằng hình ảnh mới trong WordPress

Mã dưới đây hoạt động tốt có 1 lỗi không update được postmeta ” meta_key=

Bài 1 – React Native DevOps các khái niệm và các cài đặt căn bản

Hướng dẫn setup jenkins agent để bắt đầu build mobile bằng jenkins cho devloper an t

Chuyển đổi từ monolith sang microservices qua ví dụ

1. Why microservices? Microservices là kiến trúc hệ thống phần mềm hướng dịch vụ,