Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

removing arbitrary elements from an array?

by Anonymous Monk
on Mar 15, 2000 at 19:58 UTC ( #5424=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I'm writing a program to simulate the shuffling of a deck of cards. So far it works fine, with one problem -- repeat cards keep turning up. Is there any way to cut an arbitrary value out of an array? The code works like this:

while ($game_hand < 12) {
$_ = int rand(@deck);
push @hand, $_;

I'd like a function that could cut whatever value $_ gets out of @deck completely, during the loop so I don't have to go through and check it for redundancy at a later point (and yes, I know about splice: for whatever reason, in this case it doesn't work and ends up giving me more repeat values... ugh).

  • Comment on removing arbitrary elements from an array?

Replies are listed 'Best First'.
Re: removing arbitrary elements from an array?
by chromatic (Archbishop) on Mar 15, 2000 at 21:22 UTC
    The perlfaq suggests a Fisher-Yates shuffle:
    sub fisher_yates_shuffle { my $array = shift; my $i; for ($i = @$array; --$i; ) { my $j = int rand ($i+1); next if $i == $j; @$array[$i,$j] = @$array[$j,$i]; } } fisher_yates_shuffle( \@array );
    This, walks backwards through the array (thus avoiding the repetition problem), swapping cards randomly. I would call this on your deck and then, depending on your card game, treat @deck as a queue.
Re: removing arbitrary elements from an array?
by gronkulator (Sexton) on Mar 15, 2000 at 21:31 UTC
    ugly hack - pruning an array by value by checking each element sequentially

    @deck=(0 ... 51); $card=32; prune_deck($card, \@deck); print join("\n",@deck); sub prune_deck ( my $dupe = shift; # we assign $dupe to the id of the card we just +pulled my $deckref = shift; my @remainder; # a scratch array to hold what's left for my $card (@{$deckref}) { $card eq $dupe ? next : push(@remainder, $card); # save curren +t card if not the one we pulled } @{$deckref}=(undef); # empty the deck push @{$deckref}, @remainder; # push back the remainder 1; }
Re: removing arbitrary elements from an array?
by btrott (Parson) on Mar 17, 2000 at 03:25 UTC
    As chromatic wrote, you should use the Fisher-Yates shuffle.

    However, you said splice wouldn't work for you--I'm curious as to why. What was your code, using splice? I tried this:

    while ($game_hand < 12) { push @hand, splice @deck, rand @deck, 1; $game_hand++; }
    and it worked for me.

    This is, in fact, the very same algorithm that perlfaq4 warns against using.

    So use the Fisher-Yates shuffle to shuffle your array.

RE: removing arbitrary elements from an array?
by Anonymous Monk on Mar 15, 2000 at 21:18 UTC
    This doesn't exacty answer you question, but arrays are designed so that it is easy to pop and push elements onto and off of the top of the deck. Why not shuffle the deck first, and deal off the top?
RE: removing arbitrary elements from an array?
by Anonymous Monk on Mar 15, 2000 at 21:12 UTC
    for a card game I'd build off of the Games::Cards module on CPAN as it already has tons of card-type logic built into it (includding shuffling). If all you want is shuffling of a list take a look at the Algorithm::Numerical::Shuffle module.

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://5424]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others romping around the Monastery: (7)
As of 2023-03-20 13:14 GMT
Find Nodes?
    Voting Booth?
    Which type of climate do you prefer to live in?

    Results (59 votes). Check out past polls.