We’ll start the code off naturally with the procedure Main
and comment
on the steps to take in the code.
- As soon as we launch the
app
, we will need to print an option screen for theUser
to choose theX
orO
symbol to write to theTic-Tac-Toe
table and show the steps of theUser
and theComputer
. - Scan the
User
‘s input selection and save theUser_Symbol
state. - After the user has selected the wildcard, the
app
needs to initialize aState
that stores the state of thegameboard
including the steps of theUser
, and the steps of theComputer
, and also the remaining empty cells. ThisState
may contain additional states such as theMatch_Status
to indicate that the game is over after a certain move by theUser
orComputer
.
For a simple start, we will default that User
will always take the first step. And the sequence of the next procedure
to perform is:
- Print out the
Tic-Tac-Toe
so that theUser
can monitor the current state of thegameboard
and calculate the step. - Get input results to describe the step the
User
wants to take. - Update the
State
of the application corresponding to the last step of theUser
. - Check the status of the
gameboard
to see if the game is over. If it is over, thenUser
wins or the result is a draw.
Similarly, with the Computer
‘s turn, we also have the same procedures as above:
- Print out the
Tic-Tac-Toe
so that theUser
can monitor the current state of thegameboard
and calculate the step. - Calls the sequence to create moves for the
Computer
based on the state of the currentgameboard
. - Update the
State
of the application corresponding to the last step ofComputer
. - Check the status of the
gameboard
to see if the game is over. If it is over, then theComputer
wins or the result is a draw.
After a move of User
and Computer
like this, we just need to repeat the procedure from 3 .. 10
until the game is over.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | with Ada.Text_IO; use Ada.Text_IO; with App_Model; use App_Model; with Console_IO; use Console_IO; procedure Main is -- local begin -- 0. Put_Symbol_Menu; -- 1. Get_User_Symbol; -- -- 2. Init_App_State; -- loop -- 3. Put_Chess_Board; -- 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; |
Put_Symbol_Menu;
This is the expected output of Put_Symbol_Menu;
and Get_User_Symbol;
:
1 2 3 4 5 | Choose your Symbol ... 1. Letter 'X' 2. Letter 'O' Your choice: |
We can design the usage syntax of these initialization procedure
in a similar form to Put (Symbol_Menu);
and Get (User_Symbol);
of the Ada.Text_IO
library that we already know. However, for such a Put
operation, defining a constant
containing the entire contents of Symbol_Menu
formatted as lines and indented spaces as above will be quite cumbersome in Ada
.
So here we will perform the Put_Symbol_Menu
operation with the contents of menu
placed directly inside this procedure
, and format it by printing it line by line. And the Get_User_Symbol
operation will be designed as Get (User_Symbol);
About saving the symbol type that User
has selected, temporarily we will define an enum Symbol
and store it in a local variable of the procedure Main
.
And in case the selection entered by the user is not valid then we need to add a self-defined exception Error
to raise
and re-process the operation that requires the selection input.
1 2 3 4 5 6 7 8 9 | package Console_IO is type Symbol is (X, O); SYMBOL_CHOICE_ERROR : exception; procedure Put_Symbol_Menu; procedure Get (User_Symbol : out Symbol); end Console_IO; |
1 2 3 4 5 6 7 8 | package body Console_IO is procedure Put_Symbol_Menu is ... ; procedure Get (User_Symbol : out Symbol) is ... ; end Console_IO; |
The implementation code of Put_Symbol_Menu;
then there’s nothing to note because we’re simply Put_Line
line-by-line in the desired result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | with Ada.Text_IO; use Ada.Text_IO; package body Console_IO is procedure Put_Symbol_Menu is -- local begin Put_Line ("Choose your Symbol ..."); Put_Line (" 1. Letter 'X'"); Put_Line (" 2. Letter 'O'"); end Put_Symbol_Menu; procedure Get (User_Symbol : out Symbol) is ... ; end Console_IO; |
Get(User_Symbol);
Get (User_Symbol)
is also quite simple and the order to do is that we will Put
Your choice:
so that the cursor does not jump to a new line and the User
‘s input content will appear on the same line. Then perform the Get (User_Input)
to display the input pointer and receive the information string.
All that remains is to convert the input string to the integer value Chosen_Number
because the contents of menu
are suggesting the user enter 1
or 2
to choose the X
or O
symbol. Then create a conditional structure to assign the appropriate result to the User_Symbol
parameter, or raise SYMBOL_CHOICE_ERROR
if the user enters an invalid choice.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | with Ada.Text_IO; use Ada.Text_IO; package body Console_IO is procedure Put_Symbol_Menu is ... procedure Get (User_Symbol : out Symbol) is User_Input : String := "9"; Chosen_Number : Integer := 9; begin Put ("Your choice: "); Get (User_Input); Chosen_Number := Integer'Value (User_Input); case Chosen_Number is when 1 => User_Symbol := X; when 2 => User_Symbol := O; when others => raise SYMBOL_CHOICE_ERROR; end case; Put_Line ("You've chosen: " & Symbol'Image (User_Symbol)); exception when others => Put_Line ("Choice number should be 1 or 2 ..."); Get (User_Symbol); -- end when end Get; |
The body of the procedure
is a begin .. exception .. end
block here which is still quite easy to follow because the code to be executed is not very long. As for the exception
, here we can use others
to include other exceptions such as converting the data type from User_Input
to Chosen_Number
.
Another note is that the procedure Get
that we define ourselves will be considered an overload
version of Ada.Text_IO.Get
. With a symbol signature Get (out Symbol)
can be easily distinguished by the compiler from Ada.Text_IO
‘s Get (out String)
. So when we use Get (User_Input)
at the beginning of the procedure
and then call Get (User_Symbol)
in the exception
, there will be no need to refer to the name of the package
to distinguish.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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; begin Put_Symbol_Menu; Get (User_Symbol); -- -- 2. Init_App_State; -- loop -- 3. Put_Number_Board -- 4. Get_User_Move -- 5. Update_User_Set -- 6. Update_Match_Status -- -- 7. Put_Number_Board -- 8. Get_Computer_Move -- 9. Update_Computer_Set -- 10. Update_Match_Status -- -- exit when App_State.Match_Status /= PLAYING; -- end loop; end Main; |
Finally, the code used at
Main
, we need to add a local variable User_Symbol
to store the symbol that the user has selected during the game.1 2 3 4 5 6 7 8 9 10 11 12 | alr run Choose your Symbol ... 1. Letter 'X' 2. Letter 'O' Your choice: A Choice number should be 1 or 2 ... Your choice: 9 Choice number should be 1 or 2 ... Your choice: 1 You've chosen: X |