Bộ đôi thủ tục tiếp theo là Put_Chess_Board;
và Get_User_move;
lại rất tương đồng với đoạn xử lý Put_Symbol_Menu;
và Get (User_Symbol);
trước đó.
Put_Chess_Board;
Khởi đầu mỗi ván cờ, chúng ta sẽ có một bảng Tic-Tac-Toe với các ô được đánh số 1 .. 9
để người dùng có thể định vị và nhập lựa chọn ô muốn đánh dấu.
+ - - + - - + - - +
| 2 | 9 | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| 6 | 1 | 8 |
+ - - + - - + - - +
Và nếu như sử dụng cách đánh số các ô trên bảng như thế này thì khi kiểm tra để cập nhật Match_Status
sau mỗi bước đi của User
hoặc Computer
, thì chúng ta sẽ kiểm tra xem có bất kỳ bộ 3 số nào trong tập User_Set
hoặc Computer_Set
có tổng bằng 15
hay không. Nếu có, thì có nghĩa là User
hoặc Computer
đã hoàn thành được một đường thẳng nào đó trên bảng và thắng ván cờ đó.
Giả sử User_Symbol
là X
thì ký hiệu còn lại O
sẽ là của Computer
, và chúng ta sẽ tùy vào dữ liệu của User_Set
và Computer_Set
để ghi các ký hiệu tương ứng thay thế vào vị trí của các chữ số trong bảng Tic-Tac-Toe. Như vậy trình in Put_Chess_Board
này có phức tạp hơn Put_Symbol_Menu
một chút và ở vị trí của mỗi chữ số, chúng ta sẽ cần một function Area_Image
để xác định ký ký tự được in ra là ký hiệu X
hay O
, hay chính chữ số đó.
package Console_IO is
type Symbol is (X, O);
SYMBOL_CHOICE_ERROR : exception;
procedure Put_Symbol_Menu;
procedure Get (User_Symbol : out Symbol);
procedure Put_Chess_Board
( App_State : in State
; User_Symbol : in Symbol )
; -- return Nothing
function Area_Image
( Area : in Digit
; App_State : in State
; User_Symbol : in Symbol )
return String;
end Console_IO;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
package body Console_IO is
procedure Put_Symbol_Menu is ...
procedure Get (User_Symbol : out Symbol) is ...
procedure Put_Chess_Board
( App_State : in State
; User_Symbol : in Symbol ) is ...
function Area_Image
( Area : in Digit
; App_State : in State
; User_Symbol : in Symbol )
return String is ...
end Console_IO;
Trong Put_Chess_Board
thì chúng ta vẫn thực hiện in ra từng dòng copy/paste
từ kết quả dự kiến. Và ở vị trí của các chữ số thì chúng ta cần sử dụng coupling function
như đã nói ở trên để xác định ký tự sẽ được in ra.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
package body Console_IO is
-- ...
procedure Put_Chess_Board
( App_State : in State
; User_Symbol : in Symbol ) is
begin
Put_Line ("+ - - + - - + - - + ");
Put_Line ("| " & Area_Image (2, App_State, User_Symbol) & " | "
& Area_Image (9, App_State, User_Symbol) & " | "
& Area_Image (4, App_State, User_Symbol) & " | ");
Put_Line ("+ - - + - - + - - + ");
Put_Line ("| " & Area_Image (7, App_State, User_Symbol) & " | "
& Area_Image (5, App_State, User_Symbol) & " | "
& Area_Image (3, App_State, User_Symbol) & " | ");
Put_Line ("+ - - + - - + - - + ");
Put_Line ("| " & Area_Image (6, App_State, User_Symbol) & " | "
& Area_Image (1, App_State, User_Symbol) & " | "
& Area_Image (8, App_State, User_Symbol) & " | ");
Put_Line ("+ - - + - - + - - + ");
end Put_Chess_Board;
-- function Area_Image ...
end Console_IO;
Và ở Area_image
, thao tác kiểm tra chữ số được truyền vào đang thuộc *_Set
nào sẽ được ủy thác cho một function
khác để duy trì logic xử lý ký tự in ra với các nhánh lệnh dễ theo dõi.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
package body Console_IO is
-- ...
function Area_Image
( Area : in Digit
; App_State : in State
; User_Symbol : in Symbol )
return String is
Computer_Symbol : Symbol;
Result : String := "0";
begin
Computer_Symbol := (if User_Symbol = X then O else X);
--
if Found (Area, App_State.User_Set) then
Result := Symbol'Image (User_Symbol);
elsif Found (Area, App_State.Computer_Set) then
Result := Symbol'Image (Computer_Symbol);
else -- Found in App_State.Common_Set
case Area is
when 1 => Result := "1";
when 2 => Result := "2";
when 3 => Result := "3";
when 4 => Result := "4";
when 5 => Result := "5";
when 6 => Result := "6";
when 7 => Result := "7";
when 8 => Result := "8";
when 9 => Result := "9";
when others => Result := "0";
end case;
end if;
--
return Result;
end Area_Image;
end Console_IO;
Phép kiểm tra xem có tìm thấy Found
ô trống Area
trong một *_Set
nào đó hay không – rất có thể sẽ được sử dụng lại và không hẳn thuộc về mảng làm việc Input/Output
với cửa sổ Console
; Vì vậy nên chúng ta sẽ định nghĩa tại package App_Model
.
package App_Model is
-- ...
function Found (Area : Digit; Move_Set : Digit_Array)
return Boolean;
end App_Model;
package body App_Model is
-- procedure Init ...
function Found
( Area : Digit
; Move_Set : Digit_Array )
return Boolean is
Result : Boolean := FALSE;
begin
for Index in Move_Set'Range loop
if Area = Move_Set (Index) then
Result := TRUE;
end if;
end loop;
--
return Result;
end Found;
end App_Model;
Và cuối cùng là code sử dụng ở Main
, chúng ta sẽ tạm thời thêm vào một vài câu lệnh để thể hiện một bước đi của User
và một bước đi của Computer
ở phía trước câu lệnh in bảng để kiểm tra logic hoạt động của Area_Image
và `Found (Area, Move_Set).
with Ada.Text_IO; use Ada.Text_IO;
with App_Model; use App_Model;
with Console_IO; use Console_IO;
procedure Main is
User_Symbol : Symbol;
App_State : State;
begin
Put_Symbol_Menu;
Get (User_Symbol);
Init (App_State);
-- loop
Put_Chess_Board (App_State, User_Symbol);
--
Put_Line ("User Moved: 1");
App_State.Common_Set (1) := 0;
App_State.User_Set (1) := 1;
--
Put_Line ("Computer Moved: 9");
App_State.Common_Set (9) := 0;
App_State.Computer_Set (9) := 9;
--
Put_Chess_Board (App_State, User_Symbol);
-- 4. Get_User_Move
-- 5. Update_User_Set
-- 6. Update_Match_Status
--
-- 7. Put_Chess_Board
-- 8. Get_Computer_Move
-- 9. Update_Computer_Set
-- 10. Update_Match_Status
--
-- exit when App_State.Match_Status /= PLAYING;
-- 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 |
+ - - + - - + - - +
User Moved: 1
Computer Moved: 9
+ - - + - - + - - +
| 2 | O | 4 |
+ - - + - - + - - +
| 7 | 5 | 3 |
+ - - + - - + - - +
| 6 | X | 8 |
+ - - + - - + - - +
Get_User_Move;
Thao tác Get_User_Move;
cũng có thể thiết kế với cú pháp sử dụng giống như Get (User_Symbol);
trước đó. và kết quả sẽ được lưu lại vào biến cục bộ User_move
của procedure Main
. Trong trường hợp giá trị người dùng nhập vào ngoài khoảng 1 .. 9
thì chúng ta sẽ cần phải phát động ngoại lệ để đưa ra thông báo và yêu cầu thực hiện lại việc nhập liệu.
with App_Model; use App_Model;
package Console_IO is
type Symbol is (X, O);
SYMBOL_CHOICE_ERROR : exception;
MOVE_CHOICE_ERROR : exception;
procedure Put_Symbol_Menu;
procedure Get (User_Symbol : out Symbol);
procedure Put_Chess_Board ...
procedure Get (User_Move : out Digit);
function Area_Image ...
return String;
end Console_IO;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Exceptions; use Ada.Exceptions;
package body Console_IO is
-- ...
procedure Get (User_Move : out Digit) is
User_Input : String := "0";
Chosen_Number : Integer;
begin
Put ("Your move: "); Get (User_Input);
Chosen_Number := Integer'Value (User_Input);
case Chosen_Number is
when 0 => raise MOVE_CHOICE_ERROR;
when others => User_Move := Chosen_Number;
end case;
exception
when others =>
Put_Line ("Choice number should be in 1 .. 9");
Get (User_Move);
-- end when
end Get;
-- function Area_Image ...
end Console_IO;
Và ở code sử dụng tại Main
chúng ta sẽ tạm thời thêm lệnh Put_Line
để kiểm tra kết quả nhập liệu.
with Ada.Text_IO; use Ada.Text_IO;
with App_Model; use App_Model;
with Console_IO; use Console_IO;
procedure Main is
User_Symbol : Symbol;
App_State : State;
User_Move : Digit;
begin
Put_Symbol_Menu;
Get (User_Symbol);
Init (App_State);
-- loop
Put_Chess_Board (App_State, User_Symbol);
Get (User_Move); Put_Line ("User Moved: " & Digit'Image (User_Move));
-- 5. Update_User_Set
-- 6. Update_Match_Status
--
-- 7. Put_Chess_Board
-- 8. Get_Computer_Move
-- 9. Update_Computer_Set
-- 10. Update_Match_Status
--
-- exit when App_State.Match_Status /= PLAYING;
-- end loop
end Main;
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: 0
Choice number should be in 1 .. 9
Your move: A
Choice number should be in 1 .. 9
Your move: 1
User Moved: 1
(chưa đăng tải) [Procedural Programming + Ada] Bài 20 – Console Tic-Tac-Toe App (tiếp theo)
Nguồn: viblo.asia