aboutsummaryrefslogtreecommitdiff
path: root/challenge-077/alexander-pankoff/perl/ch-2.pl
blob: f2a43994cc8c7eafa3828445ed22ccbc6adadf3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env perl
use v5.20;
use utf8;
use strict;
use warnings;
use autodie;
use feature qw(say signatures);
no warnings 'experimental::signatures';

use List::Util qw(
  all
  any
  max
  min
);

# You are given m x n character matrix consists of O and X only.
#
# Write a script to count the total number of X surrounded by O only. Print 0 if none found.

my ($file) = @ARGV;

my $fh;
if ($file) {
    open( $fh, '<', $file );
}
else {
    $fh = *STDIN;
}

my $matrix      = parse_input($fh);
my @lonely_xses = lonely_xses($matrix);

say scalar @lonely_xses;
if ( $ENV{DEBUG} ) {
    say "Lonely X found at Row "
      . ( $_->[0] + 1 ) . ' Col '
      . ( $_->[1] + 1 ) . '.'
      for @lonely_xses;
}

exit 0;

sub lonely_xses($matrix) {
    return grep {
        all { $matrix->[ $_->[0] ][ $_->[1] ] eq 'O' } neighbors( $matrix, $_ );
    } x_positions($matrix);

}

sub x_positions($matrix) {
    return
      grep { $matrix->[ $_->[0] ][ $_->[1] ] eq 'X' }
      combinations( [ 0 .. $#{$matrix} ], [ 0 .. $#{ $matrix->[0] } ] );
}

sub neighbors ( $matrix, $pos ) {
    my ( $row, $col ) = @$pos;
    my @neighbor_rows =
      ( max( 0, $row - 1 ) .. min( $row + 1, $#{$matrix} ) );
    my @neighbor_cols =
      ( max( 0, $col - 1 ) .. min( $col + 1, $#{ $matrix->[0] } ) );

    grep { $_->[0] != $row || $_->[1] != $col }
      combinations( \@neighbor_rows, \@neighbor_cols );
}

sub combinations ( $a, $b ) {
    map {
        my $x = $_;
        map { [ $x, $_ ] } @$b;
    } @$a;
}

sub parse_input($fh) {
    chomp( my @lines = <$fh> );
    my $length;
    my @rows = map {
        my $line = $_;
        return () if $line !~ m/\S/;
        $line =~ m/^\s*\[\s*(.*?)\s*\]\s*$/;
        die "cannot parse $line" unless $1;
        my @os_and_xses = split( /\s+/, $1 );
        die "invalid input in $line" if any { $_ ne 'O' && $_ ne 'X' } @os_and_xses;
        $length //= @os_and_xses;
        die "column count not uniform" unless @os_and_xses == $length;
        \@os_and_xses;
    } @lines;

    return \@rows;
}