Perl Weekly Challenge 268: Number Game

These are some answers to the Week 268, Task 2, of the Perl Weekly Challenge organized by Mohammad S. Anwar.

Spoiler Alert: This weekly challenge deadline is due in a few days from now (on May 12, 2024 at 23:59). This blog post provides some solutions to this challenge. Please don’t read on if you intend to complete the challenge on your own.

Task 2: Number Game

You are given an array of integers, @ints, with even number of elements.

Write a script to create a new array made up of elements of the given array. Pick the two smallest integers and add it to new array in decreasing order i.e. high to low. Keep doing until the given array is empty.

Example 1

Input: @ints = (2, 5, 3, 4)
Output: (3, 2, 5, 4)

Round 1: we picked (2, 3) and push it to the new array (3, 2)
Round 2: we picked the remaining (4, 5) and push it to the new array (5, 4)

Example 2

Input: @ints = (9, 4, 1, 3, 6, 4, 6, 1)
Output: (1, 1, 4, 3, 6, 4, 9, 6)

Example 3

Input: @ints = (1, 2, 2, 3) Output: (2, 1, 3, 2)

Number Game in Raku

In Raku, a for loop using a pointy block syntax can use two (or more) parameters, as shown with three block parameters in the Raku REPL example below:

> for 1..9 -> $a, $b, $c { say "$a, $b and $c" }
1, 2 and 3
4, 5 and 6
7, 8 and 9

We use this feature to pick up and reverse two items at a time of the input array:

sub number-game (@in) {
    my @result;
    for @in.sort -> $i, $j {
        push @result, $j, $i;
    }
    return @result;
}

my @tests = <2 5 3 4>, <1 1 4 3 6 4 9 6>, <1 2 2 3>;
for @tests -> @test {
    printf "%-16s => ", "@test[]";
    say number-game @test;
}

This program displays the following output:

$ raku ./number-game.raku
2 5 3 4          => [3 2 5 4]
1 1 4 3 6 4 9 6  => [1 1 4 3 6 4 9 6]
1 2 2 3          => [2 1 3 2]

Number Game in Perl

Perl doesn't have the Raku syntax with several parameters, but we can easily simulate it with two shift statements, as shown in the code below:

use strict;
use warnings;
use feature 'say';

sub number_game {
    my @in = sort { $a <=> $b } @_;
    my @result;
    while (@in) {
        my $i = shift @in;
        my $j = shift @in;
        push @result, $j, $i;
    }

    return join " ", @result;
}

my @tests = ([<2 5 3 4>], [<1 1 4 3 6 4 9 6>], [<1 2 2 3>]);
for my $test (@tests) {
    printf "%-16s => ", "@$test";
    say number_game @$test;
}

Note that this code could be made significantly shorter using a splice statement:

sub number_game {
    my @in = sort { $a <=> $b } @_;
    my @result;
    push @result, reverse splice @in, 0, 2 while @in;
    return join " ", @result;
}

This program displays the following output (both versions):

$ perl ./number-game.pl
2 5 3 4          => 3 2 5 4
1 1 4 3 6 4 9 6  => 1 1 4 3 6 4 9 6
1 2 2 3          => 2 1 3 2

Wrapping up

The next week Perl Weekly Challenge will start soon. If you want to participate in this challenge, please check https://perlweeklychallenge.org/ and make sure you answer the challenge before 23:59 BST (British summer time) on May 19, 2024. And, please, also spread the word about the Perl Weekly Challenge if you can.

Leave a comment

About laurent_r

user-pic I am the author of the "Think Perl 6" book (O'Reilly, 2017) and I blog about the Perl 5 and Raku programming languages.