Perl Weekly Challenge 95.

My solutions (task 1, task 1a, and task 2) to the The Weekly Challenge - 095.

Task 1: Palindrome Number

Submitted by: Mohammad S Anwar

You are given a number $N.

Write a script to figure out if the given number is Palindrome. Print 1 if true otherwise 0.

Example 1:
Input: 1221
Output: 1
Example 2:
Input: -101
Output: 0, since -101 and 101- are not the same.
Example 3:
Input: 90
Output: 0

Instead of checking if a number is a palindrome, I will test if an arbitrary string is a palindrome. I simply reverse the string and compare it to the original.

# Perl weekly challenge 095
# Task 1: Palindrome number.
# Figure out if a number is a palindrome.
# See https:/wlmb.github.io/2021/01/11/PWC95/#task-1-palindrome-number
use v5.12;
use strict;
use warnings;
say("Input: $_\nOutput:", ("$_" eq reverse "$_")?1:0) foreach @ARGV;

./ch-1.pl 1221 -101 90

Results:

Input: 1221
Output:1
Input: -101
Output:0
Input: 90
Output:0

This is small enough to be made into a oneliner.

perl -E 'say("Input: $_\nOutput:", ("$_" eq reverse "$_")?1:0) foreach @ARGV' 1221 -101 90;

Results:

Input: 1221
Output:1
Input: -101
Output:0
Input: 90
Output:0

Finally, I make a small variation to remove all punctuation and use lowercase before making the comparison, to test actual palindromes. In this case, I receive the text from STDIN.

# Perl weekly challenge 095
# Task 1: Palindrome number. Alternative solution
# Figure out if a string is a palindrome after stripping punctuation.
# See https:/wlmb.github.io/2021/01/11/PWC95/#task-1-palindrome-number
use v5.12;
use strict;
use warnings;
use English;
undef $INPUT_RECORD_SEPARATOR;
my $input=<>;
(my $clean_input=lc $input)=~s/\W//g;
say("Input:\n$input\nOutput:", ("$clean_input" eq reverse "$clean_input")?1:0);

Example: A children’s palindrome in Spanish:

./ch-1a.pl <<FIN
Anita
lava la
tina.
FIN

Results:

Input:
Anita
lava la
tina.

Output:1

Example: One of Merlina Acevedo’s recent palindromes.

./ch-1a.pl <<EOF
Evil alive's in a man
is a fool, an aloof,
as in a man, is evil
lives in a bar,
a wall
a wiz
a nazi wall,
as in a tan,
ill in a dumb mob
as a bomb
Mud,
an ill in a tan is all:
a wiz
a nazi wall,
a war
a ban
Is evil,
lives in a man,
is a fool, an aloof,
As in a man,
Is evil alive?
EOF

Results:

Input:
Evil alive's in a man
is a fool, an aloof,
as in a man, is evil
lives in a bar,
a wall
a wiz
a nazi wall,
as in a tan,
ill in a dumb mob
as a bomb
Mud,
an ill in a tan is all:
a wiz
a nazi wall,
a war
a ban
Is evil,
lives in a man,
is a fool, an aloof,
As in a man,
Is evil alive?

Output:1

I found that \W gets confused by some punctuation marks, such as the opening question mark ‘¿’ or some quotes ‘´’. I guess I would have to set the adequate locale for it to work with these characters.

Task 2: Demo Stack

Submitted by: Mohammad S Anwar

Write a script to demonstrate Stack operations like below:

push($n) - add $n to the stack pop() - remove the top element top() - get the top element min() - return the minimum element

Example:
my $stack = Stack->new;
$stack->push(2);
$stack->push(-1);
$stack->push(0);
$stack->pop;       # removes 0
print $stack->top; # prints -1
$stack->push(0);
print $stack->min; # prints -1

I make a stack class using Moo and an array for the data. I prints the stack everytime it changes and I print the on-going operation.

