# ETOOBUSY ðŸš€ minimal blogging for the impatient

# PWC114 - Next Palindrome Number

**TL;DR**

Here we are with TASK #1 from the Perl Weekly Challenge #114. Enjoy!

# The challenge

You are given a positive integer

`$N`

.Write a script to find out the next

`Palindrome Number`

higher than the given integer`$N`

.

Example`Input: $N = 1234 Output: 1331 Input: $N = 999 Output: 1001`

# The questions

I guess there are almost no question this time, assuming that:

- a
`Palindrome Number`

is an integer whose representation in base 10 is a palindrome string - we trust our inputs to contain a valid sequence of digits.

# The solution

As it often happens, this challenge can be addressed with a simple
*brute force* attack or something a bit more *aimed*.

The *brute force* in this case would be to start counting from `$N + 1`

on, checking for palindrome values and stopping at the first.

The *aimed* approach requires dealing with a few corner casesâ€¦

## How many digits?

First of all, there is a *corner* case that manwar very gently
reminds us of: a sequence of all `9`

s. This is the only case where the
*next* palindrome actually contains *one more* digit than `$N`

, e.g. for
`999`

we go to `1001`

.

How do I know that this is the *only* case, you might be asking? Well,
if the starting `$N`

contains any digit that is *not* a `9`

, then `$N`

will surely be *less than* a sequence of `9`

s that is long the same as
`$N`

. Considering that a sequence of all `9`

s *is* palindrome, surely
any number below it has a greater palindrome that has the same number of
digits.

OK, so we will treat a sequence of all `9`

s as a special case, what to
do next?

## Even number of digits

If we have an even number of digits, then we only need to *count* on the
first half of the number, because the second half is constrained by the
palindrome constraint. To get the *lowest* number, it will be just
regular counting.

Whatever candidate we get for the first half, we can easily form the
full number and check it against `$N`

. If itâ€™s greater than `$N`

weâ€™re
done! Otherwise, just increasing the first half by one unit will
suffice.

## Odd number of digits

This case is *pretty much* similar to the previous, but not the same
because itâ€™s difficult to cut the string representation of `$N`

*in
half*. So we will take just half-a-character less of one half and put it
into `$n`

, and treat the middle character `$mid`

specially.

As before, our first attempt is to work with what we have, i.e. merging
`$n`

, `$mid`

and the reverse of `$n`

. If itâ€™s greater than `$N`

weâ€™re
done.

Next, to get the *closest greater* one, we try to increase `$mid`

. This
will workâ€¦ unless `$mid`

is equal to `9`

, which forces us to increase
`$n`

instead.

## Putting even and odd cases together

The two cases for even and odd alternatives are pretty similar, except for some special handling of the middle character. Hence, with a few special casesâ€¦ we should be able to address both cases in a mostly unified way.

## Perl solution

Letâ€™s start with the Perl solution:

```
#!/usr/bin/env perl
use 5.024;
use warnings;
use experimental qw< postderef signatures >;
no warnings qw< experimental::postderef experimental::signatures >;
sub next_palindrome_number ($N) {
my $l = length $N;
return '1' . ('0' x ($l - 1)) . '1' unless $N =~ m{[0-8]}mxs;
my $n = substr $N, 0, $l / 2;
my $mid = $l % 2 ? substr($N, $l / 2, 1) : '';
# just try to build straight from the inputs...
if ((my $candidate = $n . $mid . reverse($n)) > $N) {
return $candidate;
}
# if there's a "$mid", try increasing that
if ($l % 2) {
return $n . ($mid + 1) . reverse($n) if $mid != 9;
$mid = 0;
}
++$n;
return $n . $mid . reverse($n);
}
@ARGV = (1234) unless @ARGV;
say next_palindrome_number($_) for @ARGV;
```

I hope it has no surprises after the explanations above!

## Raku solution

So hereâ€™s the *translation* of the solution in Raku:

```
#!/usr/bin/env raku
use v6;
sub next-palindrome-number (IntStr $N) {
my $l = $N.chars;
return '1' ~ ('0' x ($l - 1)) ~ '1' unless $N ~~ m{<[0 .. 8]>};
my $n = $N.substr(0, $l / 2);
my $mid = $l % 2 ?? $N.substr($l / 2, 1) !! '';
# just try to build straight from the inputs...
if (my $candidate = $n ~ $mid ~ $n.flip) > $N {
return $candidate;
}
# if there's a "$mid", try increasing that
if ($l % 2) {
return $n ~ ($mid + 1) ~ $n.flip if $mid < 9;
$mid = 0;
}
++$n;
return $n ~ $mid ~ $n.flip;
}
sub MAIN (*@inputs is copy) {
@inputs.push(1234) unless @inputs.elems;
next-palindrome-number($_).say for @inputs;
}
```

This is basically my second (wellâ€¦ third) venture in Raku, and so
far itâ€™s been a bit *frustrating*.

Ok, ok, it was an occasion to break with the past and fix a few things.
Was it really necessary to move from `reverse`

to `flip`

? Change the
ternary operator that we all love from C into `?? !!`

? Turn character
classes to something different from the rest of the world?

Probably yes, but itâ€™s frustrating. For me, at least.

Another nit-pick is about the signatures, especially for `MAIN`

. I think
that thereâ€™s been a substantial loss in *whipuptitude*, because it took
me a bit to figure how to replicate the *simple* input arguments passing
that we have in Perl.

I mean, I usually resort to Getopt::Long for getting input
parameters, and I understand that the signature for `MAIN()`

can help
with this. But, againâ€¦ *whipuptitude* lost in my opinion.

Or, maybeâ€¦ I didnâ€™t read enough ðŸ™„

*Comments? Octodon, Twitter, GitHub, Reddit, or drop me a line!*