Sophie

Sophie

distrib > Fedora > 15 > i386 > by-pkgid > 5154a2138f2e08b5b9cc20341b38f491 > files > 186

PragmARC-devel-20060427-9.fc15.i686.rpm

-- The solitaire game, The Devil, for ANSI-standard displays
-- Demonstrates the use of PragmARC.Deck_Handler & PragmARC.US_card
--
with Ada.Text_Io;
with PragmARC.Ansi_Tty_Control;
with PragmARC.Us_Card;
with PragmARC.Us_Deck;
with PragmARC.Get_Line;
with Ada.Characters.Handling;
with Ada.Characters.Latin_1;

use Ada;
use Ada.Characters;
use PragmARC;
procedure Devil is
   type Game_Result is (Quit, Again);

   procedure Prepare_Screen is
      -- null;
   begin -- Prepare_Screen
      Text_Io.Put (Ansi_Tty_Control.Clear_Screen);
      Text_Io.Put (Ansi_Tty_Control.Bold_Mode);
      Text_Io.Put ("Devil");
      Text_Io.Put (Ansi_Tty_Control.Normal_Mode);
      Text_Io.Put (Ansi_Tty_Control.Position (2, 6) );
      Text_Io.Put ("1  2  3  4");
      Text_Io.Put (Ansi_Tty_Control.Position (19, 1) );
      Text_Io.Put_Line ("Q    Quit Devil                         A      Deal Again");
      Text_Io.Put_Line ("<CR> Turn over three cards              PzFy   Move card pile Z => foundation Y");
      Text_Io.Put_Line ("HF#  Move card hand => foundation #     PxPw   Move pile X onto pile W");
      Text_Io.Put_Line ("HP#  Move card hand => pile #           FzPy   Move card foundation Z => pile Y");
      Text_Io.Put_Line ("SF#  Move card stock => foundation #    CnPzPy Move N cards pile Z => pile Y");
      Text_Io.Put_Line ("SP#  Move card stock => pile #");
   end Prepare_Screen;

   function Play_Game return Game_Result is
      subtype Index_Value is Integer range 1 .. 4;

      subtype Deck_52 is Us_Deck.Deck_52;

      type Stack_Set is array (Index_Value) of Deck_52;

      Foundation : Stack_Set;
      Stack : Stack_Set;
      Stock : Deck_52;
      Exposed : Deck_52;
      Hidden : Deck_52;
      Card : Us_Card.Card_Handle;
      Spare : Deck_52;
      Count : Positive;
      Index_From : Index_Value;
      Index_To : Index_Value;

      Rule_Violation : exception;
      Invalid_Command : exception;

      function "=" (Left : Us_Card.Rank_Id; Right : Us_Card.Rank_Id) return Boolean renames Us_Card."=";
      function "=" (Left : Us_Card.Suit_Id; Right : Us_Card.Suit_Id) return Boolean renames Us_Card."=";

      function Upper (Char : Character) return Character renames Characters.Handling.To_Upper;

      procedure Put (Card : in Us_Card.Card_Handle) is
         -- null;
      begin -- Put
         case Us_Card.Suit (Card) is
         when Us_Card.Diamond | Us_Card.Heart =>
            Text_Io.Put (Ansi_Tty_Control.Reverse_Video);
         when others =>
            null;
         end case;

         Text_Io.Put (Item => Us_Card.Image (Card) );
         Text_Io.Put (Ansi_Tty_Control.Normal_Mode);
      end Put;

      procedure Display (Foundation : in Stack_Set; Stack : in Stack_Set; Stock : in Deck_52; Exposed : in Deck_52) is
         package Integer_Io is new Text_Io.Integer_Io (Num => Integer);
      begin -- Display
         Text_Io.Put (Ansi_Tty_Control.Position (5, 1) );
         Clear_All : for Line in 5 .. 16 loop
            Text_Io.Put_Line (Ansi_Tty_Control.Clear_End_Of_Line);
         end loop Clear_All;
         
         Text_Io.Put (Ansi_Tty_Control.Clear_End_Of_Line);

         Text_Io.Put (Ansi_Tty_Control.Position (3, 5) );
         
         All_Foundations : for F in Foundation'range loop
            if Us_Deck.Deck.Is_Empty (Foundation (F) ) then
               Text_Io.Put ("   ");
            else
               Put (Card => Us_Deck.Deck.Value (Foundation (F), Us_Deck.Deck.Size (Foundation (F) ) ) );
               Text_Io.Put (' ');
            end if;
         end loop All_Foundations;

         Text_Io.Put (Ansi_Tty_Control.Position (5, 1) );
         
         Stock_Cards : for S in 1 .. Us_Deck.Deck.Size (Stock) loop
            Put (Card => Us_Deck.Deck.Value (Stock, S) );
            Text_Io.New_Line;
         end loop Stock_Cards;

         All_Stacks : for S in Stack'range loop
            All_Cards : for C in 1 .. Us_Deck.Deck.Size (Stack (S) ) loop
               Text_Io.Put (Ansi_Tty_Control.Position (C + 4, 5 + 3 * (S - 1) ) );
               Put (Card => Us_Deck.Deck.Value (Stack (S), C) );
            end loop All_Cards;
         end loop All_Stacks;

         Text_Io.Put (Ansi_Tty_Control.Position (5, 25) );
         Text_Io.Put ("Hand (");
         Integer_Io.Put (Us_Deck.Deck.Size (Exposed), Width => 2);
         Text_Io.Put ("):  ");

         if Us_Deck.Deck.Size (Exposed) >= 3 then
            Put (Card => Us_Deck.Deck.Value (Exposed, Us_Deck.Deck.Size (Exposed) - 2) );
            Text_Io.Put (' ');
         end if;

         if Us_Deck.Deck.Size (Exposed) >= 2 then
            Put (Card => Us_Deck.Deck.Value (Exposed, Us_Deck.Deck.Size (Exposed) - 1) );
            Text_Io.Put (' ');
         end if;

         if Us_Deck.Deck.Size (Exposed) >= 1 then
            Put (Card => Us_Deck.Deck.Value (Exposed, Us_Deck.Deck.Size (Exposed) ) );
         end if;

         Text_Io.Put (Ansi_Tty_Control.Position (7, 25) );
         Text_Io.Put ("Command:  ");
      end Display;

      procedure Check_To_Foundation (From_Card : in Us_Card.Card_Handle; Index_To : in Index_Value) is
         To_Card : Us_Card.Card_Handle;
      begin -- Check_To_Foundation
         if Us_Deck.Deck.Is_Empty (Foundation (Index_To) ) then
            if Us_Card.Rank (From_Card) /= Us_Card.Rank (Us_Deck.Deck.Value (Foundation (1), 1) ) then
               raise Rule_Violation;
            end if;

            return;
         end if;

         To_Card := Us_Deck.Deck.Value (Foundation (Index_To), Us_Deck.Deck.Size (Foundation (Index_To) ));

         if Us_Card.Suit (From_Card) /= Us_Card.Suit (To_Card) then
            raise Rule_Violation;
         end if;

         if Us_Card.Rank (To_Card) = Us_Card.Rank_Id'Last then
            if Us_Card.Rank (From_Card) /= Us_Card.Rank_Id'First then
               raise Rule_Violation;
            end if;
         elsif Us_Card.Rank (From_Card) /= Us_Card.Rank_Id'Succ (Us_Card.Rank (To_Card) ) then
            raise Rule_Violation;
         else
            null;
         end if;
      end Check_To_Foundation;

      procedure Check_To_Stack (From_Card : in Us_Card.Card_Handle; Index_To : in Index_Value) is
         To_Card : Us_Card.Card_Handle;
      begin -- Check_To_Stack
         if Us_Deck.Deck.Is_Empty (Stack (Index_To) ) then
            return;
         end if;

         To_Card := Us_Deck.Deck.Value (Stack (Index_To), Us_Deck.Deck.Size (Stack (Index_To) ));

         if ( (Us_Card.Suit (From_Card) = Us_Card.Diamond or else Us_Card.Suit (From_Card) = Us_Card.Heart) and then
              (Us_Card.Suit (To_Card) = Us_Card.Diamond or else Us_Card.Suit (To_Card) = Us_Card.Heart)
            ) or else
            ( (Us_Card.Suit (From_Card) = Us_Card.Club or else Us_Card.Suit (From_Card) = Us_Card.Spade) and then
              (Us_Card.Suit (To_Card) = Us_Card.Club or else Us_Card.Suit (To_Card) = Us_Card.Spade)
            )
         then
            raise Rule_Violation;
         end if;

         if Us_Card.Rank (To_Card) = Us_Card.Rank_Id'First then
            if Us_Card.Rank (From_Card) /= Us_Card.Rank_Id'Last then
               raise Rule_Violation;
            end if;
         elsif Us_Card.Rank (From_Card) /= Us_Card.Rank_Id'Pred (Us_Card.Rank (To_Card) ) then
            raise Rule_Violation;
         else
            null;
         end if;
      end Check_To_Stack;
   begin -- Play_Game
      Us_Deck.Standard_Deck (Item => Hidden);
      Us_Deck.Deck.Shuffle (Item => Hidden);

      Init_Stacks : for S in Stack'range loop
         Us_Deck.Deck.Deal (From => Hidden, To => Card);
         Us_Deck.Deck.Add (Item => Card, To => Stack (S) );
      end loop Init_Stacks;

      Us_Deck.Deck.Deal (From => Hidden, To => Card);
      Us_Deck.Deck.Add (Item => Card, To => Foundation (1) );

      Fill_Stock : for I in 1 .. 13 loop
         Us_Deck.Deck.Deal (From => Hidden, To => Card);
         Us_Deck.Deck.Add (Item => Card, To => Stock);
      end loop Fill_Stock;

      Text_Io.Put (Ansi_Tty_Control.Position (3, 1) ); -- Display foundations' base rank
      Put (Us_Deck.Deck.Value (Foundation (1), 1) );
      Text_Io.Put (Ansi_Tty_Control.Position (3, 2) & ' ');

      All_Actions : loop
         Display (Foundation => Foundation, Stack => Stack, Stock => Stock, Exposed => Exposed);

         Handle_Command : declare
            Command : constant String := Get_Line;
         begin -- handle_command
            if Command'Length < 1 then
               if Us_Deck.Deck.Is_Empty (Hidden) then
                  Us_Deck.Deck.Assign (To => Hidden, From => Exposed);
                  Us_Deck.Deck.Make_Empty (Item => Exposed);
               end if;

               Turn_3 : for I in 1 .. 3 loop
                  exit Turn_3 when Us_Deck.Deck.Is_Empty (Hidden);

                  Us_Deck.Deck.Deal (From => Hidden, To => Card);
                  Us_Deck.Deck.Add (Item => Card, To =>Exposed);
               end loop Turn_3;
            elsif Upper (Command (1) ) = 'T' then
               if Us_Deck.Deck.Is_Empty (Hidden) then
                  Us_Deck.Deck.Assign (To => Hidden, From => Exposed);
                  Us_Deck.Deck.Make_Empty (Item => Exposed);
               end if;

               if not Us_Deck.Deck.Is_Empty (Hidden) then
                  Us_Deck.Deck.Deal (From => Hidden, To => Card);
                  Us_Deck.Deck.Add (Item => Card, To =>Exposed);
               end if;
            elsif Upper (Command (1) ) = 'Q' then
               return Quit;
            elsif Upper (Command (1) ) = 'A' then
               return Again;
            elsif Command'Length >= 3 and then Upper (Command (1) ) = 'H' then
               Index_To := Integer'Value (Command (3 .. 3) );
               Card := Us_Deck.Deck.Value (Exposed, Us_Deck.Deck.Size (Exposed) );

               if Upper (Command (2) ) = 'F' then
                  Check_To_Foundation (Card, Index_To);
                  Us_Deck.Deck.Remove (From => Exposed, Position => Us_Deck.Deck.Size (Exposed), To => Card);
                  Us_Deck.Deck.Add (Item => Card, To => Foundation (Index_To) );
               elsif Upper (Command (2) ) = 'P' then
                  Check_To_Stack (Card, Index_To);
                  Us_Deck.Deck.Remove (From => Exposed, Position => Us_Deck.Deck.Size (Exposed), To => Card);
                  Us_Deck.Deck.Add (Item => Card, To =>Stack (Index_To) );
               else
                  raise Invalid_Command;
               end if;
            elsif Command'Length >= 3 and then Upper (Command (1) ) = 'S' then
               Index_To := Integer'Value (Command (3 .. 3) );
               Card := Us_Deck.Deck.Value (Stock, Us_Deck.Deck.Size (Stock) );

               if Upper (Command (2) ) = 'F' then
                  Check_To_Foundation (Card, Index_To);
                  Us_Deck.Deck.Remove (From => Stock, Position => Us_Deck.Deck.Size (Stock), To => Card);
                  Us_Deck.Deck.Add (Item => Card, To => Foundation (Index_To) );
               elsif Upper (Command (2) ) = 'P' then
                  Check_To_Stack (Card, Index_To);
                  Us_Deck.Deck.Remove (From => Stock, Position => Us_Deck.Deck.Size (Stock), To => Card);
                  Us_Deck.Deck.Add (Item => Card, To => Stack (Index_To) );
               else
                  raise Invalid_Command;
               end if;
            elsif Command'Length >= 4 and then Upper (Command (1) ) = 'P' then
               Index_From := Integer'Value (Command (2 .. 2) );
               Index_To := Integer'Value (Command (4 .. 4) );

               if Upper (Command (3) ) = 'F' then
                  Card := Us_Deck.Deck.Value (Stack (Index_From), Us_Deck.Deck.Size (Stack (Index_From) ));
                  Check_To_Foundation (Card, Index_To);
                  Us_Deck.Deck.Remove (From => Stack (Index_From),
                                       Position => Us_Deck.Deck.Size (Stack (Index_From) ),
                                       To => Card
                                      )
                  ;
                  Us_Deck.Deck.Add (Item => Card, To => Foundation (Index_To) );
               elsif Upper (Command (3) ) = 'P' then
                  Card := Us_Deck.Deck.Value (Stack (Index_From), 1);
                  Check_To_Stack (Card, Index_To);

                  Transfer : loop
                     exit Transfer when Us_Deck.Deck.Is_Empty (Stack (Index_From) );

                     Us_Deck.Deck.Deal (From => Stack (Index_From), To => Card);
                     Us_Deck.Deck.Add (Item => Card, To => Stack (Index_To) );
                  end loop Transfer;
               else
                  raise Invalid_Command;
               end if;

               if Us_Deck.Deck.Is_Empty (Stack (Index_From) ) and then not Us_Deck.Deck.Is_Empty (Stock) then
                  Us_Deck.Deck.Remove (From => Stock, Position => Us_Deck.Deck.Size (Stock), To => Card);
                  Us_Deck.Deck.Add (Item => Card, To => Stack (Index_From) );
               end if;
            elsif Command'Length >= 4 and then Upper (Command (1) ) = 'F' then
               Index_From := Integer'Value (Command (2 .. 2) );
               Index_To := Integer'Value (Command (4 .. 4) );

               if Upper (Command (3) ) /= 'P' then
                  raise Invalid_Command;
               end if;

               Card := Us_Deck.Deck.Value (Foundation (Index_From), Us_Deck.Deck.Size (Foundation (Index_From) ));
               Check_To_Stack (Card, Index_To);
               Us_Deck.Deck.Remove (From => Foundation (Index_From),
                                    Position => Us_Deck.Deck.Size (Foundation (Index_From) ),
                                    To => Card
                                   )
               ;
               Us_Deck.Deck.Add (Item => Card, To => Stack (Index_To) );
            elsif Command'Length >= 6 and then Upper (Command (1) ) = 'C' then
               Count := Integer'Value (Command (2 .. 2) );
               Index_From := Integer'Value (Command (4 .. 4) );
               Index_To := Integer'Value (Command (6 .. 6) );

               if Upper (Command (3) ) /= 'P' or else Upper (Command (5) ) /= 'P' then
                  raise Invalid_Command;
               end if;

               if Count > Us_Deck.Deck.Size (Stack (Index_From) ) then
                  raise Invalid_Command;
               end if;

               Card := Us_Deck.Deck.Value (Stack (Index_From), Us_Deck.Deck.Size (Stack (Index_From) ) - Count + 1);
               Check_To_Stack (Card, Index_To);
               Us_Deck.Deck.Make_Empty (Item => Spare);

               Remove : for I in 1 .. Count loop
                  Us_Deck.Deck.Remove (From => Stack (Index_From),
                                       Position => Us_Deck.Deck.Size (Stack (Index_From) ),
                                       To => Card
                                      )
                  ;
                  Us_Deck.Deck.Add (Item => Card, To => Spare);
               end loop Remove;

               Add : for I in 1 .. Count loop
                  Us_Deck.Deck.Remove (From => Spare, Position => Us_Deck.Deck.Size (Spare), To => Card);
                  Us_Deck.Deck.Add (Item => Card, To => Stack (Index_To) );
               end loop Add;
            else
               raise Invalid_Command;
            end if;
         exception -- Handle_Command
         when others =>
            Text_Io.Put (Latin_1.Bel);
         end Handle_Command;
      end loop All_Actions;
   end Play_Game;
begin -- Devil
   Prepare_Screen;

   All_Games : loop
      exit All_Games when Play_Game = Quit;
   end loop All_Games;

   Text_Io.Put (Ansi_Tty_Control.Clear_Screen);
end Devil;
--
-- Copyright (C) 2002 by PragmAda Software Engineering.  All rights reserved.
--
-- This is free software; you can redistribute it and/or modify it under
-- terms of the GNU General Public License as published by the Free Software
-- Foundation; either version 2, or (at your option) any later version.
-- This software is distributed in the hope that it will be useful, but WITH
-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-- for more details. Free Software Foundation, 59 Temple Place - Suite
-- 330, Boston, MA 02111-1307, USA.