diff options
| author | Mohammad Sajid Anwar <Mohammad.Anwar@yahoo.com> | 2024-09-29 19:43:13 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-29 19:43:13 +0100 |
| commit | b1cd8eaccef473671cddffe2a8fd68f8ed0d99ed (patch) | |
| tree | 24c10a4ca0044dce9f0de8506bb86fe01897612b | |
| parent | b49b67ce568b3f8929823965bb905d221895b761 (diff) | |
| parent | d7f8cc252462bac699dcf32d80224fe4ffc19e99 (diff) | |
| download | perlweeklychallenge-club-b1cd8eaccef473671cddffe2a8fd68f8ed0d99ed.tar.gz perlweeklychallenge-club-b1cd8eaccef473671cddffe2a8fd68f8ed0d99ed.tar.bz2 perlweeklychallenge-club-b1cd8eaccef473671cddffe2a8fd68f8ed0d99ed.zip | |
Merge pull request #10922 from PerlMonk-Athanasius/branch-for-challenge-288
Perl & Raku solutions to Tasks 1 & 2 for Week 288
| -rw-r--r-- | challenge-288/athanasius/perl/ch-1.pl | 200 | ||||
| -rw-r--r-- | challenge-288/athanasius/perl/ch-2.pl | 425 | ||||
| -rw-r--r-- | challenge-288/athanasius/raku/ch-1.raku | 198 | ||||
| -rw-r--r-- | challenge-288/athanasius/raku/ch-2.raku | 406 |
4 files changed, 1229 insertions, 0 deletions
diff --git a/challenge-288/athanasius/perl/ch-1.pl b/challenge-288/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..fd42ec5ca8 --- /dev/null +++ b/challenge-288/athanasius/perl/ch-1.pl @@ -0,0 +1,200 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 288 +========================= + +TASK #1 +------- +*Closest Palindrome* + +Submitted by: Mohammad Sajid Anwar + +You are given a string, $str, which is an integer. + +Write a script to find out the closest palindrome, not including itself. If +there are more than one then return the smallest. + + The closest is defined as the absolute difference minimized between two + integers. + +Example 1 + + Input: $str = "123" + Output: "121" + +Example 2 + + Input: $str = "2" + Output: "1" + + There are two closest palindrome "1" and "3". Therefore we return the smallest + "1". + +Example 3 + + Input: $str = "1400" + Output: "1441" + +Example 4 + + Input: $str = "1001" + Output: "999" + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Assumption +---------- +The input integer is unsigned (non-negative). + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. A string representing an unsigned integer is entered on the command-line. + +=cut +#=============================================================================== + +use v5.32; # Enables strictures and warnings +use Const::Fast; +use Regexp::Common qw( number ); +use Test::More; + +const my $USAGE => <<END; +Usage: + Usage: + perl $0 <str> + perl $0 + + <str> A string representing an unsigned integer +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 288, Task #1: Closest Palindrome (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + my $argc = scalar @ARGV; + + if ($argc == 0) + { + run_tests(); + } + elsif ($argc == 1) + { + my $str = $ARGV[ 0 ]; + $str =~ / ^ $RE{num}{int} $ /x + or error( qq["$str" is not a valid integer] ); + $str >= 0 or error( "$str is negative" ); + $str += 0; # Normalize + + print qq[Input: \$str = "$str"\n]; + + my $closest_palindrome = find_closest_palindrome( $str ); + + print qq[Output: "$closest_palindrome"\n]; + } + else + { + error( "Expected 1 or 0 command-line arguments, found $argc" ); + } +} + +#------------------------------------------------------------------------------- +sub find_closest_palindrome +#------------------------------------------------------------------------------- +{ + my ($int) = @_; + + return 1 if $int == 0; + + my $above = $int + 1; + ++$above until is_palindrome( $above ); + + my $below = $int - 1; + --$below until is_palindrome( $below ); + + my $above_diff = $above - $int; + my $below_diff = $int - $below; + + return ($above_diff < $below_diff) ? $above : $below; +} + +#------------------------------------------------------------------------------- +sub is_palindrome +#------------------------------------------------------------------------------- +{ + my ($int) = @_; + my @digits = split //, $int; + + for my $i (0 .. int( $#digits / 2 )) + { + return 0 unless $digits[ $i ] == $digits[ $#digits - $i ]; + } + + return 1; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $str, $expected) = split / \| /x, $line; + + for ($test_name, $str, $expected) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my $closest_palindrome = find_closest_palindrome( $str ); + + is $closest_palindrome, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1| 123| 121 +Example 2| 2| 1 +Example 3| 1400| 1441 +Example 4| 1001| 999 +Zero | 0| 1 +One | 1| 0 +1 Million|1000000|999999 +Odd | 12721| 12621 diff --git a/challenge-288/athanasius/perl/ch-2.pl b/challenge-288/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..2d520dd368 --- /dev/null +++ b/challenge-288/athanasius/perl/ch-2.pl @@ -0,0 +1,425 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 288 +========================= + +TASK #2 +------- +*Contiguous Block* + +Submitted by: Peter Campbell Smith + +You are given a rectangular matrix where all the cells contain either x or o. + +Write a script to determine the size of the largest contiguous block. + + A contiguous block consists of elements containing the same symbol which + share an edge (not just a corner) with other elements in the block, and + where there is a path between any two of these elements that crosses only + those shared edges. + +Example 1 + + Input: $matrix = [ + ['x', 'x', 'x', 'x', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'x', 'x', 'o', 'o'], + ] + Output: 11 + + There is a block of 9 contiguous cells containing 'x'. + There is a block of 11 contiguous cells containing 'o'. + +Example 2 + + Input: $matrix = [ + ['x', 'x', 'x', 'x', 'x'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'x', 'x', 'x', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ] + Output: 11 + + There is a block of 11 contiguous cells containing 'x'. + There is a block of 9 contiguous cells containing 'o'. + +Example 3 + + Input: $matrix = [ + ['x', 'x', 'x', 'o', 'o'], + ['o', 'o', 'o', 'x', 'x'], + ['o', 'x', 'x', 'o', 'o'], + ['o', 'o', 'o', 'x', 'x'], + ] + Output: 7 + + There is a block of 7 contiguous cells containing 'o'. + There are two other 2-cell blocks of 'o'. + There are three 2-cell blocks of 'x' and one 3-cell. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. A single string is entered on the command-line, e.g., "xxxo xooo xooo xxoo". + This string comprises whitespace-separated rows; each row contains only the + characters 'x' or 'o'. The matrix represented must be rectangular and not + empty. +3. If $VERBOSE is set to a true value, the output is augmented with a matrix + diagram showing the different contiguous blocks found, and identifying the + largest. + +=cut +#=============================================================================== + +use v5.32; # Enables strictures and warnings +use Const::Fast; +use Test::More; + +const my $VERBOSE => 1; +const my $USAGE => <<END; +Usage: + perl $0 <matrix-str> + perl $0 + + <matrix-str> Non-empty matrix string, e.g., "xxxo xooo xooo xxoo" +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 288, Task #2: Contiguous Block (Perl)\n\n"; +} + +#=============================================================================== +package Matrix +#=============================================================================== +{ + use List::Util qw( max ); + use Moo; + use namespace::clean; + + #--------------------------------------------------------------------------- + # Attributes + #--------------------------------------------------------------------------- + + has matrix => ( is => 'ro' ); + has rows => ( is => 'ro' ); + has cols => ( is => 'ro' ); + + #--------------------------------------------------------------------------- + around BUILDARGS => sub + #--------------------------------------------------------------------------- + { + my ($orig, $class, @args) = @_; + + return { matrix_str => $args[ 0 ] }; + }; + + #--------------------------------------------------------------------------- + sub BUILD + #--------------------------------------------------------------------------- + { + my ($self, $args) = @_; + + my @rows = split / \s+ /x, $args->{ matrix_str }; + + scalar @rows > 0 or error( 'Empty matrix' ); + + my $cols = length $rows[ 0 ]; + + $rows[ 0 ] =~ / ^ [xo]+ $ /x or error( 'Invalid character' ); + + my @matrix = [ split //, $rows[ 0 ] ]; + + for my $i (1 .. $#rows) + { + $rows[ $i ] =~ / ^ [xo]+ $ /x or error( 'Invalid character' ); + length $rows[ $i ] == $cols or error( 'Ragged array' ); + + push @matrix, [ split //, $rows[ $i ] ]; + } + + $self->{ matrix } = \@matrix; + $self->{ rows } = scalar @matrix; + $self->{ cols } = scalar @{ $matrix[ 0 ] }; + } + + #--------------------------------------------------------------------------- + sub find_largest_block_size + #--------------------------------------------------------------------------- + { + my ($self) = @_; + my $x_num = 0; + my $o_num = 0; + + for my $row (0 .. $self->rows - 1) + { + for my $col (0 .. $self->cols - 1) + { + my $elem = $self->matrix->[ $row ][ $col ]; + + if ($elem eq 'x' || $elem eq 'o') + { + my $num = ($elem eq 'x') ? $x_num++ : $o_num++; + + $self->_find_block( $elem, "$elem$num", $row, $col ); + } + } + } + + return $self->_count_blocks(); + } + + #--------------------------------------------------------------------------- + sub _find_block + #--------------------------------------------------------------------------- + { + my ($self, $elem, $marker, $row, $col ) = @_; + + $self->matrix->[ $row ][ $col ] = $marker; + + $self->_search_up ( $elem, $marker, $row, $col ); + $self->_search_left ( $elem, $marker, $row, $col ); + $self->_search_right( $elem, $marker, $row, $col ); + $self->_search_down ( $elem, $marker, $row, $col ); + } + + #--------------------------------------------------------------------------- + sub _search_up + #--------------------------------------------------------------------------- + { + my ($self, $elem, $marker, $row, $col ) = @_; + + if ($row > 0) + { + my $up_row = $row - 1; + + if ($self->matrix->[ $up_row ][ $col ] eq $elem) + { + $self->matrix->[ $up_row ][ $col ] = $marker; + + $self->_find_block( $elem, $marker, $up_row, $col ); + } + } + } + + #--------------------------------------------------------------------------- + sub _search_left + #--------------------------------------------------------------------------- + { + my ($self, $elem, $marker, $row, $col ) = @_; + + if ($col > 0) + { + my $left_col = $col - 1; + + if ($self->matrix->[ $row ][ $left_col ] eq $elem) + { + $self->matrix->[ $row ][ $left_col ] = $marker; + + $self->_find_block( $elem, $marker, $row, $left_col ); + } + } + } + + #--------------------------------------------------------------------------- + sub _search_right + #--------------------------------------------------------------------------- + { + my ($self, $elem, $marker, $row, $col ) = @_; + + if ($col < $self->cols - 1) + { + my $right_col = $col + 1; + + if ($self->matrix->[ $row ][ $right_col ] eq $elem) + { + $self->matrix->[ $row ][ $right_col ] = $marker; + + $self->_find_block( $elem, $marker, $row, $right_col ); + } + } + } + + #--------------------------------------------------------------------------- + sub _search_down + #--------------------------------------------------------------------------- + { + my ($self, $elem, $marker, $row, $col ) = @_; + + if ($row < $self->rows - 1) + { + my $down_row = $row + 1; + + if ($self->matrix->[ $down_row ][ $col ] eq $elem) + { + $self->matrix->[ $down_row ][ $col ] = $marker; + + $self->_find_block( $elem, $marker, $down_row, $col ); + } + } + } + + #--------------------------------------------------------------------------- + sub _count_blocks + #--------------------------------------------------------------------------- + { + my ($self) = @_; + my %block_counts; + + for my $row (0 .. $self->rows - 1) + { + for my $col (0 .. $self->cols - 1) + { + ++$block_counts{ $self->matrix->[ $row ][ $col ] }; + } + } + + my $max_size = max values %block_counts; + my @max_blocks; + + while (my ($key, $value) = each %block_counts) + { + push @max_blocks, $key if $value == $max_size; + } + + @max_blocks = sort { + substr( $a, 0, 1 ) cmp substr( $b, 0, 1 ) + || + substr( $a, 1 ) <=> substr( $b, 1 ) + + } @max_blocks; + + return ($max_size, \@max_blocks); + } + + #--------------------------------------------------------------------------- + sub print # Adapted from print_matrix() in ch-2.pl for Week 266 + #--------------------------------------------------------------------------- + { + my ($self, $prefix) = @_; + my $tab = ' ' x length $prefix; + my @width = (1) x scalar @{ $self->matrix->[ 0 ] }; + + for my $row (@{ $self->matrix }) + { + for my $i (0 .. $#$row) + { + my $w = length $row->[ $i ]; + + $width[ $i ] = $w if $w > $width[ $i ]; + } + } + + print "$prefix\[\n"; + + for my $row (@{ $self->matrix }) + { + my @row_str; + + for my $i (0 .. $#$row) + { + push @row_str, sprintf '%*s', $width[ $i ], $row->[ $i ]; + } + + printf "%s [%s]\n", $tab, join ', ', map { "'$_'" } @row_str; + } + + print "$tab]\n"; + } +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + my $argc = scalar @ARGV; + + if ($argc == 0) + { + run_tests(); + } + elsif ($argc == 1) + { + my $matrix = Matrix->new( $ARGV[ 0 ] ); + + $matrix->print( 'Input: $matrix = ', $matrix ); + + my ($max_size, $max_blocks) = $matrix->find_largest_block_size; + + print "Output: $max_size\n"; + + if ($VERBOSE) + { + print "\n"; + + $matrix->print( 'Blocks: ' ); + + printf "Largest block%s: %s\n", scalar @$max_blocks > 1 ? 's' : '', + join ', ', @$max_blocks; + } + } + else + { + error( "Expected 1 or 0 command-line arguments, found $argc" ); + } +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $matrix_str, $expected) = split / \| /x, $line; + + for ($test_name, $matrix_str, $expected) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my $matrix = Matrix->new( $matrix_str ); + my ($max_size) = $matrix->find_largest_block_size; + + is $max_size, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1|xxxxo xoooo xoooo xxxoo|11 +Example 2|xxxxx xoooo xxxxo xoooo|11 +Example 3|xxxoo oooxx oxxoo oooxx| 7 diff --git a/challenge-288/athanasius/raku/ch-1.raku b/challenge-288/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..9f703ba951 --- /dev/null +++ b/challenge-288/athanasius/raku/ch-1.raku @@ -0,0 +1,198 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 288 +========================= + +TASK #1 +------- +*Closest Palindrome* + +Submitted by: Mohammad Sajid Anwar + +You are given a string, $str, which is an integer. + +Write a script to find out the closest palindrome, not including itself. If +there are more than one then return the smallest. + + The closest is defined as the absolute difference minimized between two + integers. + +Example 1 + + Input: $str = "123" + Output: "121" + +Example 2 + + Input: $str = "2" + Output: "1" + + There are two closest palindrome "1" and "3". Therefore we return the smallest + "1". + +Example 3 + + Input: $str = "1400" + Output: "1441" + +Example 4 + + Input: $str = "1001" + Output: "999" + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Assumption +---------- +The input integer is unsigned (non-negative). + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. A string representing an unsigned integer is entered on the command-line. + +=end comment +#=============================================================================== + +use Test; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 288, Task #1: Closest Palindrome (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + Str:D $str #= A string representing an unsigned integer +) +#=============================================================================== +{ + $str ~~ Int:D or error( qq["$str" is not a valid integer] ); + + my Int $int = +$str; + + $int >= 0 or error( "$int is negative" ); + + print qq[Input: \$str = "$int"\n]; + + my UInt $closest-palindrome = find-closest-palindrome( $int ); + + print qq[Output: "$closest-palindrome"\n]; +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub find-closest-palindrome( UInt:D $int --> UInt:D ) +#------------------------------------------------------------------------------- +{ + return 1 if $int == 0; + + my UInt $above = $int + 1; + ++$above until is-palindrome( $above ); + + my UInt $below = $int - 1; + --$below until is-palindrome( $below ); + + my UInt $above-diff = $above - $int; + my UInt $below-diff = $int - $below; + + return ($above-diff < $below-diff) ?? $above !! $below; +} + +#------------------------------------------------------------------------------- +sub is-palindrome( UInt:D $int --> Bool:D ) +#------------------------------------------------------------------------------- +{ + my UInt @digits = $int.split( '', :skip-empty ).map: { .Int }; + + for 0 .. (@digits.end / 2).floor -> UInt $i + { + return False unless @digits[ $i ] == @digits[ @digits.end - $i ]; + } + + return True; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $str, $expected) = $line.split: / \| /; + + for $test-name, $str, $expected + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my UInt $closest-palindrome = find-closest-palindrome( $str.Int ); + + is $closest-palindrome, $expected.Int, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub error( Str:D $message ) +#------------------------------------------------------------------------------- +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + return q:to/END/; + Example 1| 123| 121 + Example 2| 2| 1 + Example 3| 1400| 1441 + Example 4| 1001| 999 + Zero | 0| 1 + One | 1| 0 + 1 Million|1000000|999999 + Odd | 12721| 12621 + END +} + +################################################################################ diff --git a/challenge-288/athanasius/raku/ch-2.raku b/challenge-288/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..49a4aff10d --- /dev/null +++ b/challenge-288/athanasius/raku/ch-2.raku @@ -0,0 +1,406 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 288 +========================= + +TASK #2 +------- +*Contiguous Block* + +Submitted by: Peter Campbell Smith + +You are given a rectangular matrix where all the cells contain either x or o. + +Write a script to determine the size of the largest contiguous block. + + A contiguous block consists of elements containing the same symbol which + share an edge (not just a corner) with other elements in the block, and + where there is a path between any two of these elements that crosses only + those shared edges. + +Example 1 + + Input: $matrix = [ + ['x', 'x', 'x', 'x', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'x', 'x', 'o', 'o'], + ] + Output: 11 + + There is a block of 9 contiguous cells containing 'x'. + There is a block of 11 contiguous cells containing 'o'. + +Example 2 + + Input: $matrix = [ + ['x', 'x', 'x', 'x', 'x'], + ['x', 'o', 'o', 'o', 'o'], + ['x', 'x', 'x', 'x', 'o'], + ['x', 'o', 'o', 'o', 'o'], + ] + Output: 11 + + There is a block of 11 contiguous cells containing 'x'. + There is a block of 9 contiguous cells containing 'o'. + +Example 3 + + Input: $matrix = [ + ['x', 'x', 'x', 'o', 'o'], + ['o', 'o', 'o', 'x', 'x'], + ['o', 'x', 'x', 'o', 'o'], + ['o', 'o', 'o', 'x', 'x'], + ] + Output: 7 + + There is a block of 7 contiguous cells containing 'o'. + There are two other 2-cell blocks of 'o'. + There are three 2-cell blocks of 'x' and one 3-cell. + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. A single string is entered on the command-line, e.g., "xxxo xooo xooo xxoo". + This string comprises whitespace-separated rows; each row contains only the + characters 'x' or 'o'. The matrix represented must be rectangular and not + empty. +3. If VERBOSE is set to True, the output is augmented with a matrix diagram + showing the different contiguous blocks found, and identifying the largest. + +=end comment +#=============================================================================== + +use Test; + +my Bool constant VERBOSE = True; + +subset Result of List where (UInt, Array[Str]); + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 288, Task #2: Contiguous Block (Raku)\n".put; +} + +#=============================================================================== +class Matrix +#=============================================================================== +{ + subset Elem of Str where * ~~ 'x' | 'o'; + subset MatrixT of Array where * ~~ Array[Array[Str]]; + + #--------------------------------------------------------------------------- + # Attributes + #--------------------------------------------------------------------------- + + has MatrixT $!matrix is built; + has UInt $!rows is built; + has UInt $!cols is built; + has Str $!matrix-str is built; + + #--------------------------------------------------------------------------- + method new( Str:D $matrix-str ) + #--------------------------------------------------------------------------- + { + return self.bless( :$matrix-str ); + } + + #--------------------------------------------------------------------------- + submethod TWEAK() + #--------------------------------------------------------------------------- + { + my Str @rows = $!matrix-str.split: / \s+ /, :skip-empty; + @rows.elems > 0 or error( 'Empty matrix' ); + my UInt $cols = @rows[ 0 ].chars; + + @rows[ 0 ] ~~ / ^ <[ x o ]>+ $ / or error( 'Invalid character' ); + + $!matrix = Array[Array[Str]].new; + + $!matrix.push: Array[Str].new: @rows[ 0 ].split: '', :skip-empty; + + for 1 .. @rows.end -> UInt $i + { + @rows[ $i ] ~~ / ^ <[ x o ]>+ $ / or error( 'Invalid character' ); + @rows[ $i ].chars == $cols or error( 'Ragged array' ); + + $!matrix.push: Array[Str].new: @rows[ $i ].split: '', :skip-empty; + } + + $!rows = $!matrix.elems; + $!cols = $!matrix[ 0 ].elems; + } + + #--------------------------------------------------------------------------- + method find-largest-block-size( --> Result:D ) + #--------------------------------------------------------------------------- + { + my UInt $x-num = 0; + my UInt $o-num = 0; + + for 0 .. $!rows - 1 -> UInt $row + { + for 0 .. $!cols - 1 -> UInt $col + { + my Str $elem = $!matrix[ $row; $col ]; + + if $elem ~~ Elem:D + { + my UInt $num = ($elem eq 'x') ?? $x-num++ !! $o-num++; + + self!find-block( $elem, "$elem$num", $row, $col ); + } + } + } + + return self!count-blocks; + } + + #--------------------------------------------------------------------------- + method !find-block( Elem:D $elem, Str:D $marker, Int:D $row, Int:D $col ) + #--------------------------------------------------------------------------- + { + $!matrix[ $row; $col ] = $marker; + + self!search-up( $elem, $marker, $row, $col ); + self!search-left( $elem, $marker, $row, $col ); + self!search-right( $elem, $marker, $row, $col ); + self!search-down( $elem, $marker, $row, $col ); + } + + #--------------------------------------------------------------------------- + method !search-up( Elem:D $elem, Str:D $marker, Int:D $row, Int:D $col ) + #--------------------------------------------------------------------------- + { + if $row > 0 + { + my Int $up-row = $row - 1; + + if $!matrix[ $up-row; $col ] eq $elem + { + $!matrix[ $up-row; $col ] = $marker; + + self!find-block( $elem, $marker, $up-row, $col ); + } + } + } + + #--------------------------------------------------------------------------- + method !search-left( Elem:D $elem, Str:D $marker, Int:D $row, Int:D $col ) + #--------------------------------------------------------------------------- + { + if $col > 0 + { + my Int $left-col = $col - 1; + + if $!matrix[ $row; $left-col ] eq $elem + { + $!matrix[ $row; $left-col ] = $marker; + + self!find-block( $elem, $marker, $row, $left-col ); + } + } + } + + #--------------------------------------------------------------------------- + method !search-right( Elem:D $elem, Str:D $marker, Int:D $row, Int:D $col ) + #--------------------------------------------------------------------------- + { + if $col < $!cols - 1 + { + my Int $right-col = $col + 1; + + if $!matrix[ $row; $right-col ] eq $elem + { + $!matrix[ $row; $right-col ] = $marker; + + self!find-block( $elem, $marker, $row, $right-col ); + } + } + } + + #--------------------------------------------------------------------------- + method !search-down( Elem:D $elem, Str:D $marker, Int:D $row, Int:D $col ) |
