- vừa được xem lúc

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

0 0 17

Người đăng: Semi Dev

Theo Viblo Asia

Trong số các thủ tục được gọi ở lượt di chuyển của Computer thì chúng ta chỉ còn Get_Computer_Move;Update_Computer_Set; là các thủ tục mới. Tuy nhiên Update_Computer_Set; có logic tương đồng với Update_User_Set; vì vậy nên ở đây mình sẽ chỉ đặt code ví dụ và chúng ta sẽ chuyển qua nói về Get_Computer_Move; luôn.

Update_Computer_Set;

Khai báo Update_Computer_Set gắn kèm các contract để đảm bảo các *_Set sau thao tác cập nhật vẫn chứa nội dung bổ trợ lẫn nhau và không có ô cờ nào bị lặp.

package App_Model is -- ... procedure Update_User_Set (App_State : out State; User_Move : in Digit) with Post => Areas_Are_Unique (App_State) and Sets_Are_Complement (App_State); procedure Update_Computer_Set (App_State : out State; Computer_Move : in Digit) with Post => Areas_Are_Unique (App_State) and Sets_Are_Complement (App_State); -- ... end App_Model;

Xóa tại Common_Set và thêm mới tại Computer_Set.

package body App_Model is -- ... procedure Update_Computer_Set ( App_State : out State ; Computer_Move : in Digit ) is -- local Index : Integer := Computer_Move; begin App_State.Common_Set (Index) := 0; App_State.Computer_Set (Index) := Computer_Move; end Update_Computer_Set; -- ... end App_Model;

Get_Computer_Move;

Ở đây chúng ta cần xác định mục tiêu xây dựng cho code xử lý logic tính toán và tạo bước đi cho Computer. Hiển nhiên nếu chúng ta muốn tạo ra một logic tính toán linh động và tự nhiên gần giống với phương thức suy nghĩ của con người thì code triển khai sẽ cần thêm nhiều thao tác bổ trợ. Còn nếu chúng ta chỉ đặt ra mục tiêu là một logic tính toán để có được kết quả hòa và không cần thêm các yếu tố khác như chọn bước đi ngẫu nhiên thì code triển khai cũng không quá phức tạp.

Lựa chọn của mỗi người có lẽ sẽ khác nhau, tuy nhiên điểm chung vẫn là chúng ta sẽ xuất phát với các trường hợp tư duy logic đơn giản và phát triển dần để mở rộng các trường hợp cần xử lý trong code. Và để thuận tiện cho việc mở rộng logic tính toán hỗ trợ cho Get_Computer_Move; khi cần thiết thì chúng ta sẽ tạo thêm một package riêng cho procedure này và các sub-program hỗ trợ xoay quanh đó tên là AI_Mockup.

src
├── ai-mockup
│ ├── ai_mockup.adb
│ └── ai_mockup.ads
├── app-state
│ ├── app_state.adb
│ └── app_state.ads
├── console-io
│ ├── console_io.adb
│ └── console_io.ads
├── src.map
└── main.adb

Trường hợp đơn giản nhất là các bước đi ở thế cân bằng ở thời điểm mở đầu ván cờ, chúng ta thường sẽ ưu tiên chọn các ô cờ quan trọng và có nhiều đường thẳng đi qua nhất. Như vậy giải pháp đơn giản là chúng ta có thể tạo ra một mảng liệt kê đầy đủ các ô trên bàn cờ nhưng được sắp xếp theo mức độ quan trọng gảm dần. Sau đó lặp qua mảng này và lấy ra từng phần tử để so sánh và kiểm tra sự có mặt trong Common_Set để chọn bước di chuyển hợp lệ.

