The final procedure in the User
‘s move is to update the state of the Update_Match_Status;
. This procedure will also be reused on Computer
‘s move just like Put_Chess_Board;
. So we write forked code that includes all the potential states of Match_Status
defined by type Status
:
- Will be
USER_WIN
– ifUser_Set
has at least one set of winning numbers. - Or
COMPUTER_WIN
– ifComputer_Set
has at least one winning set. - Or
DRAW
– ifCommon_Set
has no more meaningful values and the chessboard is empty. - Or
PLAYING
– if all of the above are not present.
Therefore we will have additional support function
as Found_Wining (Move_Set);
and Found_Empty (Move_Set);
to check if any *_Set
contains a winning set, and check if any *_Set
is empty.
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 28 29 30 31 32 33 34 35 36 | package App_Model is subtype Digit is Integer range 0 .. 9; type Digit_Array is array (1 .. 9) of Digit; type Status is (PLAYING, DRAW, USER_WIN, COMPUTER_WIN); type State is record Common_Set : Digit_Array; User_Set : Digit_Array; Computer_Set : Digit_Array; Match_Status : Status; end record; procedure Init (App_State : out State) with Post => Areas_Are_Unique (App_State) and Sets_Are_Complement (App_State); 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_Match_Status (App_State : in out State); -- - new function Areas_Are_Unique (App_State : State) return Boolean; function Sets_Are_Complement (App_State : State) return Boolean; function Found (Area : Digit; Move_Set : Digit_Array) return Boolean; function Found_Winning (Move_Set : Digit_Array) -- - new return Boolean; function Found_Empty (Move_Set : Digit_Array) -- - new return Boolean; end App_Model; |
Update_Match_Status;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package body App_Model is -- ... procedure Update_Match_Status (App_State : in out State) is -- local begin if Found_Winning (App_State.User_Set) then App_State.Match_Status := USER_WIN; elsif Found_Winning (App_State.Computer_Set) then App_State.Match_Status := COMPUTER_WIN; elsif Found_Empty (App_State.Common_Set) then App_State.Match_Status := DRAW; else App_State.Match_Status := PLAYING; end if; end Update_Match_Status; end App_Model; |
Found_Winning;
Testing for the presence of at least one set of winning numbers in User_Set
or Computer_Set
can be done in different ways:
- List the winning sets then check for the presence of each of those sets in the
Move_Set
passed to thefunction
. - Or get each set of numbers in
Move_Set
to check the total value. If at least one set of numbers sums to 15, returnTRUE
.
The first test can be applied to any numbering scheme on the chessboard. The second method can only be applied if the chessboard is numbered as we are currently using.
1 2 3 4 5 6 7 8 | + - - + - - + - - + | 2 | 9 | 4 | + - - + - - + - - + | 7 | 5 | 3 | + - - + - - + - - + | 6 | 1 | 8 | + - - + - - + - - + |
Any straight line between two opposite edges of the chessboard in this case will always pass through the cells forming a set of numbers that sums to 15
.
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 28 29 30 31 32 33 | package body App_Model is -- ... function Found_Winning (Move_Set : Digit_Array) return Boolean is -- local Total : Integer; Result : Boolean := FALSE; begin for I1 in 1 .. 7 loop for I2 in 2 .. 8 loop for I3 in 3 .. 9 loop Total := Move_Set (I1) + Move_Set (I2) + Move_Set (I3); if Total = 15 and Move_Set (I1) /= 0 and Move_Set (I2) /= 0 and Move_Set (I3) /= 0 and Move_Set (I1) /= Move_Set (I2) and Move_Set (I2) /= Move_Set (I3) and Move_Set (I3) /= Move_Set (I1) then Result := TRUE; end if; end loop; end loop; end loop; -- return Result; end Found_Winning; end App_Model; |
Found_Empty;
The function checks whether a passed Move_Set
is empty or not.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package body App_Model is -- ... function Found_Empty (Move_Set : Digit_Array) return Boolean is -- local Result : Boolean := TRUE; begin for Index in Move_Set'Range loop if Move_Set (Index) /= 0 then Result := FALSE; end if; end loop; -- return Result; end Found_Empty; end App_Model; |
Main;
And finally the code used in Main
, we will try Update_User_Move;
add few steps to check Update_Match_Status;
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 28 29 30 31 32 33 34 35 | 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); Put_Chess_Board (App_State, User_Symbol); -- loop for I in 1 .. 3 loop 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); end loop; -- -- 9. Get_Computer_Move; -- 10. Update_Computer_Set; -- 11. Update_Match_Status; -- 12. Put_Chess_Board; -- -- exit when App_State.Match_Status /= PLAYING; -- end loop end Main; |
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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 | + - - + - - + - - + Your move: 5 PLAYING ... + - - + - - + - - + | 2 | 9 | 4 | + - - + - - + - - + | 7 | X | 3 | + - - + - - + - - + | 6 | X | 8 | + - - + - - + - - + Your move: 9 USER_WIN ... + - - + - - + - - + | 2 | X | 4 | + - - + - - + - - + | 7 | X | 3 | + - - + - - + - - + | 6 | X | 8 | + - - + - - + - - + |