with Text_IO;
with Ada.Integer_Text_IO;
with Ada.Strings.Fixed;
with Ada.Strings.Maps.Constants;
with Ada.Strings.Unbounded;
with Ada.Numerics.Discrete_Random;
with GNAT.IO;
use GNAT.IO;
use Ada.Strings.Unbounded;
procedure Aceyducey is
   package Boolean_IO is new Text_IO.Enumeration_IO(Boolean);
   use Boolean_IO;
   Running: Boolean;
   GameOver: Boolean;
   Wallet: Integer;
   Cards: Array(1..3) of Integer;
   Bet: Integer;
   function GetIntInput(Prompt: String) return Integer is
      Val: Integer;
   begin
      Text_IO.Put(Prompt & " ");
      Ada.Integer_Text_IO.Get(Val);
      Text_IO.Put_Line("");
      return Val;
   end GetIntInput;
   function AskForBet return Integer is
      Bet: Integer;
   begin
      <<afb_Loop>>
      Bet := GetIntInput("WHAT IS YOUR BET?");
      if Bet < 0 then
         Text_IO.Put_Line("PLEASE BET A NON-NEGATIVE AMOUNT.");
         goto afb_Loop;
      elsif Bet > Wallet then
         Text_IO.Put_Line("SORRY MY FRIEND, BUT YOU BET TOO MUCH.");
         Text_IO.Put_Line("YOU HAVE ONLY" & Integer'Image(Wallet) & " DOLLARS TO BET.");
         goto afb_Loop;
      end if;
      return Bet;
   End AskForBet;
   function AskQuestion(Prompt: String; Skip: Boolean) return Boolean is
      Answer: Boolean;
      Ans: String(1..3);
      Len: Integer;
      DoSkip: Boolean := Skip;
   begin
      <<aq_Loop>>
      if DoSkip = TRUE then
         Text_IO.Skip_Line;
      end if;
      Text_IO.Put(Prompt & "? ");
      Text_IO.Get_Line(Ans, Len);
      Ans := Ada.Strings.Fixed.Translate(Ans, Ada.Strings.Maps.Constants.Upper_Case_Map);
      if Ans(1..1) = "Y" or Ans = "YES" then
         Answer := TRUE;
      elsif Ans(1..1) = "N" or Ans(1..2) = "NO" then
         Answer := FALSE;
      else
         Text_IO.Put_Line("PLEASE ANSWER ""YES"" OR ""NO"".");
         DoSkip := TRUE;
         goto aq_Loop;
      end if;
      return Answer;
   end AskQuestion;
   function AskToPlayAgain return Boolean is
   begin
      return AskQuestion("DO YOU WANT TO PLAY AGAIN", TRUE);
   end AskToPlayAgain;
   function AskToSeeTheRules return Boolean is
   begin
      return AskQuestion("DO YOU WANT TO SEE THE RULES", FALSE);
   end AskToSeeTheRules;
   procedure DisplayCard(Card: Integer) is
   begin
      if Card = 11 then
         Text_IO.Put_Line("JACK");
      elsif Card = 12 then
         Text_IO.Put_Line("QUEEN");
      elsif Card = 13 then
         Text_IO.Put_Line("KING");
      elsif Card = 14 then
         Text_IO.Put_Line("ACE");
      else
         Text_IO.Put_Line(Integer'Image(Card));
      end if;
   end DisplayCard;
   procedure DisplayRules is
   begin
      Text_IO.Put_Line("ACEY DUCEY IS PLAYED IN THE FOLLOWING MANNER:");
      Text_IO.Put_Line("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP");
      Text_IO.Put_Line("YOU HAVE THE OPTION TO BET OR NOT BET DEPENDING");
      Text_IO.Put_Line("ON WHETHER OR NOT YOU FEEL THE NEXT CARD WILL");
      Text_IO.Put_Line("HAVE A VALUE BETWEEN THE FIRST TWO.");
      Text_IO.Put_Line("");
      Text_IO.Put_Line("IF YOU DO NOT WANT TO BET, INPUT A 0 (ZERO).");
   end DisplayRules;
   function GenerateRandomNumber(Minimum: Integer; Maximum: Integer; Show: Boolean) return Integer is
      type rndRange is new Integer range Minimum..Maximum;
      package Rand_Int is new Ada.Numerics.Discrete_Random(rndRange);
      use Rand_Int;
      Gen: Generator;
      Num: rndRange;
   begin
      reset(Gen);
      Num := Random(Gen);
      if Show = TRUE then
         Text_IO.Put_Line(rndRange'Image(Num));
      end if;
      return Integer'Value(rndRange'Image(Num));
   end GenerateRandomNumber;
   function SelectCard return Integer is
      Card: Integer;
   begin
      <<sc_Loop>>
      Card := GenerateRandomNumber(2, 14, FALSE);
      if Card = Cards(1) or Card = Cards(2) or Card = Cards(3) then
         goto sc_Loop;
      end if;
      DisplayCard(Card);
      return Card;
   end SelectCard;
begin
   Text_IO.Put_Line("*** ACEY DUCEY : ADA ***");
   Running := TRUE;
   if AskToSeeTheRules = TRUE then
      DisplayRules;
   end if;
   <<running_Loop>>
   Wallet := 100;
   GameOver := FALSE;
   <<gameover_Loop>>
   Text_IO.Put_Line("YOU NOW HAVE" & Integer'Image(Wallet) & " DOLLARS.");
   Cards(1) := SelectCard;
   Cards(2) := SelectCard;
   Bet := AskForBet;
   if Bet > 0 then
      Cards(3) := SelectCard;
      if (Cards(3) > Cards(1) and Cards(3) < Cards(2)) or (Cards(3) > Cards(2) and Cards(3) < Cards(1)) then
         Text_IO.Put_Line("YOU WIN!!!");
         Wallet := Wallet + Bet;
      else
         Text_IO.Put_Line("SORRY, YOU LOSE.");
         Wallet := Wallet - Bet;
      end if;
      if Wallet < 1 then
         Text_IO.Put_Line("SORRY FRIEND, YOU ARE BROKE.");
         GameOver := TRUE;
      end if;
   else
      GameOver := TRUE;
   end if;
   if GameOver = FALSE then
      goto gameover_Loop;
   end if;
   Text_IO.Put_Line("*** GAME OVER ***");
   Running := AskToPlayAgain;
   if Running = TRUE then
      goto running_Loop;
   end if;
   Text_IO.Put_Line("OK, HOPE YOU HAD FUN.");
   Text_IO.Put_Line("THANKS FOR PLAYING!");
   null;
end Aceyducey;