diff options
| author | Myoungjin JEON <jeongoon@gmail.com> | 2020-08-02 02:12:33 +1000 |
|---|---|---|
| committer | Myoungjin JEON <jeongoon@gmail.com> | 2020-08-02 02:12:33 +1000 |
| commit | a63a9ebea520836f1783689454064ad0ced584fd (patch) | |
| tree | 70ee4c049849226fe4ce80b376c23795aeecd183 /challenge-071 | |
| parent | 3dee8e8787d5b0285bdd87968c0a5a14cacbf6af (diff) | |
| download | perlweeklychallenge-club-a63a9ebea520836f1783689454064ad0ced584fd.tar.gz perlweeklychallenge-club-a63a9ebea520836f1783689454064ad0ced584fd.tar.bz2 perlweeklychallenge-club-a63a9ebea520836f1783689454064ad0ced584fd.zip | |
challenge #71 by Jeon
Diffstat (limited to 'challenge-071')
| -rw-r--r-- | challenge-071/jeongoon/perl/ch-1.pl | 153 | ||||
| -rw-r--r-- | challenge-071/jeongoon/perl/ch-2.pl | 322 | ||||
| -rw-r--r-- | challenge-071/jeongoon/raku/ch-1.raku | 67 | ||||
| -rw-r--r-- | challenge-071/jeongoon/raku/ch-2.raku | 115 |
4 files changed, 657 insertions, 0 deletions
diff --git a/challenge-071/jeongoon/perl/ch-1.pl b/challenge-071/jeongoon/perl/ch-1.pl new file mode 100644 index 0000000000..5108f945e9 --- /dev/null +++ b/challenge-071/jeongoon/perl/ch-1.pl @@ -0,0 +1,153 @@ +#!/usr/bin/env perl +# -*- Mode: cperl; cperl-indent-level:4 tab-width: 8; indent-tabs-mode: nil -*- +# -*- coding: utf-8 -*- + +use utf8; +use strict; use warnings; +use Getopt::Long qw(:config no_ignore_case gnu_compat); +use Pod::Usage; +use Term::ANSIColor; + + +BEGIN { + $::debugging = 0; + $::utf8 = 1; + $::colour = 1; + $::help = 0; + + GetOptions( 'debug' => \$::debugging, + 'utf8!' => \$::utf8, + 'color|colour!' => \$::colour, + 'N=i' => \$::N, + 'help' => \$::help, + ) or pod2usage(2); + + our $dbuff_ = ''; + our $dprint = sub ( @ ) { ++$|; print STDERR @_; }; + our $dpush = sub ( @ ) { $dbuff_ .= join "", @_; }; + + if ( $::utf8 ) { + binmode( STDERR, ':utf8' ); + binmode( STDOUT, ':utf8' ); + *IC = sub { 'β' }; *DC = sub { 'β' }; } + else { + *IC = sub { '/' }; *DC = sub { '\\' }; } + + *::dpush = $::debugging ? $dpush : sub {}; + *::dmesg = $::debugging ? + sub { $dprint->('[DBG] ',$dbuff_,@_ ); $dbuff_='';} : sub {}; + +} + +=pod + +=head1 Peak Element + +ch-1.pl [--debug] [--help] [--no-utf8] [--no-color] [N (default: 42)] +where 1 < N <= 50 + +=head1 Challenge + +You are given positive integer $N (>1). + +Write a script to create an array of size $N with random unique elements between 1 and 50. + + | I'm going to make a list and shuffle (because the list would be not very long.) + | then return @array[ 0..$N ] + +=cut + +sub make_random_array_ ( @ ) { # note: this function does not validate parameters + my %args = @_; + my $narray = $args{'number-of-array'}; + my $members =$args{'elements'}; + + my $n = scalar @$members; + + for ( 0.. $n*2 ) { # shuffle enough + my ( $l, $r ) = ( int(rand($n)), int(rand($n)) ); + @{$members}[$l, $r] = @{$members}[$r, $l]; + } + @{$members}[ 0.. $narray-1 ]; +} + +=pod + +=encoding utf8 + +In the end it should print peak elements in the array, if found. + + An array element is called peak if it is bigger than itβs neighbour. + + Example 1 + Array: [ 18, 45, 38, 25, 10, 7, 21, 6, 28, 48 ] + Peak: [ 48, 45, 21 ] + Example 2 + Array: [ 47, 11, 32, 8, 1, 9, 39, 14, 36, 23 ] + Peak: [ 47, 32, 39, 36 ] + +=cut + +sub get_peak_from_array ( @ ) { + my $n = 0; + my $l = 1; + my $pasc = 1; # previous ascend value + my @ps; + + ::dpush "visual list: "; + for (@_) { + +=pod + +=head1 My solution + + | So.. I just simply compare current number to next one. if the number increased + | previouly and will be decreased, which means current number is peak + +=cut + + my $d = ( ( $_[$n+1] || 0 ) - $_[$n++] ); # (d)elta + $d /= abs $d; # need direction only + my $asc = (0,1,0)[$d]; # d == 1 -> $asc = 0, $t == -1 -> $asc = 1; + ::dpush $pasc?IC:DC; + + # I found the bit operation is interesting + # change comparison method a little bit. + # pasc asc peak + # 0 0 no (keep decreasing) + # 1 0 yes + # 0 1 no (low peak) + # 1 1 no (keep increasing) + # not very usueful here but I hope someday it will be :-] + if ( ($pasc<<1 | $asc) == 0b10 ) { # if $pasc and not $asc; + push @ps, $_; + ::dpush " ", colored( ['yellow on_black'], $_ ), " "; + } + else { + ::dpush " $_ "; + } + $pasc = $asc; + } + ::dmesg " ", ($pasc?IC:DC), "\n"; + return @ps; +} + + +package main; + +defined $::N or + $::N = 42, warn "Use Default N: 42"; + +die "Invalid value of N($::N): must be 1 < N <= 50" + unless $::N > 1 and $::N <= 50; + +pod2usage( -exitval => 0, -verbose => 2 ) if $::help; + +my @r_array = make_random_array_( 'number-of-array' => $::N, + 'elements' => [ 1..50 ] ); +$"=", "; + +print "Array: [ @r_array ]\n"; +print "Peak: [ ".join($", get_peak_from_array @r_array)." ]"; + +exit 0; diff --git a/challenge-071/jeongoon/perl/ch-2.pl b/challenge-071/jeongoon/perl/ch-2.pl new file mode 100644 index 0000000000..d5ca392f74 --- /dev/null +++ b/challenge-071/jeongoon/perl/ch-2.pl @@ -0,0 +1,322 @@ +#!/usr/bin/env perl +# -*- Mode: cperl; cperl-indent-level:4 tab-width: 8; indent-tabs-mode: nil -*- +# -*- coding: utf-8 -*- + +use strict; use warnings; +use Getopt::Long; +use Pod::Usage; +use Term::ANSIColor; + +=pod + +=head1 Usage + +perl ch-1.pl [--debug] [--help] + +=cut + +BEGIN { + $::debugging = 0; + $::colour = 1; + my $help = 0; + + GetOptions( "debug" => \$::debugging, + 'color|colour!' => \$::colour, + "help" => \$help, + ) or pod2usage(2); + + pod2usage( -exitval => 0, -verbose => 2 ) if $help; + + our $dprint = sub( @ ) { + ++$|; + print "[DBG] ",@_; + }; + + *::dprint = $::debugging ? $dprint : sub {}; +} + +=pod + +=head1 Challenge 2 + +You are given a singly linked list and a positive integer $N (>0). + +Write a script to remove the $Nth node from the end of the linked list and +print the linked list. + +=cut + +package linked_list; +use Scalar::Util qw(blessed refaddr weaken); + +sub new { + my $class = shift; + my %args = @_; # use hash as arguments + my $elements; + ::dprint "linked_list: initializing ...\n"; + if ( exists $args{elements} ) { + if ( not ref $args{elements} eq 'ARRAY' ) { + warn "parameter elements accept only Array Ref: ignored."; + } + else { + $elements = $args{elements}; + } + + } + + my $obj = + [ + linked_list::iterator->new( '[CORE]' ) # one default iterator for internal use + ]; + my $self = bless $obj, ( blessed $class || $class ); + + if ( defined $elements ) { + for ( reverse @$elements ) { # going to use unshift method + $self->push_back( $self->[0], $_ ); + } + } + ::dprint "linked_list: created\n"; + return $self; +} + +sub DESTROY { + ::dprint "linked_list: remvoing CORE and cache.\n"; + undef $_[0]->[0]; + ::dprint "linked_list: done"; +} + +sub before_begin_ { $_[0]->[0] } +sub begin { $_[0]->[0]->next } +sub maybe_end { $_[0]->[1] } +sub end { + # using remembered end point if any + $_[0]->[1] = $_[0]->[0]->next unless defined $_[0]->maybe_end; + # update end point if needed + while ( $_[0]->[1]->next ) { + $_[0]->[1] = $_[0]->[1]->next + } + return $_[0]->[1]; +} + +sub count { + my $itr = $_[0]->begin; + + my $count = 0; + while ( defined $itr ) { + ++$count; + $itr = $itr->next; + } + $count; +} + +sub itr_class_str () { __PACKAGE__.'::iterator' } + +sub push_back ( $;$ ) { + if ( scalar @_ == 1 ) { + ::dprint "nothing to do"; + return 0; + } + + my ( $itr, $sth ) = @_[ -2, -1 ]; + my $class = blessed $itr; + + # get valid iterator to push back + if ( not defined $itr ) { + # making begin and push something + ::dprint "push_back: iterator not defined: making first node"; + return $_[0]->push_back( itr_class_str->new(), $sth ); + } + if ( $class eq __PACKAGE__ ) { # scalar @_ == 2 + ::dprint "push_back: use tail node to push $sth"; + $itr = $_[0]->end; + } + + # get valid iterator to be pushed back + $class = blessed $sth; + if ( $class and $class eq itr_class_str ) { + ::dprint "push_back: received an itr with value: ".$sth->value.$/; + ::dprint " to be pushed after iter with value: ".$itr->value.$/; + my $nxt = $itr->next; + $itr->[1] = $sth; + if ( defined $sth->next ) { + warn "push_back: trying to insert some node which already has link"; + } + else { + # XXX: not sure it is correct behaviour + $sth->[1] = $nxt; + } + return 1; + } + else { # value + ::dprint "push_back: received a value: $sth\n"; + return $_[0]->push_back( $itr, itr_class_str->new( $sth ) ); + } + die "this is a bug" if $::debugging; +} + +sub pop ( $;$ ) { + return if scalar @_ == 1; + + my $class = blessed $_[-1]; + + if ( defined $class and $class eq __PACKAGE__ ) { + # pop the end + return $_[0]->pop( $_[0]->count - 1 ); + } + if ( defined $class and $class eq itr_class_str ) { + ::dprint "find the node and pop it from the list.\n"; + my $itr; + for ( $itr = $_[0]->begin; defined $itr; $itr = $itr->next ) { + last if ( $itr->next eq $_[-1] ); + } + if ( not defined $itr ) { + warn "could not find the $_[-1] in the list: return undef"; + return undef; + } + my $bye = delete $itr->[1]; + $itr->[1] = delete $bye->[1]; + return $bye; + } + elsif ( $_[-1] =~ /^(\+|-)?[0-9]+$/ ) { + ::dprint "pop the node at index of $_[-1] from the list.\n"; + my $before; + my $count = $_[0]->count; + my $round = 0; + + if ( $_[-1] < 0 ) { + +=pod + +If $N is greater than the size of the linked list +then remove the first node of the list. + + NOTE: Please use pure linked list implementation. + Example + Given Linked List: 1 -> 2 -> 3 -> 4 -> 5 + when $N = 1 + Output: 1 -> 2 -> 3 -> 4 + when $N = 2 + Output: 1 -> 2 -> 3 -> 5 + when $N = 3 + Output: 1 -> 2 -> 4 -> 5 + when $N = 4 + Output: 1 -> 3 -> 4 -> 5 + when $N = 5 + Output: 2 -> 3 -> 4 -> 5 + when $N = 6 + Output: 2 -> 3 -> 4 -> 5 + +=cut + + my $idx = $_[-1]; + ::dprint ">> this is a task2 solution\n"; + + if ( -$idx > $count ) { + ::dprint ">>> always remove first node when index is". + " more than length of list.\n"; + + $before = $_[0]->[0]; + ::dprint ">>>> and I have shortcut:".$before->value.$/; + } + else { + ::dprint ">>> we have to find index before the node". + " which will be removed.\n"; + $round = -$idx; + ::dprint ">>>> index would be: $round\n"; + } + } + if ( not defined $before ) { + $before = $_[0]->before_begin_; + ( $before = $before->next ) while $round--; + } + my $bye = delete $before->[1]; + $before->[1] = delete $bye->[1]; + return $bye; + } + else { + warn "invalid arguemnt for poping: ".($_[-1]//'<not given>'); + return undef; + } + die "this is a bug" if $::debugging; +} + +package linked_list::iterator; +use Scalar::Util qw(blessed refaddr weaken isweak); + +sub new { + my $class = shift; + my $value = shift; + my $obj = [ $value, undef ]; + + weaken( $obj->[0] ) if refaddr( $obj->[0] ); + bless $obj, ( blessed $class || $class ); +} + +sub next () { $_[0]->[1]; } +sub value () { $_[0]->[0]; } + +sub DESTROY { + ::dprint "$_[0]: value: ".($_[0]->[0]||'<empty>')." destroyed!!!\n"; +} + + +package main; + +sub get_actual_index_to_remove_ ( $$ ) { # have no type checking + my $list = shift; + my $N = shift; + my $count = $list->count; + + return $count - $N; # -1 because index starts from 0 +} + +sub say_elements_ ( $;$ ) { + my $lst = shift; + my $index = shift; + + my $itr = $lst->begin; + my $sep = ' -> '; + return if not defined $itr; + + print $itr->value; + --$index if defined $index; + for ( my $i = 0, $itr = $itr->next; defined $itr; ++$i, $itr = $itr->next ) { + print $sep; + if ( defined $index and $index eq $i ) { + print( ( $::colour + ? colored( [ 'yellow on_black' ], $itr->value ) + : '`'.$itr->value.'\'' ) ); + } + else { + print $itr->value; + } + } + print $/; +} + +my $example = linked_list->new( elements => [ 1..5 ] ); +print "Given Linked List: "; +say_elements_( $example ); + +for ( 1..6 ) { + my $idx = get_actual_index_to_remove_ $example, $_; + print "when \$N = $_\n"; + if ( $::debugging ) { + ::dprint "Current: "; + say_elements_ $example, $idx; + } + my $clean_itr = $example->pop( -$idx ); # minus: from the end + print "Output: "; + say_elements_ $example; + + # another hidden problem if we go through the loop + ::dprint "Inserting again for next try\n"; + my $itr = $example->before_begin_; + for ( 0 .. $idx -1 ) { $itr = $itr->next; } + if ( defined $itr ) { + $example->push_back( $itr, $clean_itr ); + } + else { + $example->push_back( $clean_itr ); + } +} diff --git a/challenge-071/jeongoon/raku/ch-1.raku b/challenge-071/jeongoon/raku/ch-1.raku new file mode 100644 index 0000000000..54274d2625 --- /dev/null +++ b/challenge-071/jeongoon/raku/ch-1.raku @@ -0,0 +1,67 @@ +#!/usr/bin/env raku +# -*- Mode: Raku; indent-tabs-mode: nil; coding: utf-8 -*- +# vim: set et ts=4 sw=4: + +class RandomList { + has @.list-all is rw = 1..42; + has Int $.num-of-list is rw = 9; + + submethod BUILD ( :out-of(:@!list-all), + Int :selects(:$!num-of-list) ) { + } + + method get-random-list () { + my $size = @!list-all.elems; + + for ^$size { + my ( $lf, $ri ) = ( 0 ..^ $size ).rand.Int xx 2; + @!list-all[$lf, $ri] = @!list-all[$ri, $lf]; + } + return @!list-all[0..^ $!num-of-list]; + } +} + +class PeakNum { + has ( $.left, $.mine ,$.right ); + method lowest () { 0 } + method take () { + # XXX list-all itself contains Any type but check numerical only here. + take $!mine if $!mine > ( ($!left || self.lowest), + ($!right || self.lowest) ).all; + } +} + +# $N == 1 isn't very harmful +sub MAIN ( $N where { $N >= 1 } = 8, #= size of random numbers + Bool :$relax, #= loose strict rule in the challenge + :$max-number? where { $max-number >= $N } = 50, + ) { + + # + if $relax.not { + die "\$N must be greater than 1" unless $N > 1; + if $max-number != 50 { + warn "max number is redeclared as 50"; + $max-number = 50; + } + } + + my $random-numbers = RandomList.new: :selects($N) :out-of(1 .. 50); + my $list = $random-numbers.get-random-list; + say "Array: " ~ $list.Array.raku; + + my @peak-array = Array.new; + #if $N == 1 { + # @peak-array. + # append( PeakNum.new( :mine($list[0]) ) ); + #} + #else { + for ^$N { + @peak-array. + append( PeakNum.new( :left( try $list[$_-1] ) + :mine( $list[$_] ), + :right( try $list[$_+1] ) ) ); + } + #} + say "Peak: " ~ gather { .take for @peak-array }.Array.raku; +} diff --git a/challenge-071/jeongoon/raku/ch-2.raku b/challenge-071/jeongoon/raku/ch-2.raku new file mode 100644 index 0000000000..24a1c04e1b --- /dev/null +++ b/challenge-071/jeongoon/raku/ch-2.raku @@ -0,0 +1,115 @@ +#!/usr/bin/env raku +# -*- Mode: Raku; indent-tabs-mode: nil; coding: utf-8 -*- +# vim: set et ts=4 sw=4: + +our $D = False; +class LinkedList { ... } +class Iter { + trusts LinkedList; + has $.value is rw; + has Iter $.next; + + method is-last () { $!next.defined.not } + + method !set-next ( Iter $another ) { $!next = $another } + method !reset-next () { $!next = Nil } + method !replace-next ( Iter:D $another ) { + my $prev-one = $!next; + $!next = $another; + return $prev-one; + } +} + +class LinkedList { + has Iter $!core; + has Str $.sep = 'β'; + + method begin () returns Iter { $!core.next } + + submethod BUILD { + $!core = Iter.new( :value( 'DO NOT REMOVE' ) ); + } + + method count () { + my $count = 0; + loop ( my $itr = self.begin; defined $itr; $itr = $itr.next ) { + ++$count + } + return $count; + } + + # push back after an iterator and + # return another iterator which has moved forward + multi method push ( Any:D $that, Iter:D :$after ) { + my $itr = $that.isa( Iter ) ?? $that !! Iter.new( :value($that) ); + say "push the node has (value: {$itr.value}) after node (value: {$after.value})" if $D; + + $itr!Iter::set-next( $after!Iter::replace-next( $itr ) ); + return $itr; + } + + # push in the end of the list + multi method push ( Any:D $that ) returns Iter { + say "push in the end" if $D; + my $itr = $!core; + while $itr.next.defined { $itr = $itr.next } + + my $node = $that.isa( Iter ) ?? $that !! Iter.new( :value( $that ) ); + print " -> " if $D; + return self.push( $node, :after($itr) ); + } + + multi method push( # or unshift + Any:D $that, Int:D :$at is copy where * < self.count ) returns Iter { + # `-> Int:D needed not to be confused with + # 'multi method push ( Any:D $that )' + my $itr = $!core; + while ( $at-- ) { $itr = $itr.next } + return self.push( $that, :after($itr) ); + } + + multi method pop ( Iter:D :$after ) returns Iter { + my $go = $after.next; + if $go.defined { + $after!Iter::set-next( $go.next ); + $go!Iter::reset-next(); + } + return $go; + } + multi method pop ( Int:D :$at where * < self.count ) returns Iter { + my $itr = $!core; + for ^$at { $itr = $itr.next } + say "pop after node (value: {$itr.value})" if $D; + return self.pop( :after($itr) ); + } + + method say-values ( Str :$prompt? ) { + if $prompt.defined { + print( $prompt ); + } + my $itr = self.begin; + $itr.value.print if $itr.defined; + loop ( $itr = $itr.next ; $itr.defined ; $itr = $itr.next ) { + print( " $!sep " ~ $itr.value ); + } + say ""; + } + +}; + +sub MAIN ( Bool :debug($d) ) { + $D = $d; + my $List = LinkedList.new; + + for 1 .. 5 -> $num { $List.push( $num ) } + for 1 .. 6 -> $N { + $List.say-values( :prompt( "Given List : " ) ); + + my $I = $List.count - $N; + $I = 0 if $I < 0; # given constraints + + my $itr = $List.pop( :at($I) ); + $List.say-values( :prompt("When \$N = $N\nOutput: " ) ); + $List.push( $itr, :at($I) ); + } +} |
