This is my response to the Perl Weekly Challenge #084.
$N
.
2,147,483,647
is the maximum positive value for a 32-bit signed
binary integer in computing.
Input: 1234
Output: 4321
Example 2
Input: -1234
Output: -4321
Example 3
Input: 1231230512
Output: 0
We need this limit as well, but the challenge does not specify it. So I looked it up, and IBM had the answer: -2147483648.
#! /usr/bin/env raku
unit sub MAIN (Int $N); # [1]
my $sign = $N < 0 # [2]
?? "-" # [2a]
!! ""; # [2b]
my $new = $sign ~ $N.abs.flip; # [3]
-2147483648 <= $new <= 2147483647 # [4]
?? say $new # [4a]
!! say "0"; # [4b]
[1] Ensure that the input is an integer.
[2] Extract the sign, as a string (i.e. "" for a positive value).
[3]
Start with the sign, if any, then the number without the
possible sign (abs
), as a string, reversed (flip
).
[4] If the number is within the limits, print it [4a], or fasil to zero [4b].
See
docs.raku.org/routine/abs for more
information about the abs
method.
See
docs.raku.org/routine/flip for more
information about the flip
method.
Running it:
$ ./reverse-integer 1234
4321
$ ./reverse-integer -1234
-4321
$ ./reverse-integer 1231230512
0
This is a straight forward translation, so I'll present it without comments.
File: reverse-integer-perl
#! /usr/bin/env perl
use feature 'say';
my $N = $ARGV[0] // die "Please specify an integer";
die "Integer only" unless $N =~ /^\-?\d+$/;
my $sign = $N < 0
? "-"
: "";
my $new = $sign . reverse(abs($N));
($new >= -2147483648 && $new <= 2147483647)
? say $new
: say "0";
Running it gives the same result as the Raku version:
$ ./reverse-integer-perl 1234
4321
$ ./reverse-integer-perl -1234
-4321
$ ./reverse-integer-perl 1231230512
0
m x n
with only 1
and
0
.
1
.
Input: [ 0 1 0 1 ]
[ 0 0 1 0 ]
[ 1 1 0 1 ]
[ 1 0 0 1 ]
Output: 1
Explanation:
There is one square (3x3) in the given matrix with four corners as 1 starts at r=1;c=2.
Input: [ 1 1 0 1 ]
[ 1 1 0 0 ]
[ 0 1 1 1 ]
[ 1 0 1 1 ]
Output: 4
Explanation:
There is one square (4x4) in the given matrix with four corners as 1 starts at r=1;c=1.
There is one square (3x3) in the given matrix with four corners as 1 starts at r=1;c=2.
There are two squares (2x2) in the given matrix with four corners as 1. First starts at r=1;c=1
and second starts at r=3;c=3.
Input: [ 0 1 0 1 ]
[ 1 0 1 0 ]
[ 0 1 0 0 ]
[ 1 0 0 1 ]
Output: 0
The first problem is how to specify the matrices to the program. I have chosen to place them in their own (text) files, like this:
File: example1.txt
0 1 0 1
0 0 1 0
1 1 0 1
1 0 0 1
Reading a matrix from a file is a repetition of what I did in the second part of Primal Words with Raku, my response to the Perl Weekly Challenge #076.
File: find-square
#! /usr/bin/env raku
unit sub MAIN ($matrix where $matrix.IO.f && $matrix.IO.r = 'example1.txt',
:v(:$verbose)); # [1]
my @matrix = $matrix.IO.lines.map( *.lc.words.list ); # [2]
die "Uneven matrix row length" unless [==] @(@matrix)>>.elems; # [3]
die "0 and 1 only" unless all( @matrix>>.List.flat ) eq any( 0, 1 ); # [4]
my $rows = @matrix.elems; # [5]
my $cols = @matrix[0].elems; # [6]
my $matches = 0; # [7]
for 0 .. $rows -2 -> $row # [8]
{
for 0 .. $cols -2 -> $col # [9]
{
for 1 .. $rows-1 -> $offset # [10]
{
last unless defined @matrix[$row+$offset][$col+$offset]; # [11]
check-box($row, $col, $offset); # [12]
}
}
}
say $matches; # [13]
sub check-box ($row, $col, $offset) # [12a]
{
say ": [$row, $col] -> [{ $row+$offset }, { $col+ $offset}]" if $verbose;
if @matrix[$row][$col] == @matrix[$row+$offset][$col] ==
@matrix[$row][$col+$offset] == @matrix[$row+$offset][$col+$offset] == 1
{ # [14]
$matches++; # [14a]
say ": - is a match" if $verbose;
}
}
[1] Ensure that the argument is a file name.
[2] Read the matrix into a two dimentional array.
[3] Ensure that all the rows have the same length.
[4] Ensure that the matrix contains nothing but zeroes and ones. We have to slap
on >>.List
here, as flat
will not flatten the
structure for us otherwise. See
docs.raku.org/routine/flat#class_Any
for details.
[5] The number of rows.
[6] The number of columns. We know that the roes have the same lengt (from [3]), so we can pick any row here.
[7] The number of matches, squares with one ibn the four corners.
[8] and [9] The idea is to iterate over all the possible starting positions for a square. We do this in [8] (one row) and [9] (starting positions on that row), starting with the first position (from the left) on the first (top) row. We stop one off the end of the lines, as we need at least two elements for a square.
[10] Then we iterate over the size of the square in [10], or rather the index offsets. Thus the offset 1 gives a 2x2 square. The upper limit is probably way off, but the check on the next line ([11]) takes care of that.
[11] Skip the innermost loop if the current square is outside of the matrix.
[12] Check if the current square has four corners with 1
.
[13] Print the number of matching squares.
[14] The actual four courner check.
Running it:
$ ./find-square example1.txt
1
$ ./find-square example2.txt
4
$ ./find-square example3.txt
0
The answers are correct, but we can use verbose mode to see why:
$ ./find-square -v example1.txt
: Upper Left: [0, 0] -> Lower Right: [1, 1]
: Upper Left: [0, 0] -> Lower Right: [2, 2]
: Upper Left: [0, 0] -> Lower Right: [3, 3]
: Upper Left: [0, 1] -> Lower Right: [1, 2]
: Upper Left: [0, 1] -> Lower Right: [2, 3]
: - is a match
: Upper Left: [0, 2] -> Lower Right: [1, 3]
: Upper Left: [1, 0] -> Lower Right: [2, 1]
: Upper Left: [1, 0] -> Lower Right: [3, 2]
: Upper Left: [1, 1] -> Lower Right: [2, 2]
: Upper Left: [1, 1] -> Lower Right: [3, 3]
: Upper Left: [1, 2] -> Lower Right: [2, 3]
: Upper Left: [2, 0] -> Lower Right: [3, 1]
: Upper Left: [2, 1] -> Lower Right: [3, 2]
: Upper Left: [2, 2] -> Lower Right: [3, 3]
1
$ ./find-square -v example2.txt
: Upper Left: [0, 0] -> Lower Right: [1, 1]
: - is a match
: Upper Left: [0, 0] -> Lower Right: [2, 2]
: Upper Left: [0, 0] -> Lower Right: [3, 3]
: - is a match
: Upper Left: [0, 1] -> Lower Right: [1, 2]
: Upper Left: [0, 1] -> Lower Right: [2, 3]
: - is a match
: Upper Left: [0, 2] -> Lower Right: [1, 3]
: Upper Left: [1, 0] -> Lower Right: [2, 1]
: Upper Left: [1, 0] -> Lower Right: [3, 2]
: Upper Left: [1, 1] -> Lower Right: [2, 2]
: Upper Left: [1, 1] -> Lower Right: [3, 3]
: Upper Left: [1, 2] -> Lower Right: [2, 3]
: Upper Left: [2, 0] -> Lower Right: [3, 1]
: Upper Left: [2, 1] -> Lower Right: [3, 2]
: Upper Left: [2, 2] -> Lower Right: [3, 3]
: - is a match
4
$ ./find-square -v example3.txt
: Upper Left: [0, 0] -> Lower Right: [1, 1]
: Upper Left: [0, 0] -> Lower Right: [2, 2]
: Upper Left: [0, 0] -> Lower Right: [3, 3]
: Upper Left: [0, 1] -> Lower Right: [1, 2]
: Upper Left: [0, 1] -> Lower Right: [2, 3]
: Upper Left: [0, 2] -> Lower Right: [1, 3]
: Upper Left: [1, 0] -> Lower Right: [2, 1]
: Upper Left: [1, 0] -> Lower Right: [3, 2]
: Upper Left: [1, 1] -> Lower Right: [2, 2]
: Upper Left: [1, 1] -> Lower Right: [3, 3]
: Upper Left: [1, 2] -> Lower Right: [2, 3]
: Upper Left: [2, 0] -> Lower Right: [3, 1]
: Upper Left: [2, 1] -> Lower Right: [3, 2]
: Upper Left: [2, 2] -> Lower Right: [3, 3]
0
Note that the coordinates are zero based.
The output we got from verbose mode is certainly better than nothing, but it is not very user friendly. We can print the whole matrix, with the currently inspected square highlighted.
Adding colour to the output is a repetition of what I did in e.g. the second part of The Email Queen with Raku, my response to the Perl Weekly Challenge #062.
I'll start with the output, and show the program afterwards (without comments). Successful squares are shown with green, unsuccesful ones in red:
$ ./find-square-verbose -vv example1.txt
: Upper Left: [0, 0] -> Lower Right: [1, 1]
: [ 0 1 1 1 ]
: [ 0 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 0] -> Lower Right: [2, 2]
: [ 0 1 0 1 ]
: [ 0 0 1 0 ]
: [ 1 1 0 0 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 0] -> Lower Right: [3, 3]
: [ 0 1 0 1 ]
: [ 0 0 1 0 ]
: [ 1 1 0 1 ]
: [ 1 0 0 1 ]
: Upper Left: [0, 1] -> Lower Right: [1, 2]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 1] -> Lower Right: [2, 3]
: - is a match
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 1 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 2] -> Lower Right: [1, 3]
: [ 0 0 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 0] -> Lower Right: [2, 1]
: [ 0 0 1 1 ]
: [ 0 0 1 0 ]
: [ 1 1 0 0 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 0] -> Lower Right: [3, 2]
: [ 0 0 1 1 ]
: [ 0 0 1 0 ]
: [ 1 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [1, 1] -> Lower Right: [2, 2]
: [ 0 0 1 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 1] -> Lower Right: [3, 3]
: [ 0 0 1 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 1 ]
: [ 1 0 0 1 ]
: Upper Left: [1, 2] -> Lower Right: [2, 3]
: [ 0 0 1 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 1 ]
: [ 1 0 1 1 ]
: Upper Left: [2, 0] -> Lower Right: [3, 1]
: [ 0 0 1 1 ]
: [ 1 0 1 0 ]
: [ 1 1 0 0 ]
: [ 1 0 1 1 ]
: Upper Left: [2, 1] -> Lower Right: [3, 2]
: [ 0 0 1 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [2, 2] -> Lower Right: [3, 3]
: [ 0 0 1 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 1 ]
: [ 1 0 0 1 ]
1
$ ./find-square-verbose -vv example2.txt
: Upper Left: [0, 0] -> Lower Right: [1, 1]
: - is a match
: [ 1 1 0 1 ]
: [ 1 1 1 0 ]
: [ 0 0 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 0] -> Lower Right: [2, 2]
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 0] -> Lower Right: [3, 3]
: - is a match
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 1] -> Lower Right: [1, 2]
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 0 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 1] -> Lower Right: [2, 3]
: - is a match
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [0, 2] -> Lower Right: [1, 3]
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 0 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 0] -> Lower Right: [2, 1]
: [ 1 1 0 1 ]
: [ 1 1 1 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 0] -> Lower Right: [3, 2]
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 1] -> Lower Right: [2, 2]
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 1] -> Lower Right: [3, 3]
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [1, 2] -> Lower Right: [2, 3]
: [ 1 1 0 1 ]
: [ 1 1 0 0 ]
: [ 0 0 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [2, 0] -> Lower Right: [3, 1]
: [ 1 1 0 1 ]
: [ 1 1 1 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [2, 1] -> Lower Right: [3, 2]
: [ 1 1 0 1 ]
: [ 1 1 1 0 ]
: [ 0 1 1 1 ]
: [ 1 0 1 1 ]
: Upper Left: [2, 2] -> Lower Right: [3, 3]
: - is a match
: [ 1 1 0 1 ]
: [ 1 1 1 0 ]
: [ 0 0 1 1 ]
: [ 1 0 1 1 ]
4
$ ./find-square-verbose -vv example3.txt
: Upper Left: [0, 0] -> Lower Right: [1, 1]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [0, 0] -> Lower Right: [2, 2]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [0, 0] -> Lower Right: [3, 3]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [0, 1] -> Lower Right: [1, 2]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [0, 1] -> Lower Right: [2, 3]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [0, 2] -> Lower Right: [1, 3]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [1, 0] -> Lower Right: [2, 1]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [1, 0] -> Lower Right: [3, 2]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [1, 1] -> Lower Right: [2, 2]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [1, 1] -> Lower Right: [3, 3]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [1, 2] -> Lower Right: [2, 3]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [2, 0] -> Lower Right: [3, 1]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [2, 1] -> Lower Right: [3, 2]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
: Upper Left: [2, 2] -> Lower Right: [3, 3]
: [ 0 1 0 1 ]
: [ 1 0 1 0 ]
: [ 0 1 0 0 ]
: [ 1 0 0 1 ]
0
Note that I used the program's html mode (with «-h») to get the output on a format suitable for an html page.
File: find-square-verbose
#! /usr/bin/env raku
unit sub MAIN ($matrix where $matrix.IO.f && $matrix.IO.r = 'example1.txt',
:h(:$html),
:vv(:$very-verbose),
:v(:$verbose) = $very-verbose);
my $blue = "\e[44m";
my $green = "\e[42m";
my $red = "\e[101m";
my $stop = "\e[0m";
if $html
{
$blue = '<span class="text-light bg-primary">';
$green = '<span class="text-light bg-success">';
$red = '<span class="text-light bg-danger">';
$stop = '</span>';
}
my @matrix = $matrix.IO.lines.map( *.lc.words.list );
die "Uneven grid row length" unless [==] @(@matrix)>>.elems;
die "0 and 1 only" unless all( @matrix>>.List.flat ) eq any( 0, 1 );
my $rows = @matrix.elems;
my $cols = @matrix[0].elems;
my $matches = 0;
for 0 .. $rows -2 -> $row
{
for 0 .. $cols -2 -> $col
{
for 1 .. $rows-1 -> $offset
{
last unless defined @matrix[$row+$offset][$col+$offset];
check-box($row, $col, $offset);
}
}
}
say $matches;
sub check-box ($row, $col, $offset)
{
say ": Upper Left: [$row, $col] -> Lower Right: [{ $row+$offset }, \
{ $col+ $offset}]" if $verbose;
if @matrix[$row][$col] == @matrix[$row+$offset][$col] ==
@matrix[$row][$col+$offset] == @matrix[$row+$offset][$col+$offset] == 1
{
$matches++;
say ": - is a match" if $verbose;
highlight-matrix($row, $col, $offset, True) if $very-verbose;
}
else
{
highlight-matrix($row, $col, $offset, False) if $very-verbose;
}
}
sub highlight-matrix ($row, $col, $offset, $hot)
{
my $inside = False;
my $row-end = $row + $offset;
my $col-end = $col + $offset;
my $start = $hot ?? $green !! $red;
for ^$rows -> $r
{
print ": [";
for ^$cols -> $c
{
$inside = $row <= $r <= $row-end && $col <= $c <= $col-end;
print " ";
$inside
?? print $start ~ @matrix[$r][$c] ~ $stop
!! print @matrix[$c][$r];
}
$inside = False;
say " ]";
}
say "";
}
And that's it.