aboutsummaryrefslogtreecommitdiff
path: root/challenge-079/daniel-mantovani/perl/ch-2.pl
blob: 65843842d0b73ac5dd6b0c18a3c206c37be57daf (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
use strict;
use warnings;
use v5.20;

# get input array from command line

my @N = @ARGV;

die "usage: perl $0 <space separate numbers (at least 3)>" unless @N > 2;

# check that all  numbers are positive, and find max value

my $max = -1;
for my $n (@N) {
  die "$n is not a proper positive number" unless $n && $n =~ /^\d+$/;
  $max = $n if $n > $max;
}

# we need to take care of the amount of decimal places needed
# form $max, so the histogram can look ok

my $places = length $max;

# so the format to print numbers should be:

my $dfmt = "\%${places}d";

my $acc_water = 0;

for my $r (reverse 1 .. $max) {

  # construct horizontal row, starting from $max
  my $line = join('', map { $_ >= $r ? '#' : ' ' } @N);

  # we need to identify in this particular line how many units
  # of rain water we can trap. We will replace with a "W" every
  # one of those units.
  #
  # We search for the pattern #< n spaces>#, and as this will
  # allow to trap n units, we will replace the spaces with the
  # letter "W"

  # Note that after replacing one group, we should start over the
  # same line. We cannot continue looking because the last caracter
  # matched ('#') may be necesary for the next match. So we cannot
  # use a /g to repeat the search, we need to start over the
  # matching, but with the spaces changed to "W" so we don't get
  # the same match but the following one, if any.

  # For the regex, we use substitution (s///) and we calculate
  # the replacement with "W" x length(spaces captured), and leave
  # the '#'s in place. /e means we are evaluating the second
  # argument, instead of taking it literally
  #
  while ($line =~ s/#(\s+)#/'#'. 'W' x length($1) . '#'/e) { }

# units this row can trap is the amount of "W"s we have on it
# feel free to change the transliteration operator to tr/W/W/
# to keep an indication of the allocated water units
  $acc_water += $line =~ tr/W/ /;

  # we will add separating spaces between symbols, note we do that after any
  # calculation
  $line = ' ' . join(' ', split('', $line));
  say sprintf($dfmt, $r) . $line;
}

# closing line
say " " x ($places - 1) . '_' . ' _' x @N;

# now print the base rows of the histogram

for my $i (0 .. $places - 1) {
  my $line = join(' ', map { substr(sprintf($dfmt, $_), $i, 1) } @N);
  say " " x ($places + 1) . $line;
}

say "Trapped water: $acc_water";