aboutsummaryrefslogtreecommitdiff
path: root/challenge-200/bob-lied/perl/ch-1.pl
blob: dfd881146d757b5274a32d3ca03602a4eb9c6b45 (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
#!/usr/bin/env perl
# vim:set ts=4 sw=4 sts=4 et ai wm=0 nu:
#=============================================================================
# ch-1.pl Perl Weekly Challenge Week 200 Task 1 Arithmetic Slice
#=============================================================================
# Copyright (c) 2023, Bob Lied
#=============================================================================
# You are given an array of integers.
# Write a script to find out all Arithmetic Slices for the given array of
# integers.  An integer array is called arithmetic if it has at least 3
# elements and the differences between any three consecutive elements are the same.
#
# Example 1 Input: @array = (1,2,3,4) Output: (1,2,3), (2,3,4), (1,2,3,4)
# Example 2 Input: @array = (2) Output: () as no slice found.
#
# Example 1 implies that we should get every sub-slice of length at least 3
# and that output order should have shorter sequences first
#=============================================================================

use v5.36;

use List::Util qw/all/;

use Getopt::Long;
my $Verbose = 0;
my $DoTest  = 0;

use constant MINLENGTH => 3;

GetOptions("test" => \$DoTest, "verbose" => \$Verbose);
exit(!runTest()) if $DoTest;

die "All args should be numeric" unless all { $_ =~ m/-?\d+/ } @ARGV;

my $answer = aslice(@ARGV); # Should validate all numbers
say join(", ", map { "(". join(",", $_->@*) .")" } $answer->@*);

sub aslice(@list)
{
    my @result = ();
    while ( @list >= MINLENGTH )
    {
        my $diff = $list[1] - $list[0];

        for ( my $i = 2; $i < @list && $list[$i] - $list[$i-1] == $diff ; $i++ )
        {
            # Push every sub-slice that is at least MINLENGTH long
            push @result, [ @list[0..$i] ] if $i >= (MINLENGTH -1 );
        }
        shift @list;
    }
    return [ sort { scalar(@$a) <=> scalar(@$b) } @result ];
}

sub runTest
{
    use Test2::V0;

    is( aslice( 1,2,3,4 ), [ [1,2,3], [2,3,4], [1,2,3,4] ],  "Example 1");
    is( aslice( 2       ), [ ],                              "Example 2");
    is( aslice( 1,2,4,6,9,15,20,25,30,37 ),
        [ [2,4,6], [15,20,25], [20,25,30], [15,20,25,30] ],  "Bigger list, more diffs");
    is( aslice( 2,3,5,8,13,21 ), [],                         "No runs of 3");
    is( aslice( 3,6,4,7,10 ), [[4,7,10]],                    "Non-monotonic");
    is( aslice( 9,3,1,-1 ), [ [3,1,-1] ],                    "Negative difference");

    done_testing;
}