This is my response to the Perl Weekly Challenge #{{PWC}}.
Example
Input: [ 2, 5, -1, 3 ]
Output: [ 2, 5 ]
which gives maximum product 10.
The values are stated to be numbers, so not restrictive
in any way. The Raku type Numeric
fits the bill.
unit sub MAIN (*@list where @list.elems >= 4 && all(@list) ~~ Numeric);
# [1] ###### # [1a] ######## ## # [1b] ##############
[1]
A slurpy array collecting all the arguments. It allows zero
arguments, so we explicitly demand 4 or more [1a]. Then we ensure that they all
are of the Numeric
type with an all
Junction [1b].
See docs.raku.org/type/Signature#index-entry-slurpy_argument for more information about slurpy arguments.
See
docs.raku.org/routine/all for
more information about all
, and
docs.raku.org/type/Junction for
more information about Junctions.
See
docs.raku.org/type/Numeric for
more information about the Numeric
type.
Then two loops iterating over all the possible contiguous sublists (with at least two items), and just printing them.
File: psu0 (partial)
for 0 .. @list.end - 1 -> $left # [2]
{
for $left + 1 .. @list.end -> $right # [3]
{
say ": (L:$left R:$right) -> @list[$left .. $right]"; # [4]
}
}
[2] Iterate the start of the sublist,
[3] and the end.
[4] Show that we got it right.
Running it:
$ raku psu0 1 2 3
Usage:
psu0 [<list> ...]
$ raku psu0 1 2 3 4
: (L:0 R:1) -> 1 2
: (L:0 R:2) -> 1 2 3
: (L:0 R:3) -> 1 2 3 4
: (L:1 R:2) -> 2 3
: (L:1 R:3) -> 2 3 4
: (L:2 R:3) -> 3 4
$ raku psu0 1 2 3 4 5 6
: (L:0 R:1) -> 1 2
: (L:0 R:2) -> 1 2 3
: (L:0 R:3) -> 1 2 3 4
: (L:0 R:4) -> 1 2 3 4 5
: (L:0 R:5) -> 1 2 3 4 5 6
: (L:1 R:2) -> 2 3
: (L:1 R:3) -> 2 3 4
: (L:1 R:4) -> 2 3 4 5
: (L:1 R:5) -> 2 3 4 5 6
: (L:2 R:3) -> 3 4
: (L:2 R:4) -> 3 4 5
: (L:2 R:5) -> 3 4 5 6
: (L:3 R:4) -> 4 5
: (L:3 R:5) -> 4 5 6
: (L:4 R:5) -> 5 6
Looking good. It requires 4 or more elements, and we got all the contiguous sublists with at least two elements
Then we can do the real work, inside the double loops:
File: psu1
unit sub MAIN (*@list where @list.elems >= 4 && all(@list) ~~ Numeric,
:$verbose); # [1]
my $maximum = 0; # [2]
my @max_array; # [3]
for 0 .. @list.end - 1 -> $left
{
for $left + 1 .. @list.end -> $right
{
my @current = @list[$left .. $right]; # [4]
my $product = [*] @current; # [5]
say ": (L:$left R:$right) -> @urrent[] -> *$product" if $verbose; # [1]
if $product == $maximum # [6]
{
@max_array.push: @current; # [6a]
}
elsif $product > $maximum # [7]
{
$maximum = $product; # [7a]
@max_array = @current,; # [7b]
}
}
}
say @max_array; # [8]
[1] The old behaviour, available with the «--verbose» command line option.
[2] The higest value, so far.
[3] The array with the highest value, so far.
[4] Get the current sublist.
[5] Get the product of the sublist, using
the Reduction Metaoperator [*]
(where *
is the operator)
to multiply all the values in the sublist.
[6] If the current sublist has the same value as the currently highest, add it to the list [6a].
[7] If it is higher, set the new maxiumum value [7a], clear the list and add the sublist as a sublist (the trailing comma, which is the list operator) [7b]. The reult is a list with one element (which is a list).
[8] Print the result, one or more sublists.
See docs.raku.org/language/operators#Reduction_metaoperators for more information about Reduction metaoperators.
See
docs.raku.org/routine/,
for more information about the list operator ,
.
The list given in the challenge gives the correct result:
$ raku psu1 2 5 -1 3
[2 5]
$ raku psu1 --verbose 2 5 -1 3
: (L:0 R:1) -> 2 5 ---> 10
: (L:0 R:2) -> 2 5 -1 ---> -10
: (L:0 R:3) -> 2 5 -1 3 ---> -30
: (L:1 R:2) -> 5 -1 ---> -5
: (L:1 R:3) -> 5 -1 3 ---> -15
: (L:2 R:3) -> -1 3 ---> -3
Let us try some other values:
$ raku psu1 -10 1 -1 1 -12
[[1 -1 1 -12] [-1 1 -12]]
$ raku psu1 --verbose -10 1 -1 1 -12
: (L:0 R:1) -> -10 1 ---> -10
: (L:0 R:2) -> -10 1 -1 ---> 10
: (L:0 R:3) -> -10 1 -1 1 ---> 10
: (L:0 R:4) -> -10 1 -1 1 -12 ---> -120
: (L:1 R:2) -> 1 -1 ---> -1
: (L:1 R:3) -> 1 -1 1 ---> -1
: (L:1 R:4) -> 1 -1 1 -12 ---> 12
: (L:2 R:3) -> -1 1 ---> -1
: (L:2 R:4) -> -1 1 -12 ---> 12
: (L:3 R:4) -> 1 -12 ---> -12
[[1 -1 1 -12] [-1 1 -12]]
Note that two different sublists gives the same answer, so the program prints both.
We can add code showing the maximum product:
File: psu2 (changes only)
unit sub MAIN (*@list where @list.elems >= 4 && all(@list) ~~ Numeric,
:$verbose, :$product);
print "[*:$maximum] -> " if $product;
say @max_array;
Running it:
$ raku psu2 -10 1 -1 1 -12
[[1 -1 1 -12] [-1 1 -12]]
$ raku psu2 --product -10 1 -1 1 -12
[*:12] -> [[1 -1 1 -12] [-1 1 -12]]
$ raku psu2 --product --verbose -10 1 -1 1 -12
: (L:0 R:1) -> -10 1 ---> -10
: (L:0 R:2) -> -10 1 -1 ---> 10
: (L:0 R:3) -> -10 1 -1 1 ---> 10
: (L:0 R:4) -> -10 1 -1 1 -12 ---> -120
: (L:1 R:2) -> 1 -1 ---> -1
: (L:1 R:3) -> 1 -1 1 ---> -1
: (L:1 R:4) -> 1 -1 1 -12 ---> 12
: (L:2 R:3) -> -1 1 ---> -1
: (L:2 R:4) -> -1 1 -12 ---> 12
: (L:3 R:4) -> 1 -12 ---> -12
[*:12] -> [[1 -1 1 -12] [-1 1 -12]]
Looking good.
A more extreme example:
$ raku psu2 --product --verbose -10 1 1 1 1
: (L:0 R:1) -> -10 1 ---> -10
: (L:0 R:2) -> -10 1 1 ---> -10
: (L:0 R:3) -> -10 1 1 1 ---> -10
: (L:0 R:4) -> -10 1 1 1 1 ---> -10
: (L:1 R:2) -> 1 1 ---> 1
: (L:1 R:3) -> 1 1 1 ---> 1
: (L:1 R:4) -> 1 1 1 1 ---> 1
: (L:2 R:3) -> 1 1 ---> 1
: (L:2 R:4) -> 1 1 1 ---> 1
: (L:3 R:4) -> 1 1 ---> 1
[*:1] -> [[1 1] [1 1 1] [1 1 1 1] [1 1] [1 1 1] [1 1]]
Note the repetitions in the sublists. They have the same values, but come from different parts of the original list. We can get rid of them (as we report the values, and not the positions, so they don't make sense):
File: psu3 (changes only)
say @max_array.unique(:with(&[eqv])); # [1]
[1]
Comparing lists (as we have a list of lists)
as done behind the scenes by unique
doesn't work, but we can ask
it to do a recursive comparison with the Equivalence Operator eqv
.
The :with
argument takes a procedure, but we can use brackets to specify
an operator. The &
part is there to get a reference and not calling it
straight away.
See
docs.raku.org/routine/unique for
more information about unique
.
See
docs.raku.org/routine/eqv for more
information about the Equivalence Operator eqv
.
Running it:
$ raku psu3 --product --verbose -10 1 1 1 1
: (L:0 R:1) -> -10 1 ---> -10
: (L:0 R:2) -> -10 1 1 ---> -10
: (L:0 R:3) -> -10 1 1 1 ---> -10
: (L:0 R:4) -> -10 1 1 1 1 ---> -10
: (L:1 R:2) -> 1 1 ---> 1
: (L:1 R:3) -> 1 1 1 ---> 1
: (L:1 R:4) -> 1 1 1 1 ---> 1
: (L:2 R:3) -> 1 1 ---> 1
: (L:2 R:4) -> 1 1 1 ---> 1
: (L:3 R:4) -> 1 1 ---> 1
[*:1] -> [[1 1] [1 1 1] [1 1 1 1]]
An finally, trying with some creative values:
$ raku psu3 --product 10 1/3 -11 1
[*:3.333333] -> ([10 1/3])
$ raku psu3 --product 30 0.67 -11 1
[*:20.1] -> ([30 0.67])
The program works fine, as long as we have the requirement of at least 4 values in the input list. The lowest possible value for the product is 0 (as shown in the table below), so the initial lowest value of 0 in the code isn't a problem.
Initial Values | Chosen Sublist | Product |
---|---|---|
[0 0 0 0] | [0 0] | 0 |
[0 -12 0 0] | [0 0] | 0 |
[1 -12 1 1] | [1 1] | 1 |
[1 -12 1 -1] | [-12 1 -1] | 12 |
If we reduce the requirement on the input list to be 2 or more items, the initial
value of 0 is a problem. Setting it to -Inf
solves that.
The challenge was specific about the limit, so I have added a command line option where we can override the default value 4.
The final program:
File: psu
unit sub MAIN (
:$min = 4, # [1]
*@list where @list.elems >= $min && all(@list) ~~ Numeric, # [2]
:$verbose,
:$product
);
say ": Minimum number of elements: $min" if $verbose;
my $maximum = -Inf;
my @max_array;
for 0 .. @list.end - 1 -> $left
{
for $left + 1 .. @list.end -> $right
{
my @current = @list[$left .. $right];
my $product = [*] @current;
say ": (L:$left R:$right) -> @current[] ---> $product" if $verbose;
if $product == $maximum
{
@max_array.push: @current;
}
elsif $product > $maximum
{
$maximum = $product;
@max_array = ();
@max_array.push: @current;
}
}
}
print "[*:$maximum] -> " if $product;
say @max_array.unique(:with(&[eqv]));
[1] We have to declare the new varible before using it (in [2]).
[2] Using the new variable to check the length of the array.
See
docs.raku.org/type/Num#index-entry-Inf_(definition) for
more information about Inf
.
Trying it out with some potentially problematic values:
$ raku psu --min=2 --product Inf Inf
[*:Inf] -> ([Inf Inf])
$ raku psu --min=2 --product Inf 1
[*:Inf] -> ([Inf 1])
$ raku psu --min=2 --product Inf 0
[*:-Inf] -> ()
$ raku psu --min=2 --product Inf -Inf
[*:-Inf] -> ([Inf -Inf])
The third one is (also) correct, as Inf * 0 -> NaN
.
You are given a string containing only digits (0..9). The string should have between 4 and 12 digits.
Write a script to print every possible valid IPv4 address that can be made by partitioning the input string.
For the purpose of this challenge, a valid IPv4 address consists of four
“octets” i.e. A, B, C and D, separated by dots
(.
).
Each octet must be between 0 and 255, and must not have any leading
zeroes. (e.g., 0
is OK, but 01
is not.)
Example
Input: 25525511135
,
Output:
255.255.11.135
255.255.111.35
I'll start with validating the input. A leading zero (as in «0111» -> «0.1.1.1») is OK, and we can actually have four zeroes and nothing else («0000» -> «0.0.0.0»). This means that the input must be treated as a string, and not an integer (to avoid missing any leading zeroes).
subset IP-Decimal where 4 <= $_.chars <= 12 && all($_.comb) ~~ /<[0..9]>/;
# [1] ########## # [2] ################### # [3] ####################
[1] A custom type declared with subset
. Note the missing
of Str
part that we can leave out as it wouldn't restrict the values.
[2] A where
clause where we restrict the legal values.
The first part checks the length of the string, by chaining to comparisons.
[3] And the second part uses an all
Junction to check that all the
individual characters of the string (which we get with comb
) are indeed
digits.
We can try it in REPL mode:
> subset IP-Decimal where 4 <= $_.chars <= 12 && all($_.comb) ~~ /<[0..9]>/;
(IP-Decimal)
> "12" ~~ IP-Decimal
False
> "1211" ~~ IP-Decimal
True
> 1211 ~~ IP-Decimal
True
> "121a1" ~~ IP-Decimal
False
It works for both numbers (without quotes) and strings (with quotes).
We can simplify the second part by smartmatching against the Int
type instead of using a Junction:
subset IP-Decimal where 4 <= $_.chars <= 12 && $_ ~~ Int;
Testing it with REPL:
> subset IP-Decimal where 4 <= $_.chars <= 12 && $_ ~~ Int;
(IP-Decimal)
> "12" ~~ IP-Decimal
False
> "1211" ~~ IP-Decimal
False
> 1211 ~~ IP-Decimal
True
> "121a1" ~~ IP-Decimal
False
A string will not smartmatch with Int
, even if the
content is an integer. This is a problem in REPL, and not when we use a value from
the command line, as we get a value of the IntStr
type then. (As Raku
sees the difference between numbers and strings by the presence of quotes. Values
from the command line are without quotes, as the Shell removes them.)
See
docs.raku.org/type/IntStr for
more information about IntStr
.
The documentation states that we get values of the IntStr
if we quote
them like this: <12>
. Let us try:
> <211> ~~ IP-Decimal4
True
> <1211a> ~~ IP-Decimal4
False
But we can simplify the second part even further, by trying to coerce the value
to an integer. (And I removed $_
, as that is implied if we apply
a method on nothing.)
subset IP-Decimal where 4 <= .chars <= 12 && .Int;
And this one works for strings as well:
> <1211a> ~~ IP-Decimal
False
> <1211> ~~ IP-Decimal
True
> <12aa11> ~~ IP-Decimal
False
> "12aa11" ~~ IP-Decimal
False
> "1211" ~~ IP-Decimal
True
I have decided to treat this as en excercise in merging lists. We need a binary mask (yeah, not the right name for this, but I had to call it something) to insert beteen the digits in the input string:
The stars are either «0» or «1», and we substitute «1» with a dot and remove the «0» to get the (potential) IP address.
File: ipv4 (partial)
subset IP-Decimal where 4 <= .chars <= 12 && .Int; # [1]
unit sub MAIN (IP-Decimal $ip-decimal, :$verbose); # [1]
my @ipv4 = $ip-decimal.comb; # [2]
my $length = $ip-decimal.chars - 1; # [3]
my $decimal = 2 ** $length -1; # [4]
say ": Binary mask: { 1 x $length } - $decimal" if $verbose; # [5]
[1] Use the custom type to validat the input.
[2] Get the individual digits (as a list).
[3] Get the length of the binary mask.
[4] Get the decimal value of the binary mask. See the illustration for explanation.
[5] Verbose output, showing that we got it right.
By iterating all the values from 1 up to the higest value for the mask, we get all the possible positions for the periods:
File: ipv4 (partial)
CANDIDATE: for 1 .. $decimal -> $current # [6]
{
my $val = $current.fmt("%0" ~ $length ~ "b"); # [7]
my $old-val = $val; # [8]
[6] Iterate over all the possible binary masks (as a decimal value).
[7] Get the binary value, padded with leading zeros.
[8] Don't worry abouth this one. It is used by verbose mode only.
Most of the candidates have the wrong number of dots (anything else than 3) and can be discarded easily:
File: ipv4 (partial)
next unless $val.comb.sum == 3; # [9]
[9] The binary number has «1» where the periods are (and «0» for the rest). We can simply count them.
Note that we could have started the loop at a higher value than 1, as we require 3
instances of «1», with at least one «0» between them. "10101".parse-base(2)
gives us 21, which we could us a s the lower limit. But it doesn't really matter
as the program is quick enough.
We convert the «0» in the mask to nothing (a space first, which we'll remove later, as we need a letter to get the correct number of elements in the list), and the «1» to «.» to get a candidate:
File: ipv4 (partial)
$val ~~ tr/01/ ./;
Merging two lists with one value from each list (called zip merge)
is easy in Raku, as it has a zip
function (and a corresponding Z
operator) built in. The problem is that it stops when the first list is empty, so the
final value («8» in the illustration) will be lost. We could have added a trailing space
to $val
(in [5]; e.g. $current.fmt("%0" ~ $length ~ "b") ~ " "
),
but it is better to use roundrobin
instead - as it goes on until both lists
are empty:
> zip <1 2 3 4 5 6 7 8>, <x x x x x x x>
((1 x) (2 x) (3 x) (4 x) (5 x) (6 x) (7 x))
> <1 2 3 4 5 6 7 8> Z <x x x x x x x>
((1 x) (2 x) (3 x) (4 x) (5 x) (6 x) (7 x))
> roundrobin <1 2 3 4 5 6 7 8>, <x x x x x x x>
((1 x) (2 x) (3 x) (4 x) (5 x) (6 x) (7 x) (8))
Note that we get a list of Pair
objects, and not really a flat list. But that is not a problem in practice.
See
docs.raku.org/routine/roundrobin
for more information about zip
function.
See
docs.raku.org/routine/zip for more
information about zip
function.
See
docs.raku.org/routine/Z for more
information about Z
operator.
my $ip = (roundrobin @ipv4, $val.comb).join.trans(' ' => ''); # [10]
say ": Iterate: $ip-decimal | $current | $old-val ($val) -> \
$ip: Found 4 parts" if $verbose;
[10] The join
call flattens the list for us (see above), and the
trans
call removes the spaces in the resulting string.
my @elems = $ip.split("."); # [11]
next if any(@elems) > 255; # [12]
for 0 .. 3 -> $index # [13]
{
next CANDIDATE if @elems[$index].Int ne @elems[$index]; # [14]
# next CANDIDATE if @elems[$index] > 255; # [15]
}
say @elems.join("."); # [16]
}
[11] Get the four octets.
[12] Discared the candidate if any of the octets have a too high value.
[13] For each octet,
[14] • Discard the candidate if the octet has leading zeroes. (The
Int
call turns the value into an integer, removing any leading
zeroes.)
[15] Use this unstead of [12] if you don't like Junctions.
[15] We have a legal IP address. Print it.
Running it:
$ raku ipv4 0000
0.0.0.0
$ raku ipv4 00000
$ raku ipv4 12345678
123.45.67.8
123.45.6.78
123.4.56.78
12.34.56.78
1.234.56.78
$ raku ipv4 --verbose 12345
: Binary mask: 1111 - 15
: Iterate: 12345 | 7 | 0111 ( ...) -> 12.3.4.5: Found 4 parts
12.3.4.5
: Iterate: 12345 | 11 | 1011 (. ..) -> 1.23.4.5: Found 4 parts
1.23.4.5
: Iterate: 12345 | 13 | 1101 (.. .) -> 1.2.34.5: Found 4 parts
1.2.34.5
: Iterate: 12345 | 14 | 1110 (... ) -> 1.2.3.45: Found 4 parts
1.2.3.45
And finally a longer example:
$ raku ipv4 123456789
123.45.67.89
$ raku ipv4 --verbose 123456789
: Binary mask: 11111111 - 255
: Iterate: 123456789 | 7 | 00000111 ( ...) -> 123456.7.8.9: Found 4 parts
: Iterate: 123456789 | 11 | 00001011 ( . ..) -> 12345.67.8.9: Found 4 parts
: Iterate: 123456789 | 13 | 00001101 ( .. .) -> 12345.6.78.9: Found 4 parts
: Iterate: 123456789 | 14 | 00001110 ( ... ) -> 12345.6.7.89: Found 4 parts
: Iterate: 123456789 | 19 | 00010011 ( . ..) -> 1234.567.8.9: Found 4 parts
: Iterate: 123456789 | 21 | 00010101 ( . . .) -> 1234.56.78.9: Found 4 parts
: Iterate: 123456789 | 22 | 00010110 ( . .. ) -> 1234.56.7.89: Found 4 parts
: Iterate: 123456789 | 25 | 00011001 ( .. .) -> 1234.5.678.9: Found 4 parts
: Iterate: 123456789 | 26 | 00011010 ( .. . ) -> 1234.5.67.89: Found 4 parts
: Iterate: 123456789 | 28 | 00011100 ( ... ) -> 1234.5.6.789: Found 4 parts
: Iterate: 123456789 | 35 | 00100011 ( . ..) -> 123.4567.8.9: Found 4 parts
: Iterate: 123456789 | 37 | 00100101 ( . . .) -> 123.456.78.9: Found 4 parts
: Iterate: 123456789 | 38 | 00100110 ( . .. ) -> 123.456.7.89: Found 4 parts
: Iterate: 123456789 | 41 | 00101001 ( . . .) -> 123.45.678.9: Found 4 parts
: Iterate: 123456789 | 42 | 00101010 ( . . . ) -> 123.45.67.89: Found 4 parts
123.45.67.89
: Iterate: 123456789 | 44 | 00101100 ( . .. ) -> 123.45.6.789: Found 4 parts
: Iterate: 123456789 | 49 | 00110001 ( .. .) -> 123.4.5678.9: Found 4 parts
: Iterate: 123456789 | 50 | 00110010 ( .. . ) -> 123.4.567.89: Found 4 parts
: Iterate: 123456789 | 52 | 00110100 ( .. . ) -> 123.4.56.789: Found 4 parts
: Iterate: 123456789 | 56 | 00111000 ( ... ) -> 123.4.5.6789: Found 4 parts
: Iterate: 123456789 | 67 | 01000011 ( . ..) -> 12.34567.8.9: Found 4 parts
: Iterate: 123456789 | 69 | 01000101 ( . . .) -> 12.3456.78.9: Found 4 parts
: Iterate: 123456789 | 70 | 01000110 ( . .. ) -> 12.3456.7.89: Found 4 parts
: Iterate: 123456789 | 73 | 01001001 ( . . .) -> 12.345.678.9: Found 4 parts
: Iterate: 123456789 | 74 | 01001010 ( . . . ) -> 12.345.67.89: Found 4 parts
: Iterate: 123456789 | 76 | 01001100 ( . .. ) -> 12.345.6.789: Found 4 parts
: Iterate: 123456789 | 81 | 01010001 ( . . .) -> 12.34.5678.9: Found 4 parts
: Iterate: 123456789 | 82 | 01010010 ( . . . ) -> 12.34.567.89: Found 4 parts
: Iterate: 123456789 | 84 | 01010100 ( . . . ) -> 12.34.56.789: Found 4 parts
: Iterate: 123456789 | 88 | 01011000 ( . .. ) -> 12.34.5.6789: Found 4 parts
: Iterate: 123456789 | 97 | 01100001 ( .. .) -> 12.3.45678.9: Found 4 parts
: Iterate: 123456789 | 98 | 01100010 ( .. . ) -> 12.3.4567.89: Found 4 parts
: Iterate: 123456789 | 100 | 01100100 ( .. . ) -> 12.3.456.789: Found 4 parts
: Iterate: 123456789 | 104 | 01101000 ( .. . ) -> 12.3.45.6789: Found 4 parts
: Iterate: 123456789 | 112 | 01110000 ( ... ) -> 12.3.4.56789: Found 4 parts
: Iterate: 123456789 | 131 | 10000011 (. ..) -> 1.234567.8.9: Found 4 parts
: Iterate: 123456789 | 133 | 10000101 (. . .) -> 1.23456.78.9: Found 4 parts
: Iterate: 123456789 | 134 | 10000110 (. .. ) -> 1.23456.7.89: Found 4 parts
: Iterate: 123456789 | 137 | 10001001 (. . .) -> 1.2345.678.9: Found 4 parts
: Iterate: 123456789 | 138 | 10001010 (. . . ) -> 1.2345.67.89: Found 4 parts
: Iterate: 123456789 | 140 | 10001100 (. .. ) -> 1.2345.6.789: Found 4 parts
: Iterate: 123456789 | 145 | 10010001 (. . .) -> 1.234.5678.9: Found 4 parts
: Iterate: 123456789 | 146 | 10010010 (. . . ) -> 1.234.567.89: Found 4 parts
: Iterate: 123456789 | 148 | 10010100 (. . . ) -> 1.234.56.789: Found 4 parts
: Iterate: 123456789 | 152 | 10011000 (. .. ) -> 1.234.5.6789: Found 4 parts
: Iterate: 123456789 | 161 | 10100001 (. . .) -> 1.23.45678.9: Found 4 parts
: Iterate: 123456789 | 162 | 10100010 (. . . ) -> 1.23.4567.89: Found 4 parts
: Iterate: 123456789 | 164 | 10100100 (. . . ) -> 1.23.456.789: Found 4 parts
: Iterate: 123456789 | 168 | 10101000 (. . . ) -> 1.23.45.6789: Found 4 parts
: Iterate: 123456789 | 176 | 10110000 (. .. ) -> 1.23.4.56789: Found 4 parts
: Iterate: 123456789 | 193 | 11000001 (.. .) -> 1.2.345678.9: Found 4 parts
: Iterate: 123456789 | 194 | 11000010 (.. . ) -> 1.2.34567.89: Found 4 parts
: Iterate: 123456789 | 196 | 11000100 (.. . ) -> 1.2.3456.789: Found 4 parts
: Iterate: 123456789 | 200 | 11001000 (.. . ) -> 1.2.345.6789: Found 4 parts
: Iterate: 123456789 | 208 | 11010000 (.. . ) -> 1.2.34.56789: Found 4 parts
: Iterate: 123456789 | 224 | 11100000 (... ) -> 1.2.3.456789: Found 4 parts
And that's it.