Re: Randomly outputting an array



ryanarossi@xxxxxxxxx wrote:
What would be the simplest way to output an array in random order, but
every element in the array MUST be outputted and the elements cannot
repeat?

Here is another solution to add to your collection of solutions.
The following code is the package specification and body for a simple
playing card representation using Ada.

The public view of the package is defined in the specification, while
the
implementation is defined in the body. I will show the specification
first, followed by the body:

package Playing_Cards is
type Card is private;
procedure Print(The_Card : Card);
type Deck is private;
procedure Print(the_Deck : Deck);
procedure Deal(From : in out Deck; The_Card : out Card);
procedure Shuffle(The_Deck : in out Deck);
function New_Deck return Deck;
Deck_Empty : exception;
private
type Pips is (Two, Three, Four, Five, Six, Seven,
Eight, Nine, Ten, Jack, Queen, King, Ace);
type Suits is (Diamonds, Spades, Hearts, Clubs);
type Card is record
Pip : Pips;
Suit : Suits;
end record;
type Index is range 1..53;
subtype Deck_Index is Index range 1..52;
type Deck_Reference is array(Deck_Index) of Deck_Index;
type Deck is record
Next_Card : Index;
Deck_Offsets : Deck_Reference;
end record;
end Playing_Cards;

with Ada.Numerics.Discrete_Random;
With Ada.Text_IO;

package body Playing_Cards is
type Internal_Deck is array(Deck_Index) of Card;
Base_Deck : Internal_Deck;
Base_Index : Index;
----------
-- Deal --
----------

procedure Deal (From : in out Deck; The_Card : out Card) is
begin
if From.Next_Card not in Deck_Index then
raise Deck_Empty;
end if;
The_Card := Base_Deck(From.Deck_Offsets(From.Next_Card));
From.Next_Card := From.Next_Card + 1;
end Deal;

--------------
-- New_Deck --
--------------

function New_Deck return Deck is
Temp : Deck;
begin
for I in Base_Deck'range loop
Temp.Deck_Offsets(I) := I;
end loop;
Temp.Next_Card := 1;
return Temp;
end New_Deck;

-----------
-- Print --
-----------

procedure Print(The_Card : Card) is
package Pip_Io is new Ada.Text_Io.Enumeration_Io(Pips);
use Pip_Io;
package Suit_Io is new Ada.Text_Io.Enumeration_Io(Suits);
use Suit_Io;
begin
Put(Item => The_Card.Pip, Width => 1);
Ada.Text_Io.Put(" of ");
Put(Item => The_Card.Suit, Width => 1);
Ada.Text_Io.New_Line;
end Print;

-----------
-- Print --
-----------

procedure Print(The_Deck : Deck) is
begin
for I in The_Deck.Next_Card..Deck_Index'Last loop
Print(Base_Deck(The_Deck.Deck_Offsets(I)));
end loop;
end Print;

-------------
-- Shuffle --
-------------

procedure Shuffle (The_Deck : in out Deck) is
procedure Swap(Left, Right : in out Deck_Index) is
Temp : Deck_Index := Left;
begin
Left := Right;
Right := Temp;
end Swap;
Swap_Index : Deck_Index;
begin
for I in Deck_Index'First..Deck_Index'Pred(Deck_Index'Last) loop
declare
subtype Remaining_Indices is Deck_Index range
I..Deck_Index'Last;
package Rand_Card is new
Ada.Numerics.Discrete_Random(Remaining_Indices);
use Rand_Card;
Seed : Generator;
begin
Reset(Seed);
Swap_Index := Random(Seed);
Swap(The_Deck.deck_Offsets(I),
The_Deck.Deck_Offsets(Swap_Index));
end;
end loop;
The_Deck.Next_Card := 1;
end Shuffle;

begin
Base_Index := 1;
for Suit in Suits'range loop
for Pip in Pips'range loop
Base_Deck(Base_Index) := (Pip, Suit);
Base_Index := Base_Index + 1;
end loop;
end loop;
end Playing_Cards;

In this example the type Deck is a private type containing an array
of references to a singleton Internal_Deck. That singleton deck is
defined in
the package body, where it is not visible to any other package or
compilation unit. The Shuffle procedure randomly organizes the
references in a Deck to point to elements of the singleton.

The Print procedure merely displays the cards in the Internal_Deck
in the order they are referenced by the Deck instance passed to
the procedure as a parameter.

The Shuffle procedure starts at the first element in the array and
randomly swaps it with some element having the same or a higher
index value. The next iteration increments the low value of the swap
"window" and swaps the second element of the array with a
random element from the set including itself and all elements with a
higher index value. This continues until the swap "window" contains
only one element.

Jim Rogers

.



Relevant Pages

  • Re: Random Number Question
    ... If it is then to exit the loop and if not repeat the code? ... This is generally called a while loop. ... where you have only 2 cards left in the deck, ... Select a card by selecting a random integer between 0 and N-1 inclusive. ...
    (comp.lang.php)
  • Clan Assamite Newsletter, July 2008
    ... vampires for the deck. ... Put this card on this magaji and untap him or her. ... Burn this card if this magaji attempts to block a vampire ... Tap this location to reduce the cost of a card you play by 1 pool ...
    (rec.games.trading-cards.jyhad)
  • Re: Clan Assamite Newsletter, July 2008
    ... vampires for the deck. ... Put this card on this magaji and untap him or her. ... Burn this card if this magaji attempts to block a vampire ... Tap this location to reduce the cost of a card you play by 1 pool ...
    (rec.games.trading-cards.jyhad)
  • Re: Malkavian Antitribu Newsletter, September 2007
    ... "If this action is blocked again, burn this card". ... I hope you aren't suggesting putting this in some deck specifically to ... +3 pool total just for an action that costs 1 blood. ... rocket, and it will add some huge bleeds to the pain (probably, with ...
    (rec.games.trading-cards.jyhad)
  • Official VEKN Ravnos Clan Newsletter - November 2005
    ... Malk bleed deck rather than the Ravnos Red Herring Tap and Bleed deck I ... help defend against weenie decks in this month's newsletter. ... There seems to be a card made just for this situation, Aranthebes, The ... Requires a ready vampire with a capacity below 6. ...
    (rec.games.trading-cards.jyhad)