Và đây là code hoàn thiện của Redirect_User_Concern;
giúp bổ sung logic điều hướng bước đi tiếp theo mà User
phải tạm dừng ý định tạo Double_Threat
để ngăn chặn Computer
thắng sớm hơn. Bây giờ chúng ta đã có thể bỏ đi các dòng Put_Line
in ra số lượng Count_Double_Threats
và các tập giá trị tiên đoán.
with Ada.Text_IO; use Ada.Text_IO;
package body AI_Mockup is
procedure Redirect_User_Concern
( Computer_Move : in out Digit
; App_State : in State )
is -- local
Foreseen_User_Moves : Digit_Array;
--
Foreseen_Computer_Moves : Digit_Array;
Foreseen_App_State : State;
Computer_After_Next_Move: Digit := 0;
begin
if Count_Double_Threats (App_State) > 1 then
Foreseen_User_Moves := (others => 0);
Get_Double_Threats (Foreseen_User_Moves, App_State);
--
Foreseen_Computer_Moves := (others => 0);
Get_Direct_Chance_Inits (Foreseen_Computer_Moves, App_State);
--
for Index in Foreseen_Computer_Moves'Range loop
if Foreseen_Computer_Moves (Index) /= 0 then
Copy (Foreseen_App_State, App_State);
Update_Computer_Set (Foreseen_App_State, Foreseen_Computer_Moves (Index));
Get_Direct_Chance (Computer_After_Next_Move, Foreseen_App_State);
--
if not Found (Computer_After_Next_Move, Foreseen_User_Moves) then
Computer_Move := Foreseen_Computer_Moves (Index);
end if;
end if;
end loop;
end if;
end Redirect_User_Concern;
end AI_Mockup;
Bạn có thể chạy thử các trường hợp trước đó để kiểm tra hoạt động của logic mới bổ sung cho AI_Mockup.Get (Computer_Move, App_State);
. Trên máy tính mình đang sử dụng thì kết quả khá ổn và chỉ hơi thiếu tự nhiên một chút bởi vì chúng ta chưa chia các tập kết quả tiềm năng ra để thực hiện lựa chọn ngẫu nhiên các bước đi có thể thực hiện. Tuy nhiên điều đó sẽ yêu cầu việc tái cấu trúc lại code kha khá thời gian và bạn nên cân nhắc sau khi đã đảm bảo rằng kết quả chạy thử hoàn toàn ổn.
Source Code
: GitHub.IO
Mặc dù vẫn còn những tính năng khác nữa mà mình chưa tìm hiểu hết về ngôn ngữ Ada
và môi trường phát triển của GNAT
, tuy nhiên đây đã là điểm phù hợp để kết thúc Sub-Series này với mục đích chính là tìm hiểu về Procedural Programming
trong môi trường phát triển được thiết kế đặc trưng cho mô hình lập trình này.
Cụ thể là trước khi chúng ta chuyển qua Sub-Series Functional Programming
đã dự định trước đó thì mình muốn gạch đầu dòng lại một vài đặc trưng trong khía cạnh tư duy Procedural
đã nghiệm thu được nhờ Ada
:
- Luôn phân biệt rất rõ các loại
sub-program
theo mục đích sử dụng. Các thủ tụcprocedure
được sử dụng để tạo ra hiệu ứng biênside-effect
có ảnh hưởng tới các dữ liệu trạng thái của môi trường bên ngoài. Các hàmfunction
được sử dụng để hỗ trợ các thao tác tính toán cục bộ và sẽ không bao giờ tạo ra hiệu ứng biênside-effect
như cácprocedure
. - Các thủ tục
procedure
được sử dụng chủ đạo và các hàmfunction
chỉ mang tính tiện ích bổ trợ. Cácprocedure
sẽ đóng vai trò điều khiển logic hoạt động chính của chương trình. Cácfunction
tiện ích được dùng để giảm thiểu số lượng biến cục bộlocal
cho cácprocedure
và ở những vị trí yêu cầu cú pháp sử dụng ở dạng biểu thức trả về giá trị, ví dụ như cáccontract
. - Trọng tâm của một chương trình là các dữ liệu trạng thái
State
sẽ được tạo ra và lưu cố định ở vị trí nào đó mang tính chất toàn cụcglobal
hoặc nếu lưu cục bộ thì sẽ là biếnlocal
của cácprocedure
quan trọng góp phần điều khiển logic xử lý chính của chương trình. - Địa chỉ tham chiếu tới các bộ dữ liệu trạng thái
State
sẽ được chia sẻ giữa cácsub-program
, và cácprocedure
sẽ đóng vai trò là các hành động khách quan xung quanh để lần lượt tạo ra các sự thay đổi trênState
. Để dễ hình dung hơn thì cácState
sẽ đóng vai trò là các Cơ Sở Dữ Liệu Mini trong thời gian chương trình vận hành và sẽ được cập nhật thay đổi nội dung nhiều lần. - Các yếu tố ràng buộc
contract
sẽ giúp ích rất nhiều cho cácsub-program
; Ví dụ như các chế độ hoạt động của các tham sốin
,out
,in out
sẽ giúp thông báo lỗi nếu như chúng ta viết code triển khai logic không phù hợp; Và các kiểucontract
tự định nghĩa khác có thể được gắn liền với cácsub-program
để đảm bảo tính hợp lệ của dữ liệuinput/output
.
Nói riêng về Ada
thì sự minh bạch trong cú pháp của ngôn ngữ và phong cách đặt tên các yếu tố trong các thư viện tiêu chuẩn cũng giúp mình cải thiện được thói quen khi code. Tuy nhiên, riêng tính năng nhóm các tham số cùng kiểu thành các danh sách bằng các dấu chấm phẩy ;
trong code khai báo các sub-program
thì có phần hơi thừa. Mình thực sự đã phải chỉnh sửa lại code rất nhiều lần chỉ vì thói quen từ các ngôn ngữ khác là chỉ có một danh sách tham số duy nhất với các tham số được liệt kê với dấu phẩy ,
.
function Area_of_Circle
( R : Float
; X , Y : Integer )
return Float;
Tuy nhiên đó chỉ là ý kiến cá nhân của một beginner
đang chập chững học code. Bởi có lẽ đối với các kỹ sư lập trình điều khiển cho các engine
phần cứng như những chiếc máy máy bay thương mại thì có lẽ đây lại là một tính năng hữu ích khi thiết kế các sub-program
có nhiều nhóm tham số khác nhau.
Điểm duy nhất mà mình có thể mạnh dạn khẳng định đó là khả năng định dạng kết quả in ra cửa sổ Console
của Ada
là rất giới hạn bởi thiết kế định kiểu chặt chẽ và không có tùy chọn để người viết code định nghĩa lại các thuộc tính Type'Attribute
. Khi sử dụng Integer'Image (Value)
với các giá trị số nguyên có một chữ số đơn thì kết quả thu được sẽ luôn là một chuỗi kèm theo một ký tự khoảng trống ở phía trước. Và chúng ta cũng không có tính năng sử dụng tham số định dạng trong C
ví dụ như %9s
để in ra chuỗi kết quả dài 9
ký tự mặc dù dữ liệu truyền vào printf
có thể ngắn hơn nhiều.
Nếu có dự định tạo ra một ứng dụng khác sau project
này thì chắc chắn mình sẽ chỉ sử dụng Ada
để code xử lý logic chính. Còn code để vẽ giao diện người dùng thì chắc chắn là sẽ viết bằng C
và import
vào Ada
để sử dụng sau. Và sự kết hợp như vậy có lẽ rất hoàn hảo cho cả Ada
và C
; bởi Ada
thì không hẳn phổ biến trong lập trình ứng dụng phổ thông General Purposes
nên sẽ cần phải giao tiếp với các API
của các môi trường khác bằng C
; còn C
thì lại không có sẵn các cấu trúc dữ liệu phổ biến như Map
, Set
, Tree
, v.v… và nhiều tính năng hỗ trợ ở cấp độ ngôn ngữ và giao diện lập trình bậc cao như contract
, và cả generic
trong C
cũng rất khó triển khai.
Bây giờ thì chúng ta sẽ chuyển sang mô hình lập trình tiếp theo trong nhóm các mô hình lập trình phổ biến. Hy vọng là bạn vẫn còn nhớ các cú pháp của Elm
và nền móng tư duy căn bản của Declarative
. Nếu bạn đã quên thì hãy dành một chút thời gian đọc lướt qua các bài viết trước đó của Sub-Series [Declarative Programming + Elm]
; Bởi vì ngôn ngữ mà chúng ta sẽ tìm hiểu và làm ví dụ cho Sub-Series tiếp theo có thể được xem là phiên bản đầy đủ hơn của Elm
về các tính năng được hỗ trợ ở cấp độ cú pháp của ngôn ngữ.
(chưa đăng tải) [Functional Programming + Haskell] Bài 1 – Giới Thiệu Ngôn Ngữ Haskell
Nguồn: viblo.asia