Perl Weekly Challenge 103: Chinese Zodiac

You are given a year $year.

Write a script to determine the Chinese Zodiac for the given year $year. Please check out wikipage for more information about it.

  • The animal cycle: Rat, Ox, Tiger, Rabbit, Dragon, Snake, Horse, Goat, Monkey, Rooster, Dog, Pig.
  • The element cycle: Wood, Fire, Earth, Metal, Water.

Examples

    Input: 2017
    Output: Fire Rooster
    Input: 1938
    Output: Earth Tiger

Upping the ante

If we’re following the given link, we learn there is also a Yin/Yang cycle. So, we include this as well in the output.

Solution

The animal cycle is also known as the Earthly Branches. There are twelve branches, represented by animals. An animal is used for one year, followed by the next animal, in a cycle which repeats every twelve years.

The element cycle is also known as the Heavenly Stems. There are ten stems, represented by elements. An element is used for two years, followed by the next element, in a cycle which repeats every ten years.

The Yin/Yang cycle repeats every two years, with odd years being Yin, and even years Yang.

This leads to a cycle which repeats every sixty years, 60 being the least common multiple of 12, 10 and 2.

We will create the cycle by having three arrays; one array for each cycle. The Earthly Branches will be a 12 element array, the Heavenly Stems will be a 10 element array — each element will be repeated, and the Yin and Yang will just be two elements. We will place the array elements in such away that the corresponding entries for the year 0 will be in index 0. That way, we can just take the year, mod it by the size of the array, and use the result as an index.

Perl

First, we create the arrays:

my $yin_yang         = [qw [Yang Yin]];
my $heavenly_stems   = [map {($_) x 2} qw [Metal Water Wood Fire Earth]];
my $earthly_branches = [qw [Monkey  Rooster  Dog    Pig   Rat    Ox
                            Tiger   Rabbit   Dragon Snake Horse  Goat]];

We then read years from standard input, and fetch the parts from the arrays so we can print them:

while (my $year = <>) {
    $, = " ";
    say map {$$_ [$year % @$_]} $yin_yang, $heavenly_stems, $earthly_branches;
}

Find the complete program on GitHub.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s