[Procedural Programming + Ada] Bài 13 – Console TicTacToe App (mở đầu)

Như vậy là chúng ta đã điểm qua các công cụ chính mà Ada cung cấp ở cấp độ cú pháp của một ngôn ngữ đặt nền móng trọng tâm trên Procedural Programming. Và so với C thì thư viện tiêu chuẩn của Ada cũng được triển khai rộng hơn và cung cấp cả những

Như vậy là chúng ta đã điểm qua các công cụ chính mà Ada cung cấp ở cấp độ cú pháp của một ngôn ngữ đặt nền móng trọng tâm trên Procedural Programming. Và so với C thì thư viện tiêu chuẩn của Ada cũng được triển khai rộng hơn và cung cấp cả những cấu trúc dữ liệu tập hợp như List, Set, Map, v.v…

Tuy nhiên mục đích của mình khi bắt đầu tìm hiểu về ngôn ngữ Ada và cho tới thời điểm này thì vẫn là để hiểu hơn về phương cách tư duy của kỹ sư thiết kế ngôn ngữ này – hay phương cách thiết kế và kiến trúc nên một phần mềm nào đó bằng ngôn ngữ Ada với tư duy Procedural Programming. Vì vậy nên việc viết một project nhỏ là rất cần thiết để nghiệm thu lại những hiểu biết về ngôn ngữ Ada và một trong số những mô hình lập trình phổ biến mà chúng ta đang tìm hiểu.

Procedural Thinking

Tư duy căn bản của Procedural Programming hiển nhiên sẽ xoay quanh các sub-program được gọi là procedure mà chúng ta đã biết. Khác biệt căn bản giữa định nghĩa thủ tục procedure và định nghĩa hàm function được vay mượn từ toán học là:

   @reflection
   record A ---> function ---> new record Z
   
   @effection
   procedure ---> record A ---> modified record A

Các hàm function là các công cụ mô tả logic ánh xạ và sẽ không tạo ra tác động thay đổi tới các dữ liệu trạng thái state. Khi chúng ta có một record ban đầu A, được truyền vào một lời gọi hàm f (A) thì ở đây hàm f sẽ mô tả một logic chỉ đường tham chiếu tới một record kết quả trả về mới Z. Và bản ghi A ban đầu sẽ không bị thay đổi về mặt nội dung.

Trong khi đó thì các procedure lại không phải là các công cụ mô tả logic ánh xạ, mà thay vào đó lại có ý nghĩa mô tả các thao tác khách quan tác động lên các dữ liệu trạng thái state. Khi chúng ta có một record A, được truyền vào một lời gọi thủ tục p (A) thì ở đây thủ tục p sẽ thực hiện thao tác thay đổi nội dung của record A ban đầu chứ không tạo ra một record Z hoàn toàn mới như function.

Như vậy, chúng ta có thể hình dung đơn giản là Procedural Programming sẽ nhìn nhận một chương trình bất kỳ bao gồm 2 thành phần căn bản là:

                        procedure-that
                             |
                             |
                            |/
                             :
   procedure-left ------>  state  <------ procedure-right
                             :
                            /|
                             |
                             |
                        procedure-this
  • Các dữ liệu trạng thái state được lưu trữ cố định ở một điểm nào đó. Ví dụ: các biến toàn cục global, các biến local của procedure Main, hoặc cũng có thể là state của các nguồn trừu tượng như trạng thái hiển thị của cửa sổ dòng lệnh console.
  • Các procedure được thiết kế xoay quanh state để tạo ra các thao tác thay đổi nội dung của state đang lưu trữ.

Các hàm function tuy cũng được sử dụng trong môi trường Procedural, tuy nhiên chỉ đóng vai trò là các chức năng hỗ trợ utility cho các thao tác tính toán, và sẽ được gọi bởi các procedure chính điều khiển logic xử lý của phần mềm.

Init Project

Sau khi nhắc lại khái niệm căn bản về Procedural Programming thì ở đây chúng ta sẽ bắt đầu khởi tạo project để xây dựng một ứng dụng console – tương tác với người dùng nhập liệu trên cửa sổ dòng lệnh.

cd Documents
alr init --bin console_tictactoe

Success: console_tictactoe initialized successfully.

Lúc này chúng ta đã có một thư mục project với tên như mô tả trong lệnh khởi tạo phía trên và đã có thể chỉnh sửa code ở tệp khởi chạy để biên dịch thử.

