RabbitFarm

2023-02-05

Into the Odd Wide Valley

The examples used here are from the weekly challenge problem statement and demonstrate the working solution.

Part 1

You are given an array of integers. Write a script to print 1 if there are THREE consecutive odds in the given array otherwise print 0.

Solution


use v5.36;
use boolean;

sub three_consecutive_odds{
    my @numbers = @_;
    my $consecutive_odds = 0;
    {
        my $x = pop @numbers;
        $consecutive_odds++   if 1 == ($x & 1);
        $consecutive_odds = 0 if 0 == ($x & 1);
        return true if 3 == $consecutive_odds;
        redo if @numbers;
    }
    return false;
}

MAIN:{
    say three_consecutive_odds(1, 5, 3, 6);
    say three_consecutive_odds(2, 6, 3, 5);
    say three_consecutive_odds(1, 2, 3, 4);
    say three_consecutive_odds(2, 3, 5, 7);
}

Sample Run


$ perl perl/ch-1.pl 
1
0
0
1

Notes

Part 2

Given a profile as a list of altitudes, return the leftmost widest valley. A valley is defined as a subarray of the profile consisting of two parts: the first part is non-increasing and the second part is non-decreasing. Either part can be empty.

Solution


use v5.36;
use boolean;
use FSA::Rules;

