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

Hi All! I have the following problem. Created a shuffle function for a deck of cards. When I call the function against an array once, everything looks good. When I execute the function a second time, the results from the first shuffle append to the second. Can somebody tell me why? Here is the script:
#!/usr/bin/perl @deck = (card1,card2,card3,card4); @shuffle1 = shuffle(@deck); @shuffle2 = shuffle(@shuffle1); print "@shuffle1\n"; print "@shuffle2\n"; sub shuffle () { $e = 0; $b = $#array; while ($e < $b) { push(@newdeck, "$array[$e]","$array[$b]"); $e++; $b--; } return @newdeck; }
  • Comment on When function is executed twice I get the results from the first set in the second
  • Download Code

Replies are listed 'Best First'.
Re: When function is executed twice I get the results from the first set in the second
by moritz (Cardinal) on Nov 15, 2009 at 17:02 UTC

    That's because @newdeck is a global variable, and you don't clear it.

    I recommend to use strict; use warnings; and declare my @newdeck inside the shuffle sub.

    There's also a shuffle function in the core module List::Util, which is tested and works.

    Perl 6 - links to (nearly) everything that is Perl 6.
      Thank you moritz! Declaring the return value as private fixed my issue!
Re: When function is executed twice I get the results from the first set in the second
by gmargo (Hermit) on Nov 15, 2009 at 17:05 UTC

    Because you don't clear the global variable @newdeck before calling shuffle() again.

    Use the strict and warnings, Luke!

Re: When function is executed twice I get the results from the first set in the second
by GrandFather (Saint) on Nov 15, 2009 at 22:57 UTC

    Your code doesn't run at all in fact. @array does not exist and your prototyped sub is declared too late for the prototype to be checked.

    As already suggested use strictures (use strict; use warnings; - see The strictures, according to Seuss).

    Don't use prototyped subs. In your sample code the prototype says "take no parameters" but @array is almost certainly intended to be a parameter (you surely aren't using global variables are you?).

    A first cut at cleaning up the code could look like:

    #!/usr/bin/perl use strict; use warnings; my @deck = qw(card1 card2 card3 card4); my @shuffle1 = shuffle (@deck); my @shuffle2 = shuffle (@shuffle1); print "@shuffle1\n"; print "@shuffle2\n"; sub shuffle { my $first = 0; my $last = $#_; my @newdeck; while ($first < $last) { push @newdeck, $_[$last--], $_[$first++]; } return @newdeck; }

    Using a somewhat more Perlish (and probably harder to understand) approach to implementing shuffle may get you to:

    sub shuffle { my @newdeck; push @newdeck, @_[-$_ - 1, $_] for 0 .. @_ / 2 - 1; return @newdeck; }

    Both versions print:

    card4 card1 card3 card2 card2 card4 card3 card1

    True laziness is hard work
      push @newdeck, pop, shift while @_;
      but every version fails in case of odd number of cards ...
      push @newdeck, grep defined, pop, shift while @_;
Re: When function is executed twice I get the results from the first set in the second
by 7stud (Deacon) on Nov 15, 2009 at 17:21 UTC

    Next assignment:

    Write a function that creates a deck of cards. The strings representing each card should look like "A H", which stands for "Ace of hearts". The function should return an array containing 52 strings: one for each card in a standard deck of cards.

Re: When function is executed twice I get the results from the first set in the second
by happy.barney (Friar) on Nov 15, 2009 at 22:16 UTC