with Ada.Text_IO; use Ada.Text_IO;

procedure Console_Tictactoe is
   -- local
begin
   Put_Line ("Console Tic-Tac-Toe");
end Console_Tictactoe;
cd console_tictactoe
alr run

Note: Building console_tictactoe/console_tictactoe.gpr...
Setup
   [mkdir]        object directory for project Console_Tictactoe
Compile
   [Ada]          main.adb
Bind
   [gprbind]      main.bexch
   [Ada]          main.ali
Link
   [link]         main.adb
Build finished successfully in 1.15 seconds.
Console Tic-Tac-Toe

Sau khi chạy lệnh alr run lần đầu thì trong thư mục gốc của project sẽ xuất hiện thêm một số thư mục được tạo ra do alrgprbuild. Lúc này chúng ta có cấu trúc tổng quan của thư mục project như thế này:

console-tictactoe
├── alire
│   ├── alire.lock
│   └── config.toml
├── alire.toml
├── bin
│   └── console_tictactoe.exe
├── config
│   ├── console_tictactoe_config.ads
│   ├── console_tictactoe_config.gpr
│   └── console_tictactoe_config.h  
├── console_tictactoe.gpr
├── obj
│   ├── ...
│   └── console_tictactoe.o
├── share
└── src
    └── console_tictactoe.adb

Ở đây chúng ta có thể thực hiện chỉnh sửa các tệp cấu hình của project để điều khiển tiến trình biên dịch của gprbuild và thay đổi tên của tệp khởi chạy thành main.adbprocedure Main.

with "config/console_tictactoe_config.gpr";

project Console_Tictactoe is

   for Languages use ("Ada", "C");
   for Create_Missing_Dirs use "True";
   for Source_Dirs use ("src/**", "config");
   for Object_Dir use "obj";
   for Exec_Dir use "bin";
   for Main use ("main.adb");

   package Compiler is
      for Default_Switches ("Ada") use ("-gnat2020", "-gnata");
   end Compiler;

   package Binder is
      for Switches ("Ada") use ("-Es");
   end Binder;

   package Install is
      for Artifacts (".") use ("share");
   end Install;

end Console_Tictactoe;
  • Danh sách các ngôn ngữ Languages có thể sử dụng trong project được khai báo cụ thể và nếu muốn thì bạn có thể bổ sung thêm C.
  • Các thư mục chứa mã nguồn Source_Dirs sẽ sử dụng src/** để truy vấn cả các thư mục con bên trong thư mục src. Như vậy chúng ta sẽ có thể sắp xếp các tệp code thành các nhóm dễ dàng hơn.
  • Tệp code khởi chạy đổi tên thành main.adb.
  • Các tham số sử dụng cho lệnh gprbuild bao gồm:
    • -gnat2020 để hỗ trợ những tính năng mới nhất của ngôn ngữ.
    • -gnata để hỗ trợ tính năng kiểm thứ với assertion và cho phép sử dụng contract.
name = "console_tictactoe"
description = "The Tic-Tac-Toe Gameboard in Console Window"
version = "0.1.0"

...

executables = ["main"]

Tệp khai báo project của alire cũng cần chỉnh sửa lại tên tệp thực thi executables sau khi biên dịch xong là main. Thông thường thì gprbuild sẽ tạo ra tệp này cùng với các tệp hỗ trợ tiến trình biên dịch và đặt tất cả trong thư mục obj. Ở đây alire sẽ tự động chuyển tệp thực thi vào thư mục riêng có tên là bin.

Source Modules

Như đã nói trước đó thì chúng ta sẽ thiết kế các procedure xoay quanh các state. Và ở đây, chúng ta có các nhóm state là:

  • console-io – dữ liệu trạng thái của cửa sổ dòng lệnh nơi nhận tương tác nhập liệu của người sử dụng.
  • app-model – dữ liệu trạng thái mô tả bảng Tic-Tac-Toe trong suốt quá trình tương tác với người dùng.

Như vậy thư mục src của chúng ta sẽ có cấu trúc khởi đầu như thế này:

src
├── app-model
│   ├── app-model.adb
│   └── app-model.ads
├── console-io
│   ├── console_io.adb
│   └── console_io.ads
└── main.adb

Và bây giờ thì chúng ta sẽ bắt đầu viết code để tạo ra một gameboard Tic-Tac-Toe trên nền console.

[Procedural Programming + Ada] Bài 14 – 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 đầ