sub widest_valley_rules{
    my @altitudes = @_;
    my @downslope;
    my @upslope;
    my $fsa = FSA::Rules->new(
        move => {
            do => sub{  my $state = shift;
                        $state->machine->{altitude}  = [] if(!$state->machine->{altitude});
                        $state->machine->{plateau}   = [] if(!$state->machine->{plateau});
                        $state->machine->{downslope} = [] if(!$state->machine->{downslope});
                        $state->machine->{upslope}   = [] if(!$state->machine->{upslope});
                        my $previous_altitudes = $state->machine->{altitude};
                        my $current_altitude = shift @altitudes;
                        push @{$previous_altitudes}, $current_altitude
            },
            rules => [ done      => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          !defined($previous_altitudes->[@{$previous_altitudes} - 1]) 
                       },
                       move      => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          @{$previous_altitudes} ==  1; 
                       },
                       plateau   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if(@{$previous_altitudes} == 2){
                                              if($previous_altitudes->[@{$previous_altitudes} - 1] == $previous_altitudes->[@{$previous_altitudes} - 2]){
                                                  push @{$state->machine->{plateau}}, $previous_altitudes->[@{$previous_altitudes} - 2], $previous_altitudes->[@{$previous_altitudes} - 1];
                                              }
                                          }
                       },
                       plateau   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if(@{$previous_altitudes} > 2){
                                              if($previous_altitudes->[@{$previous_altitudes} - 1] == $previous_altitudes->[@{$previous_altitudes} - 2]){
                                                  push @{$state->machine->{plateau}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                              }
                                          }
                       },
                       downslope => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if(@{$previous_altitudes} == 2){
                                              if($previous_altitudes->[@{$previous_altitudes} - 1] < $previous_altitudes->[@{$previous_altitudes} - 2]){
                                                  push @{$state->machine->{downslope}}, $previous_altitudes->[@{$previous_altitudes} - 2], $previous_altitudes->[@{$previous_altitudes} - 1];
                                              }
                                          }
                       },
                       downslope => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if(@{$previous_altitudes} > 2){
                                              if($previous_altitudes->[@{$previous_altitudes} - 1] < $previous_altitudes->[@{$previous_altitudes} - 2]){
                                                  push @{$state->machine->{downslope}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                              }else{false}
                                          } 
                       },
                       upslope => sub{  my $state = shift; 
                                        my $previous_altitudes = $state->machine->{altitude}; 
                                        if(@{$previous_altitudes} == 2){
                                           if($previous_altitudes->[@{$previous_altitudes} - 1] > $previous_altitudes->[@{$previous_altitudes} - 2]){
                                               push @{$state->machine->{upslope}}, $previous_altitudes->[@{$previous_altitudes} - 2], $previous_altitudes->[@{$previous_altitudes} - 1];
                                           }
                                        } 
                       },
                       upslope => sub{  my $state = shift; 
                                        my $previous_altitudes = $state->machine->{altitude}; 
                                        if(@{$previous_altitudes} > 2){
                                           if($previous_altitudes->[@{$previous_altitudes} - 1] > $previous_altitudes->[@{$previous_altitudes} - 2]){
                                               push @{$state->machine->{upslope}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                           }
                                        } 
                       },
            ],
        },
        plateau => {             
            do => sub{  my $state = shift;
                        my $previous_altitudes = $state->machine->{altitude}; 
                        my $current_altitude = shift @altitudes; 
                        push @{$previous_altitudes}, $current_altitude;
            },
            rules => [ done      => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          !defined($previous_altitudes->[@{$previous_altitudes} - 1]) 
                       },  
                       plateau   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] == $previous_altitudes->[@{$previous_altitudes} - 2]){
                                               push @{$state->machine->{plateau}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                          }
                       },       
                       downslope => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] < $previous_altitudes->[@{$previous_altitudes} - 2]){
                                              push @{$state->machine->{downslope}}, @{$state->machine->{plateau}};
                                              push @{$state->machine->{downslope}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                              $state->machine->{plateau} = [];
                                          }
                       },
                       upslope   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] > $previous_altitudes->[@{$previous_altitudes} - 2]){
                                              push @{$state->machine->{upslope}}, @{$state->machine->{plateau}};
                                              push @{$state->machine->{upslope}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                              $state->machine->{plateau} = [];
                                          }
                       }        
            ], 
        },
        downslope => {
            do => sub{  my $state = shift;
                        my $previous_altitudes = $state->machine->{altitude}; 
                        my $current_altitude = shift @altitudes;
                        push @{$previous_altitudes}, $current_altitude;
            },
            rules => [ done      => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          !defined($previous_altitudes->[@{$previous_altitudes} - 1]) 
                       },   
                       plateau   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] == $previous_altitudes->[@{$previous_altitudes} - 2]){
                                               push @{$state->machine->{plateau}}, $previous_altitudes->[@{$previous_altitudes} - 2], $previous_altitudes->[@{$previous_altitudes} - 1];
                                               #pop @{$state->machine->{downslope}};true;
                                          }
                       },      
                       downslope => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] < $previous_altitudes->[@{$previous_altitudes} - 2]){
                                              push @{$state->machine->{downslope}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                          } 
                                    },
                       upslope   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] > $previous_altitudes->[@{$previous_altitudes} - 2]){
                                               $state->machine->{upslope} = [];
                                               push @{$state->machine->{upslope}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                          } 
                                    },      
            ], 
        },
        upslope => {             
            do => sub{  my $state = shift;
                        my $previous_altitudes = $state->machine->{altitude}; 
                        my $current_altitude = shift @altitudes;
                        push @{$previous_altitudes}, $current_altitude; 
            },
            rules => [ done      => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          !defined($previous_altitudes->[@{$previous_altitudes} - 1]) 
                       },   
                       done      => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          $previous_altitudes->[@{$previous_altitudes} - 1] < $previous_altitudes->[@{$previous_altitudes} - 2];
                       }, 
                       plateau   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] == $previous_altitudes->[@{$previous_altitudes} - 2]){
                                               push @{$state->machine->{plateau}}, $previous_altitudes->[@{$previous_altitudes} - 2], $previous_altitudes->[@{$previous_altitudes} - 1];
                                          }
                       },   
                       upslope   => sub{  my $state = shift; 
                                          my $previous_altitudes = $state->machine->{altitude}; 
                                          if($previous_altitudes->[@{$previous_altitudes} - 1] > $previous_altitudes->[@{$previous_altitudes} - 2]){
                                               push @{$state->machine->{upslope}}, $previous_altitudes->[@{$previous_altitudes} - 1];
                                          }
                       }        
            ], 
        },
        done => { 
            do => sub { my $state = shift; 
                        say q/Valley: / . join(q/, /,  @{$state->machine->{downslope}}, @{$state->machine->{upslope}});
                  } 
        },
    );
    return $fsa;
}

sub widest_valley{
    my $rules = widest_valley_rules(@_);
    $rules->start;
    $rules->switch until $rules->at(q/done/);
    my $graph_viz = $rules->graph();
}

MAIN:{
    widest_valley 1, 5, 5, 2, 8;
    widest_valley 2, 6, 8, 5;
    widest_valley 2, 1, 2, 1, 3;
}

Sample Run


$ perl perl/ch-2.pl 
Valley: 5, 5, 2, 8
Valley: 2, 6, 8
Valley: 2, 1, 2

Notes

References

Challenge 202

posted at: 18:39 by: Adam Russell | path: /perl | permanent link to this entry