# Perl weekly challenge 095
# Task 2: Demo stack.
# Demonstrate Stack operations.
# See https:/wlmb.github.io/2021/01/11/PWC95/#task-2-demo-stack
package Stack;
use List::Util;
use v5.12;
use Moo;
has _stack=>(is=>'ro', default=>sub{[]}, init_arg=>undef);
sub push {
    my $self=shift;
    my $x=shift;
    say "Push:\t$x";
    my $s=$self->_stack;
    push @$s, $x;
    $self->show;
}
sub pop {
    my $self=shift;
    my $s=$self->_stack;
    die "Empty stack" unless defined $s;
    my $top=pop @$s;
    say "Pop:\t$top";
    $self->show;
    return $top;
}
sub top {
    my $self=shift;
    my $top=$self->_stack->[-1];
    say "Top:\t$top";
    return $top;
}
sub exch {
    my $self=shift;
    my $x=$self->pop;
    my $y=$self->pop;
    say "Exch:\t$x <-> $y";
    $self->push($x);
    $self->push($y);
}
sub min {
    my $self=shift;
    my $s=$self->_stack;
    my $min=List::Util::min @$s;
    say "Min:\t$min";
    $self->push($min);
}
sub max {
    my $self=shift;
    my $s=$self->_stack;
    my $max=List::Util::max @$s;
    say "Max:\t$max";
    $self->push($max);
}
sub add {
    my $self=shift;
    my ($x, $y)=($self->pop,$self->pop);
    my $res=$x+$y;
    say "Add:\t$x + $y -> $res";
    $self->push($res);
}
sub sub {
    my $self=shift;
    my ($x, $y)=($self->pop,$self->pop);
    my $res=$y-$x;
    say "Sub:\t$y - $x -> $res";
    say "Sub:\t$res";
    $self->push($res);
}
sub mul {
    my $self=shift;
    my ($x, $y)=($self->pop,$self->pop);
    my $res=$x*$y;
    say "Mul:\t$x * $y -> $res";
    $self->push($res);
}
sub div {
    my $self=shift;
    my ($x, $y)=($self->pop,$self->pop);
    my $res=$y/$x;
    say "Div:\t$y / $x -> $res";
    $self->push($res);
}
sub cs {
    my $self=shift;
    my $x=$self->pop;
    my $res=-$x;
    say "CS:\t$x -> $res";
    $self->push($res);
}
sub inv {
    my $self=shift;
    my $x=$self->pop;
    my $res=1/$x;
    say "Inv:\t1/$x -> $res";
    $self->push($res);
}
sub show {
    my $self=shift;
    my $s=$self->_stack;
    say "Stack:\t", join " ", reverse @$s;
}

Drive the package from STDIN. I use a simple RPN notation to make a primitive calculator. Numbers are pushed, operators operate on the top operands of the stack.

package main;
use Scalar::Util qw(looks_like_number);
my $s=Stack->new;
while(<>){
    chomp;
    $s->push($_), next if looks_like_number($_);
    $s->pop, next if lc $_ eq "pop";
    $s->top, next if lc $_ eq "top";
    $s->exch, next if lc $_ eq "exch";
    $s->min, next if lc $_ eq "min";
    $s->max, next if lc $_ eq "max";
    $s->add, next if $_ eq "+";
    $s->sub, next if lc $_ eq "-";
    $s->mul, next if lc $_ eq "*";
    $s->div, next if lc $_ eq "/";
    $s->cs, next if lc $_ eq "cs"; # change sign
    $s->inv, next if lc $_ eq "inv"; # invert
    $s->show, next if lc $_ eq "show";
    die "Unrecognized op";
}

Example:

./ch-2.pl <<EOF
2
-1
0
pop
top
0
min
EOF

Results:

Push:	2
Stack:	2
Push:	-1
Stack:	-1 2
Push:	0
Stack:	0 -1 2
Pop:	0
Stack:	-1 2
Top:	-1
Push:	0
Stack:	0 -1 2
Min:	-1
Push:	-1
Stack:	-1 0 -1 2

Another example:

./ch-2.pl <<EOF #5/2*2-5=0
2
5
exch
/
2
*
5
-
EOF

Results:

Push:	2
Stack:	2
Push:	5
Stack:	5 2
Pop:	5
Stack:	2
Pop:	2
Stack:
Exch:	5 <-> 2
Push:	5
Stack:	5
Push:	2
Stack:	2 5
Pop:	2
Stack:	5
Pop:	5
Stack:
Div:	5 / 2 -> 2.5
Push:	2.5
Stack:	2.5
Push:	2
Stack:	2 2.5
Pop:	2
Stack:	2.5
Pop:	2.5
Stack:
Mul:	2 * 2.5 -> 5
Push:	5
Stack:	5
Push:	5
Stack:	5 5
Pop:	5
Stack:	5
Pop:	5
Stack:
Sub:	5 - 5 -> 0
Sub:	0
Push:	0
Stack:	0

Yet another example:

./ch-2.pl <<EOF # -1/(1+5-4)*4/2)*4=-1
1
5
+
4
-
4
*
2
/
inv
cs
4
*
EOF

Results:

Push:	1
Stack:	1
Push:	5
Stack:	5 1
Pop:	5
Stack:	1
Pop:	1
Stack:
Add:	5 + 1 -> 6
Push:	6
Stack:	6
Push:	4
Stack:	4 6
Pop:	4
Stack:	6
Pop:	6
Stack:
Sub:	6 - 4 -> 2
Sub:	2
Push:	2
Stack:	2
Push:	4
Stack:	4 2
Pop:	4
Stack:	2
Pop:	2
Stack:
Mul:	4 * 2 -> 8
Push:	8
Stack:	8
Push:	2
Stack:	2 8
Pop:	2
Stack:	8
Pop:	8
Stack:
Div:	8 / 2 -> 4
Push:	4
Stack:	4
Pop:	4
Stack:
Inv:	1/4 -> 0.25
Push:	0.25
Stack:	0.25
Pop:	0.25
Stack:
CS:	0.25 -> -0.25
Push:	-0.25
Stack:	-0.25
Push:	4
Stack:	4 -0.25
Pop:	4
Stack:	-0.25
Pop:	-0.25
Stack:
Mul:	4 * -0.25 -> -1
Push:	-1
Stack:	-1
Written on January 11, 2021