PERL WEEKLY CHALLENGE – 046

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


Easy Challenge

Cryptic Message

The communication system of an office is broken and message received are not completely reliable. To send message Hello, it ended up sending these following:

H x l 4 !
c e - l o
z e 6 l g
H W l v R
q 9 m # o

Similary another day we received a message repeatedly like below:

P + 2 l ! a t o
1 e 8 0 R $ 4 u
5 - r ] + a > /
P x w l b 3 k \
2 e 3 5 R 8 y u
< ! r ^ ( ) k 0

Write a script to decrypt the above repeated message (one message repeated 6 times).

HINT: Look for characters repeated in a particular position in all six messages received.


In perl 5 and Raku I just tokenized the message into lines and characters. Then stored the number of times the character exists for the column in a arrays of hashrefs with the arrays index related to the column.

Then it was a matter of sorting the hashref with the character that appears the most and displaying that character.

Perl 5 solution

#!/usr/bin/perl
# Test: ./ch1.pl
use strict;
use warnings;
use feature qw /say/;

# The message
my $message =
'P + 2 l ! a t o
1 e 8 0 R $ 4 u
5 - r ] + a > /
P x w l b 3 k \
2 e 3 5 R 8 y u
< ! r ^ ( ) k 0';

# Initialize the columns hash
my @column_hash;
my ($first_line) = split ("\n", $message, 2);
my $length = length(join '', split (" ", $first_line));
$column_hash[$_] = {} for (0..$length-1);

# Parse the cryptic message
for my $line (split ("\n", $message)) {
	my $i = 0;
	for my $char (split (" ", $line)) {
		$column_hash[$i++]->{$char}++;
	}
}

# Sort
for my $column (@column_hash) {
	my @sort =
		sort { $column->{$b} <=> $column->{$a} }
		keys %$column;

	print $sort[0];
}

say '';

Output

PerlRaku

Raku solution

# Test: perl6 ch1.p6
use v6.d;

# The message
our $message =
'P + 2 l ! a t o
1 e 8 0 R $ 4 u
5 - r ] + a > /
P x w l b 3 k \
2 e 3 5 R 8 y u
< ! r ^ ( ) k 0';

sub MAIN() {

	# Initialize the columns hash
	my @column_hash;
	my ($first_line) = $message.split("\n", 2);
	my $length = $first_line.split(" ").join.chars;
	@column_hash[0 .. $length - 1] = {};

	# Parse the cryptic message
	for ($message.split("\n")) -> $line {
		my $i = 0;
		for ($line.split(" ")) -> $char {
			@column_hash[$i++].{$char}++;
		}
	}

	# Sort
	my $output = '';
	for (@column_hash) -> %column {
		$output = $output ~
			%column.keys.sort(
				{ %column.{$^b} <=> %column.{$^a} }
			)[0];
	}

	say $output;
}

Output

PerlRaku

Hard Challenge

Is the room open?

There are 500 rooms in a hotel with 500 employees having keys to all the rooms. The first employee opened main entrance door of all the rooms. The second employee then closed the doors of room numbers 2,4,6,8,10 and so on to 500. The third employee then closed the door if it was opened or opened the door if it was closed of rooms 3,6,9,12,15 and so on to 500. Similarly the fourth employee did the same as the third but only room numbers 4,8,12,16 and so on to 500. This goes on until all employees has had a turn.

Write a script to find out all the rooms still open at the end.


In perl 5 and Raku I just looped through each employee and looped through each door. I’m sure there are smarter ways of doing this but I didn’t want to devote too much time to this.

I stored the door’s state in an array called doors and for my sanity I kept the door number and index number of the array consistent.

Perl 5 solution

#!/usr/bin/perl
# test: perl ch2.pl | diff - ch2.pl
use strict;
use warnings;
use feature qw /say/;

my @doors;
$doors[$_] = 0 for (0 .. 500);

for my $employee (1 .. 500) {
	for my $door ($employee .. 500 ) {
		next unless $door % $employee == 0;
		$doors[$door] = ($doors[$door]) ? 0 : 1;
	}
}

for my $i (1 .. 500) {
	say "Door: " . $i . " is open."
		if ($doors[$i]);
}

Output

Door: 1 is open.
Door: 4 is open.
Door: 9 is open.
Door: 16 is open.
Door: 25 is open.
Door: 36 is open.
Door: 49 is open.
Door: 64 is open.
Door: 81 is open.
Door: 100 is open.
Door: 121 is open.
Door: 144 is open.
Door: 169 is open.
Door: 196 is open.
Door: 225 is open.
Door: 256 is open.
Door: 289 is open.
Door: 324 is open.
Door: 361 is open.
Door: 400 is open.
Door: 441 is open.
Door: 484 is open.

Raku solution

# Test: perl6 ch2.p6 
use v6.d;

sub MAIN () {
	my @doors;
	@doors[0 .. 500] = 0;

	for (1 .. 500) -> $employee {
		for ($employee .. 500 ) -> $door {
			next unless $door % $employee == 0;
			@doors[$door] = (@doors[$door]) ?? 0 !! 1;
		}
	}

	for (1 .. 500) -> $i {
		say "Door: " ~ $i ~ " is open."
			if (@doors[$i]);
	}
}

Output

Door: 1 is open.
Door: 4 is open.
Door: 9 is open.
Door: 16 is open.
Door: 25 is open.
Door: 36 is open.
Door: 49 is open.
Door: 64 is open.
Door: 81 is open.
Door: 100 is open.
Door: 121 is open.
Door: 144 is open.
Door: 169 is open.
Door: 196 is open.
Door: 225 is open.
Door: 256 is open.
Door: 289 is open.
Door: 324 is open.
Door: 361 is open.
Door: 400 is open.
Door: 441 is open.
Door: 484 is open.

3 thoughts on “PERL WEEKLY CHALLENGE – 046

  1. Hello.

    Thank you for your time writing this blog.

    Your Raku solutions look a lot like Perl. There is nothing wrong with that, Raku welcomes all styles of expressions. But you ain’t gonna impress anybody (read: attract new users) with prettier for loops.

    If I may, this is my take at the challenge #1:

    [~] zip(
    $encrypted.lines.map: *.words
    ).map(
    *.Bag.maxpairs[0].key
    );

    where $encrypted is a multiline string that contains the message. This demonstrates how expressive Raku is.

    Keep in mind there is a Bool type in Raku. There is no need to use Ints to represent on/off states.

    Also, you might have noticed something standing out abouth the open door numbers. If you take that into account and think about the problem from the perspective of the door, you might find a more straightforward solution for #2.

    Like

    1. Hi Holli,

      Thanks for the feedback, I’m using these challenges to learn Raku, so I’ll need to lose the perl 5 accent. You’ll need to bear with my learning curve, as currently it’s just about the syntax and trying to learn what Raku is capable of.

      Like

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