aboutsummaryrefslogtreecommitdiff
path: root/challenge-140/alexander-pankoff/perl/ch-2.pl
blob: 5b663dae9165c37686e99cade3350e7f1bc8d38a (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
use strict;
use warnings;
use feature qw'say signatures';
no warnings 'experimental::signatures';

use constant DEBUG => $ENV{DEBUG} // 0;

run() unless caller();

sub run() {
    my $i = prompt_for_integer('i');
    my $j = prompt_for_integer('j');
    my $k = prompt_for_integer('k');

    my $max = $i * $j;

    if ( $k > $max ) {
        die "Index 'k' ($k) is larger than the table. Max: $max\n";
    }

    my $matrix        = multiplication_matrix( $i, $j );
    my @sorted_matrix = sort_multiplication_matrix($matrix);
    my $res           = $sorted_matrix[ $k - 1 ];

    if (DEBUG) {
        say "Since the multiplication of $i x $j is as below:";

        say render_matrix($matrix);
        say "The sorted multiplication table:";
        say join( ' ', @sorted_matrix );

        say "Now the " . to_ordinal($k) . " element in the table is '$res'";

    }

    say $res;

}

sub multiplication_matrix ( $i, $j ) {
    [
        map {
            my $row = $_;
            [
                map {
                    my $col = $_;
                    $col * $row;

                } ( 1 .. $j )
            ];
        } ( 1 .. $i )
    ];
}

sub sort_multiplication_matrix($matrix) {
    sort { $a <=> $b } map { @$_ } @$matrix;
}

sub render_matrix($matrix) {
    my $max        = $matrix->[-1][-1];
    my $width      = length $max;
    my $format_str = "%$width" . 'd';

    join(
        "\n",
        map {
            join( " ", map { sprintf( $format_str, $_ ) } @$_ )
        } @$matrix
    );
}

sub to_ordinal($n) {
    return ( $n == 1 ) ? "1st" : $n == 2 ? "2nd" : $n == 3 ? "3rd" : $n . 'th';
}

sub prompt_for_integer($name) {
    say "Enter integer number $name greater or equal to 1.";
    chomp( my $number = <STDIN> );

    if ( $number !~ m/^\d+$/ || $number < 1 ) {
        say "Invalid integer.";
        return prompt_for_integer($name);
    }

    return $number;
}