Author Archive

Day 15: .pick your game

December 15, 2009

Another college semester has ended, or is soon ending, for many of us in the United States. I feel it’s appropriate that this gift will involve some fun. The gift is the ability to .pick things.

.pick allows for picking random elements from a list. Perl 5 allowed doing so through this syntax:

my @dice = (1, 2, 3, 4, 5, 6);
my $index = int (rand() * scalar @dice);
print $dice[$index] . "\n"; 
> 5

Perl 6 allows simplifying this, while at the same time picking more than one element.

my @dice = 1..6;
say @dice.pick(2).join(" ");
> 3 4

With just a set of dice, it is already possible to have a role playing session with your friends. Now, let’s see how much attack I can do with 10 d6s…

my @dice = 1..6;
say @dice.pick(10).join(" ");
> 5 3 1 4 2 6

For those wondering, the above result is not a typo. .pick‘s behavior is actually consistent with its name. When you pick something out, you generally keep it out. If you want to put the item back in, allowing the same item to be drawn again, use the :replace adverb in the second parameter.

my @dice = 1..6;
say @dice.pick(10, :replace).join(" ");
> 4 1 5 6 4 3 3 5 1 1

Note to game masters: don’t invite me to your D&D games unless you need someone with terrible dice luck. ;)

There is no specific order the list items have to be in for .pick to work its magic. Take the values of monopoly money, for instance:

my @dice = <1 5 10 20 50 100 500>;
say @dice.pick(10, :replace).join(" ");
> 20 50 100 500 500 10 20 5 50 20

When dice aren’t available, a deck of cards is usually on hand. This version is very basic, but is meant to get ideas going.

use v6;
class Card
{
  has $.rank;
  has $.suit;

  multi method Str()
  {
    return $.rank ~ $.suit;
  }
}

my @deck;
for <A 2 3 4 5 6 7 8 9 T J Q K> -> $rank
{
  for <♥ ♣ ♦ ♠> -> $suit
  {
    @deck.push(Card.new(:$rank, :$suit));
  }
}
# Shuffle the cards.
@deck .= pick(*);
say @deck.Str;
> Not outputting the results here.

What does the pick(*) do? Call that a sneak peak for another gift. For now, see if you can improve on the card code and make a deck class.

With that, I hope I have proven that Perl 6 is fun. It certainly gets a high mark from me. ✓

Day 8: .comb your constraints

December 8, 2009

We have hit the point where the previous gifts are useful for the current gifts. Today is a dual set: the comb method and the idea of constraints.

Similar to the static types previous defined, constraints allow fine control in writing subroutines and methods. In many other programming languages, you have to pass parameters into a subroutine and then validate the input that comes in. With constraints, you can do the validation right in the declaration.

Take this basic example. If the integer is even, I don’t want to deal with this subroutine. In Perl 5, it would be written something similar to this:

sub very_odd
{
    my $odd = shift;
    unless ($odd % 2)
    {
        return undef;
    }
    # Process the odd number here.
}

In Perl 6, this can be simplified thusly:

sub very_odd(Int $odd where {$odd % 2})
{
    # Process the odd number here
}

If you attempt to call very_odd with an even number, you will get an error. Do not fret though: you can use the multi sub functionality to give even numbers a chance to shine…maybe. ;)

multi sub very_odd(Int $odd where {$odd % 2})
{
    # Process the odd number here
}
multi sub very_odd(Int $odd) { return Bool::False; }

These constraints can be useful when paired with the .comb method. What exactly is .comb? For those that brush their own hair, you generally use a comb to get the strands you want and settle them somewhere on your head. For those that like using .split, it’s the opposite: instead of separating a Str by what you don’t want, you separate it by what you do. This simple piece of code should demonstrate that:

say "Perl 6 Advent".comb(/<alpha>/).join('|');
say "Perl 6 Advent".comb(/<alpha>+/).join('|');

