PERL WEEKLY CHALLENGE – 052

This is my 22th week participating into the weekly challenge.


Stepping Numbers


Write a script to accept two numbers between 100 and 999. It should then print all Stepping Numbers between them.

A number is called a stepping number if the adjacent digits have a difference of 1. For example, 456 is a stepping number 


For this task I just brute forced and checked that each number is a stepping number. I did some basic validation and checked that the number is a stepping number by looping through each digit and comparing it to the digit before it.

Perl 5 solution

#!/usr/bin/perl
# Test: ./ch-1.pl 100 999
use strict;
use warnings;
use feature qw /say/;

my $start = $ARGV[0];
my $end   = $ARGV[1];

# Some input validation
unless ($start && $end && $end > $start &&
    $start >= 100 && $start < 1000 &&
    $end   >= 100 && $end < 1000) {

	say "Usage: 100 999";
	exit;
}

# Check each digit if it's stepping
for my $i ($start .. $end) {
	my $is_stepping = 1;
	my $prev_digit;

	my @digits = split ('', $i);
	for my $digit (@digits) {
		$is_stepping = 0 if
		( defined($prev_digit) &&
			( $prev_digit != $digit + 1 &&
			  $prev_digit != $digit - 1) );
		$prev_digit = $digit;
	}
	say $i if ($is_stepping);
}

Output

101
121
123
210
212
232
234
321
323
343
345
432
434
454
456
543
545
565
567
654
656
676
678
765
767
787
789
876
878
898
987
989

Raku solution

#!/usr/bin/perl
# Test: ./ch-6.p6

multi MAIN { MAIN(100, 999) };
multi MAIN(Int $start, Int $end) {
	die "End smaller than start" if $end < $start;
	.say for ($start .. $end).grep({is-stepping($_)});
}

sub is-stepping($num) {
	my $is_stepping = True;
	my $prev_digit;

	for ($num.comb) -> $i {
		$is_stepping = False
			if ($prev_digit.defined &&
			    $prev_digit != $i + 1 &&
			    $prev_digit != $i - 1 );

		$prev_digit = $i;
	}

	return $is_stepping;
}

Output

101
121
123
210
212
232
234
321
323
343
345
432
434
454
456
543
545
565
567
654
656
676
678
765
767
787
789
876
878
898
987
989

Task 2


Lucky Winner


Suppose there are following coins arranged on a table in a line in random order.

£1, 50p, 1p, 10p, 5p, 20p, £2, 2p

Suppose you are playing against the computer. Player can only pick one coin at a time from either ends. Find out the lucky winner, who has the larger amounts in total?


So I just modeled this as two players grabbing the highest coin. This results is player 2 winning and this can be tested with: ./ch-2.pl or
perl6 ./ch2.p6

This isn’t the optimal strategy because they key strategy to winning is trying to get the £2 coin and the person who goes first should always gets that coin (as the coin is positioned at the odd parity). This can be done if the first player always picks the left-most coin.

The lucky winner is always the first player, if played at the optimal strategy as player #1 will always get the £1 and £2 coins.

You can test that with: ./ch2-pl --optimal or
perl6 ./ch2-p6 --optimal

Perl 5 solution

#!/usr/bin/perl
# Test: ./ch-2.pl --optimal
use strict;
use warnings;
use Getopt::Long;
use feature qw /say/;

# Optimal flag
my $optimal = 0;
GetOptions ('optimal' => \$optimal);

# Some initialization variables
my @coins = (100, 50, 1, 10, 5, 20, 200, 2);
my $players = 2;
my $player_turn = 0;
my @totals = map { 0 } 1 .. $players;

# Play the game
while (scalar(@coins) > 0) {
	if ( ($optimal && $player_turn == 0) ||
	      $coins[0] > $coins[-1] ) {
		$totals[$player_turn] += shift @coins;
	} else {
		$totals[$player_turn] += pop @coins;
	}

	# Next turn
	$player_turn = ($player_turn + 1) % $players;
}

# Display the scores
for my $i (1..$players) {
	say "Player $i total: " . $totals[$i - 1] . 'p';
}

Output (optimal)

Player 1 total: 306p
Player 2 total: 82p

Output (player picks highest coin)

Player 1 total: 132p
Player 2 total: 256p

Raku solution

# Test: perl6 ch-2.p6
use v6.d;

sub MAIN(Bool :$optimal = False) {
	# Some initialization variables
	my @coins = (100, 50, 1, 10, 5, 20, 200, 2);
	my $players = 2;
	my $player_turn = 0;
	my @totals = map { 0 }, 1 .. $players;

	# Play the game
	while (@coins.elems > 0) {
		if ( ($optimal && $player_turn == 0) ||
		      @coins[0] > @coins[*-1] ) {
			@totals[$player_turn] += @coins.shift;
		} else {
			@totals[$player_turn] += @coins.pop;
		}

		# Next turn
		$player_turn = ($player_turn + 1) % $players;
	}

	for (1..$players) -> $i {
		say "Player $i total: " ~ @totals[$i - 1] ~ 'p';
	}
}

Output (optimal)

Player 1 total: 306p
Player 2 total: 82p

Output (player picks highest coin)

Player 1 total: 132p
Player 2 total: 256p

One thought on “PERL WEEKLY CHALLENGE – 052

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