with App_Model; use App_Model; package AI_Mockup is procedure Get (Computer_Move : out Digit; App_State : in State);
end AI_Mockup;
package body AI_Mockup is procedure Get ( 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; -- Put_Line ("Computer move:" & Digit'Image (Computer_Move)); end Get; end AI_Mockup;

Lúc này ở code sử dụng tại Main khi chúng ta nhúng thêm package AI_Mockup bằng lệnh use thì đã có sự trùng lặp về chữ ký signature của procedure Get (out Digit, in State);. Do đó nên chúng ta sẽ phải sửa lại lệnh gọi tên thủ tục Get ở lượt di chuyển của User thành dạng tham chiếu từ tên package để trình biên dịch có thể xác định được chính xác định nghĩa của mỗi procedure mà chúng ta sử dụng.

with Ada.Text_IO; use Ada.Text_IO;
with App_Model; use App_Model;
with Console_IO; use Console_IO;
with AI_Mockup; use AI_Mockup; procedure Main is User_Symbol : Symbol; App_State : State; User_Move : Digit; Computer_Move : Digit;
begin Put_Symbol_Menu; Get (User_Symbol); Init (App_State); Put_Chess_Board (App_State, User_Symbol); -- loop Console_IO.Get (User_Move, App_State); Update_User_Set (App_State, User_Move); Update_Match_Status (App_State); Put_Line (Status'Image (App_State.Match_Status) & " ..."); Put_Chess_Board (App_State, User_Symbol); -- AI_Mockup.Get (Computer_Move, App_State); Update_Computer_Set (App_State, Computer_Move); Update_Match_Status (App_State); Put_Line (Status'Image (App_State.Match_Status) & " ..."); Put_Chess_Board (App_State, User_Symbol); -- -- exit when App_State.Match_Status /= PLAYING then exit; end if; -- end loop;
end Main;
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: 1 PLAYING ...
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
Computer move: 5 PLAYING ...
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | O | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +

Bây giờ thì chúng ta đã có thể bỏ comment cấu trúc vòng lặp để đánh cờ với Computer cho đến khi ván cờ kết thúc. Để duy trì logic đơn giản ở thời điểm khởi đầu thì mình đã đặt tạm một vòng lặp dạng do .. while. Tuy nhiên logic dừng vòng lặp mà chúng ta cần ở đây lại yêu cầu sự linh động nhiều hơn một chút. Chúng ta sẽ cần kiểm tra ngay sau mỗi bước di chuyển của User hoặc Computer để đưa quyết định tiếp tục hoặc dừng vòng lặp dựa trên trạng thái của ván cờ Match_Status.

procedure Main is -- local ...
begin Put_Symbol_Menu; Get (User_Symbol); Init (App_State); Put_Chess_Board ... loop Console_IO.Get ... User_Move Update_User_Set ... Update_Match_Status ... Put_Line ... Match_Status Put_Chess_Board ... -- if App_State.Match_Status /= PLAYING then exit; end if; -- AI_Mockup.Get ... Computer_Move Update_Computer_Set ... Update_Match_Status ... Put_Line ... Match_Status Put_Chess_Board ... -- if App_State.Match_Status /= PLAYING then exit; end if; end loop;
end Main;
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: 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: 1 PLAYING ...
+ - - + - - + - - +
| O | 9 | 4 |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
Computer move: 4 PLAYING ...
+ - - + - - + - - +
| O | 9 | O |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
Your move: 9 USER_WIN ...
+ - - + - - + - - +
| O | X | O |
+ - - + - - + - - +
| 7 | X | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +

Như vậy là với logic đơn thuần là ưu tiên chọn các ô cờ có nhiều tiềm năng thì Computer vẫn còn vài bước đi nữa mới chạm tới các ô cờ ít tiềm năng. Và nếu User chọn một đường thẳng đi qua tâm bàn cờ thì kết quả của ván cờ sẽ mất quân bình, do chúng ta chưa tạo logic để ưu tiên việc chặn bước đi kết thúc đường thẳng Winning_Move.

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

Bình luận

Bài viết tương tự

- vừa được xem lúc

Closure trong Javascript - Phần 2: Định nghĩa và cách dùng

Các bạn có thể đọc qua phần 1 ở đây. Để mọi người không quên, mình xin tóm tắt gọn lại khái niệm lexical environment:.

0 0 51

- vừa được xem lúc

Var vs let vs const? Các cách khai báo biến và hằng trong Javascript

Dạo này mình tập tành học Javascript, thấy có 2 cách khai báo biến khác nhau nên đã tìm tòi sự khác biệt. Nay xin đăng lên đây để mọi người đọc xong hy vọng phân biệt được giữa let và var, và sau đó là khai báo hằng bằng const.

0 0 31

- vừa được xem lúc

VueJS: Tính năng Mixins

Chào mọi người, hôm nay mình sẽ viết về Mixins và 1 số vấn đề trong sử dụng Mixins hay ho mà mình gặp trong dự án thực. Trích dẫn từ trang chủ của VueJS:.

0 0 27

- vừa được xem lúc

Asset Pipeline là cái chi chi?

Asset Pipeline. Asset pipeline là cái chi chi. . Giải thích:.

0 0 47

- vừa được xem lúc

Tạo data table web app lấy dữ liệu từ Google Sheets sử dụng Apps Script

Google Sheets là công cụ tuyệt vời để lưu trữ bảng tính trực tuyến, bạn có thể truy cập bảng tính bất kỳ lúc nào ở bất kỳ đâu và luôn sẵn sàng để chia sẻ với người khác. Bài này gồm 2 phần.

0 0 266

- vừa được xem lúc

Học Deep Learning trên Coursera miễn phí

Bạn muốn bắt đầu với Deep Learning nhưng không biết bắt đầu từ đâu? Bạn muốn có một công việc ở mức fresher về Deep Learning? Bạn muốn khoe bạn bè về kiến thức Deep Learning của mình. Bắt đầu từ đâu.

0 0 35