Regex patterns will most likely be covered another day, but a quick preview won’t hurt. The first line will print P|e|r|l|A|d|v|e|n|t: it gets every alphabetic character and puts it into a temporary array. It is then joined together with the pipe character. The second line is similar, only it grabs as many alphabetic characters as it can, resulting in Perl|Advent.

The power of .comb is much more, however. Once you have combed out what you wanted, you can manipulate the strands. If you have a basic string of ASCII hex characters, you can use the hyperoperators to change each piece into the ASCII equivalent!

say "5065726C36".comb(/<xdigit>**2/)».fmt("0x%s")».chr
# Outputs "Perl6"

For those intimidated by that, you can find also use the .map method.

say "5065726C36".comb(/<xdigit>**2/).map: { chr '0x' ~ $_ } ;
# Outputs "Perl6"

Remember, this is Perl. There is more than one way to do it. ☺

With all of the gifts that have been presented today, I now have a challenge for all of you. With the assistance of Kyle Hasselbacher, I was able to make a decent version of the ancient Caesar Cipher using constraints, .comb, and the old style .map.

use v6;

sub rotate_one( Str $c where { $c.chars == 1 }, Int $n ) {
    return $c if $c !~~ /<alpha>/;
    my $out = $c.ord + $n;
    $out -= 26 if $out > ($c eq $c.uc ?? 'Z'.ord !! 'z'.ord);
    return $out.chr;
}

sub rotate(Str $s where {$s.chars}, Int $n = 3)
{
    return ($s.comb.map: { rotate_one( $_, $n % 26 ) }).join( '' );
}

die "Usage:\n$*PROGRAM_NAME string number_for_rotations" unless @*ARGS == 2;

my Str $mess = @*ARGS[0];
my Int $rotate = @*ARGS[1].Int;

say qq|"$mess" rotated $rotate characters gives "{rotate($mess,$rotate)}".|;

I would like to see how the rest of you can code this algorithm using Perl 6 and the gifts so far. After all, the language can only get better with more usage.

Day 3: static types and multi subs

December 3, 2009

The third box is ready for opening this Advent. Inside…well, looks like two gifts! Inside the box are static types and multi subs.

In Perl 5, $scalar variables could contain either references or values. Specifically, the values could be anything. They could be integers, strings, numbers, dates: you name it. This offers some flexibility, but at the cost of clarity.

Perl 6 is going to change that with its static types. If you want a particular variable, you place the type name in between my and $variable-type. As an example, to set up a variable to be an Int, one can do this:

my Int $days = 24;

Other static types are as follows:

  • my Str $phrase = "Hello World";
  • my Num $pi = 3.141e0;
  • my Rat $other_pi = 22/7;

If you still want the old behavior of the variables, you can either choose not to declare a static type or use Any instead.

This gift can easily go hand in hand with the second gift inside the box today: multi subs. What exactly are multi subs? In short, multi subs allow for the overloading of sub names. While multi subs can also do so much more, those are gifts for another day. For now, here are some subs that can be useful:


multi sub identify(Int $x) {
    return "$x is an integer.";
}

multi sub identify(Str $x) {
    return qq<"$x" is a string.>;
}

multi sub identify(Int $x, Str $y) {
    return "You have an integer $x, and a string \"$y\".";
}

multi sub identify(Str $x, Int $y) {
    return "You have a string \"$x\", and an integer $y.";
}

multi sub identify(Int $x, Int $y) {
    return "You have two integers $x and $y.";
}

multi sub identify(Str $x, Str $y) {
    return "You have two strings \"$x\" and \"$y\".";
}

say identify(42);
say identify("This rules!");
say identify(42, "This rules!");
say identify("This rules!", 42);
say identify("This rules!", "I agree!");
say identify(42, 24);

There is plenty to take advantage of with these two gifts. Try playing around with them, and keep coming back to our tree for more gifts that can use these features to their fullest extent. ☺


Follow

Get every new post delivered to your Inbox.

Join 37 other followers