diff options
| author | Jan Krňávek <Jan.Krnavek@gmail.com> | 2020-10-18 13:13:27 +0200 |
|---|---|---|
| committer | Jan Krňávek <Jan.Krnavek@gmail.com> | 2020-10-18 13:13:27 +0200 |
| commit | f5f5530b5c5e9e70a3059a811f85d03450b5f793 (patch) | |
| tree | 06c23b708c461be025b825caab54e7798603389a /challenge-082 | |
| parent | c2d5208ded891b4b9a21753021d96bdde0f90e6b (diff) | |
| parent | e8d83a10c2044eba1be500684d2caa4577400c85 (diff) | |
| download | perlweeklychallenge-club-f5f5530b5c5e9e70a3059a811f85d03450b5f793.tar.gz perlweeklychallenge-club-f5f5530b5c5e9e70a3059a811f85d03450b5f793.tar.bz2 perlweeklychallenge-club-f5f5530b5c5e9e70a3059a811f85d03450b5f793.zip | |
Merge remote-tracking branch 'upstream/master' into challenge-week-082
Diffstat (limited to 'challenge-082')
30 files changed, 1328 insertions, 63 deletions
diff --git a/challenge-082/abigail/blog.txt b/challenge-082/abigail/blog.txt new file mode 100644 index 0000000000..55b2db8670 --- /dev/null +++ b/challenge-082/abigail/blog.txt @@ -0,0 +1 @@ +https://wp.me/pcsEjt-1t diff --git a/challenge-082/abigail/blog1.txt b/challenge-082/abigail/blog1.txt new file mode 100644 index 0000000000..5a9e7458c3 --- /dev/null +++ b/challenge-082/abigail/blog1.txt @@ -0,0 +1 @@ +https://wp.me/pcsEjt-K diff --git a/challenge-082/abigail/perl/ch-2.pl b/challenge-082/abigail/perl/ch-2.pl index 8a176e1e79..821b05b26e 100644 --- a/challenge-082/abigail/perl/ch-2.pl +++ b/challenge-082/abigail/perl/ch-2.pl @@ -23,41 +23,56 @@ chomp (my $A = <>); chomp (my $B = <>); chomp (my $C = <>); +# +# $A, $B, $C are arrays, containing the single characters of +# the input strings. $ai, $bi, $ci are indices into the arrays +# (and can be seen as pointers into the strings). +# +# Invariants: - $ai + $bi == $ci +# - @$C [0 .. $ci - 1] is an interleaving of +# @$A [0 .. $ai - 1] and @$B [0 .. $bi - 1] +# sub is_interleaved; -sub is_interleaved ($A, $B, $C) { - # - # If $A or $B is empty, the other should equal $C. - # This also takes care of the situation where all strings - # are empty (which means, they are interleaved). - # - return $A eq $C if !length $B; - return $B eq $C if !length $A; - - # - # The length of $C must equal the length of $A plus the - # length of $B, else $C cannot be an interleaving of $A and $B. - # - return unless length ($A) + length ($B) == length ($C); - - # - # Now, let $A = a . A', $B = b . B', $C = c . C', where - # a, b, and c are the first characters of the strings - # $A, $B, $C, and A', B', C' the rest of the strings. - # $C is an interleaving of $A and $B if one of the following - # statements is true: - # * a eq c, and C' is an interleaving of A' and $B. - # * b eq c, and C' is an interleaving of $A and B'. - # - # Note that at this point, none of the strings $A, $B or $C are empty. - # - my ($a, $A_prime) = $A =~ /^(.)(.*)$/; - my ($b, $B_prime) = $B =~ /^(.)(.*)$/; - my ($c, $C_prime) = $C =~ /^(.)(.*)$/; - return $a eq $c && is_interleaved ($A_prime, $B, $C_prime) || - $b eq $c && is_interleaved ($A, $B_prime, $C_prime); +sub is_interleaved ($A, $B, $C, $ai = 0, $bi = 0, $ci = 0) { + state $cache; + local $" = ""; + $$cache [$ai] [$bi] //= do { + # + # If we have reached the end of either $A or $B, + # what is remaining in the other string, must + # match the unmatched part in $C. + # + return "@$A[$ai..$#$A]" eq "@$C[$ci..$#$C]" if $bi == @$B; + return "@$B[$bi..$#$B]" eq "@$C[$ci..$#$C]" if $ai == @$A; + + # + # Now we can recurse; if the first character of unmatched + # part of C matches the first character of the unmatched + # part of either A or B, we match the first character of C + # and the first character of either A or B, and recurse. + # If the first character of the unmatched part of C matches + # the first character of unmatched parts of both A and B, + # we first recurse first by matching against A, and if this + # doesn't provide a match, we recurse by matching against B. + # + + return $$A [$ai] eq $$C [$ci] && + is_interleaved ($A, $B, $C, $ai + 1, $bi, $ci + 1) || + $$B [$bi] eq $$C [$ci] && + is_interleaved ($A, $B, $C, $ai, $bi + 1, $ci + 1); + } } -say is_interleaved ($A, $B, $C) ? 1 : 0; +# +# Check lengths; if the length of C isn't equal to the length of A +# plus the length of B, we cannot have a match. If the lengths check +# out, recursively check whether the strings are interleafed. +# + +say length ($A) + length ($B) == length ($C) && + is_interleaved ([split // => $A], + [split // => $B], + [split // => $C]) ? 1 : 0; __END__ diff --git a/challenge-082/colin-crain/blog.txt b/challenge-082/colin-crain/blog.txt new file mode 100644 index 0000000000..ac8be5d356 --- /dev/null +++ b/challenge-082/colin-crain/blog.txt @@ -0,0 +1 @@ +https://colincrain.wordpress.com/2020/10/16/factor-i-hardly-knew-ye-interwoven-aphorisms-ftw/ diff --git a/challenge-082/e-choroba/perl5/ch-1.pl b/challenge-082/e-choroba/perl5/ch-1.pl index bac0ff5500..aeea793065 100755 --- a/challenge-082/e-choroba/perl5/ch-1.pl +++ b/challenge-082/e-choroba/perl5/ch-1.pl @@ -5,12 +5,14 @@ use strict; sub common_factors { my ($m, $n) = @_; ($m, $n) = ($n, $m) if $n < $m; - my @r; - for my $i (1 .. $m) { - push @r, $i if 0 == $m % $i - && 0 == $n % $i; + my (@r, @rev_r); + for my $i (1 .. sqrt $m) { + if (0 == $m % $i) { + push @r, $i if 0 == $n % $i; + unshift @rev_r, $m / $i if 0 == $n % ($m / $i); + } } - return \@r + return [@r, @rev_r] } use Test::More; diff --git a/challenge-082/jeongoon/elm/src/Ch1.elm b/challenge-082/jeongoon/elm/src/Ch1.elm new file mode 100644 index 0000000000..84b6dfdf0f --- /dev/null +++ b/challenge-082/jeongoon/elm/src/Ch1.elm @@ -0,0 +1,39 @@ +module Ch1 exposing ( getCommonFactors ) + +import String as S +import List as L +import Maybe as Mb + +getCommonFactors : Int -> Int -> Result String (List Int) +getCommonFactors m n = + if L.all (\x -> x < 0 ) [m, n] + then Err "" -- probably initial state or equivalent to. + else if L.any(\x -> x < 1) [m, n] + then Err "Please input all the strings !!!" + else + case commonFactors [m, n] of + [] -> Err "invalid input" + ls -> Ok ls + +commonFactors : List Int -> List Int +commonFactors ils = + case ils of + [] -> [] + ls -> + let l = L.minimum ls + g = L.maximum ls in + case Mb.map2 (\a b -> a == b) l g of + Nothing -> [] + Just same -> + case l of + Nothing -> [] -- impossible but have to + Just jl -> + if same then + -- note: modBy has opposite order of arguments + -- when compared to most of other language + L.filter (\dv -> modBy dv jl ==0) (L.range 1 jl) + else + L.filter (\dv -> + L.all (\i -> + modBy dv i == 0) ls) + (L.range 1 jl) diff --git a/challenge-082/jeongoon/elm/src/Ch2.elm b/challenge-082/jeongoon/elm/src/Ch2.elm index 85d1cb2de3..5d2f7d7422 100644 --- a/challenge-082/jeongoon/elm/src/Ch2.elm +++ b/challenge-082/jeongoon/elm/src/Ch2.elm @@ -1,7 +1,6 @@ -module Ch2 exposing ( .. {- - checkInterleavedString +module Ch2 exposing ( checkInterleavedString , allPossiblePartitions - , WhichPart-} ) + , WhichPart ) import String as S import List as L diff --git a/challenge-082/jeongoon/elm/src/Main.elm b/challenge-082/jeongoon/elm/src/Main.elm index 6d1863fcb1..a128fc6e08 100644 --- a/challenge-082/jeongoon/elm/src/Main.elm +++ b/challenge-082/jeongoon/elm/src/Main.elm @@ -1,6 +1,7 @@ {- Tested with: elm make src/Main.elm # and access elm/index.html in a web browser(firefox in my case) +# which shows Task1 and Task2 altogether -} module Main exposing (..) @@ -14,6 +15,7 @@ import String as S import List as L -- Solutions ... +import Ch1 exposing (..) import Ch2 exposing (..) -- Main @@ -24,28 +26,44 @@ main = -- Model type alias Model = - { ch2StringA : String + { ch1IntM : Int + , ch1IntN : Int + , ch1Result : Result String (List Int) + , ch2StringA : String , ch2StringB : String , ch2StringC : String , ch2Result : Result String (List (List String)) } init : Model -init = Model "" "" "" (Err "") +init = Model 0 0 (Err "") "" "" "" (Err "") -- Update type Task = Task1 | Task2 -type Msg = {-CommonFactors String | -} - InterleavedStringFirst String +type Msg = CommonFactorsM String + | CommonFactorsN String + | InterleavedStringFirst String | InterleavedStringSecond String | InterleavedStringInterleaved String update : Msg -> Model -> Model update msg m = - case msg of - InterleavedStringFirst nv -> -- new value + case msg of -- nv: new value + CommonFactorsM nv -> + case S.toInt nv of + Nothing -> { m | ch1IntM = 0 } + Just ni -> + let res = Ch1.getCommonFactors ni m.ch1IntN + in { m | ch1IntM = ni, ch1Result = res } + CommonFactorsN nv -> + case S.toInt nv of + Nothing -> { m | ch1IntN = 0 } + Just ni -> + let res = Ch1.getCommonFactors m.ch1IntM ni + in { m | ch1IntN = ni, ch1Result = res } + InterleavedStringFirst nv -> let res = Ch2.checkInterleavedString nv m.ch2StringB m.ch2StringC in { m | ch2StringA = nv, ch2Result = res } InterleavedStringSecond nv -> @@ -59,7 +77,11 @@ update msg m = view : Model -> Html Msg view m = div [ style "padding" "20px", style "width" "90%" ] - [ h1 [] [ text "Task2: Interleave String" ] + [ h1 [] [ text "Task1: Common Factors" ] + , viewInputInt "text" "$M" m.ch1IntM CommonFactorsM + , viewInputInt "text" "$N" m.ch1IntN CommonFactorsN + , displayAnswerCh1 m.ch1Result + , h1 [] [ text "Task2: Interleave String" ] , viewInput "text" "String A" m.ch2StringA InterleavedStringFirst , viewInput "text" "String B" @@ -69,31 +91,52 @@ view m = , displayAnswerCh2 m.ch2StringC m.ch2Result ] +viewInputInt : String -> String -> Int -> (String -> msg) -> Html msg +viewInputInt t p i toMsg = + viewInput t p (if i < 0 then "" + else S.fromInt i ) toMsg + viewInput : String -> String -> String -> (String -> msg) -> Html msg viewInput t p v toMsg = div [ style "display" "inline-block" ] [ input [ size 150, type_ t, placeholder p, value v, onInput toMsg ] []] +displayAnswerCh1 : Result String (List Int) -> Html msg +displayAnswerCh1 result = + displayAnswer "Result" + (case result of + Ok ints -> + Ok ("(" ++ (S.join "," + (L.map S.fromInt ints)) ++ ")") + Err e -> Err e) + displayAnswerCh2 : String -> Result String (List (List String)) -> Html msg displayAnswerCh2 stringC result = displayAnswer "Result: " (case result of Ok listOfStringList -> - Ok ("Interleaved as `" ++ stringC ++ "' can be divided into\n" - ++ (S.join " or " + Ok ("1 (Interleaved) as `" ++ stringC ++ "' can be divided into\n" + ++ (S.join "\n" (L.map (\sl -> "[" ++ (S.join ", " sl) ++ "]" ) listOfStringList ))) Err e -> Err e) +viewReadOnlyTextArea : String -> String -> Html msg +viewReadOnlyTextArea color str = + textarea [ readonly True, style "color" color + , rows 15, cols 150, value str ] [] + displayAnswer : String -> Result String String -> Html msg displayAnswer entryString result = case result of - Ok str -> div [ style "color" "green" ] - [ text (entryString ++ str) ] + Ok msg -> div [] + [ viewReadOnlyTextArea "green" msg ] Err e -> if e == "" - then div [ style "color" "blue" ] - [ text (entryString ++ "please input all the entries") ] - else div [ style "color" "red" ] [ text e ] + then div [] + [ viewReadOnlyTextArea "blue" + (entryString ++ "please input all the entries") ] + else div [] + [ viewReadOnlyTextArea "red" e ] diff --git a/challenge-082/jeongoon/go/ch-1.go b/challenge-082/jeongoon/go/ch-1.go new file mode 100644 index 0000000000..1205ad51df --- /dev/null +++ b/challenge-082/jeongoon/go/ch-1.go @@ -0,0 +1,112 @@ +/* + * test with : go run ch-1.go 12 8 + * Ref: https://www.admfactory.com/convert-string-to-int-golang/ + * https://stackoverflow.com/questions/13247644/tostring-function-in-go + */ + +/* Comment: + * I cannot see why go is popular... T.T + */ + +package main + +import ( + "os" + "fmt" + "strings" + "strconv" +) + +func usage() { + fmt.Println( "Usage: go run ch-1.go <natural num> <natural num>" ) +} + + +type MaybeNat string + +func (str MaybeNat) Nat() Nat { + n, err := strconv.Atoi(string(str)) + if err == nil { + return(Nat(n)) + } else { + return(Nat(0)) + } +} + +func (str MaybeNat) isNatural() bool { + return(str.Nat() > 0) +} + +type Nat int +func (n Nat) String() string { + return fmt.Sprintf("%d", n) +} + +func gcd(m int, n int) int { // a not bad gcd implementation + var sm, bg int + + if m == n { + return(m) + } else if m < n { + sm, bg = m, n + } else { + sm, bg = n, m + } + + if bg % sm == 0 { + return(sm) + } + + for i := sm-1; i > 0; i-- { + if bg % i == 0 && sm % i == 0 { + return(i) + } + } + // cannot reach here but have to mention + return(1) +} + +func commonDivisors (a int, b int) []int { + var result []int + gcd := gcd(a,b) + + for i := 1; i <= gcd; i++ { + if gcd % i == 0 { + result = append(result, i); + } + } + return result +} + +func main() { + if len(os.Args[1:]) != 2 { + usage(); + os.Exit(1); + } + + var N []Nat + all_good := true + + for _, str := range os.Args[1:3] { + if MaybeNat(str).isNatural() { + N = append(N, MaybeNat(str).Nat()) + } else { + all_good = false + break + } + } + + if ! all_good { + usage(); + os.Exit(2); + } + + cvs := commonDivisors(int(N[0]), int(N[1])) + + var S []string + for _, n := range(cvs) { + S = append(S, Nat(n).String()) + } + + fmt.Println( "(" + strings.Join(S, ", ") + ")" ) +} diff --git a/challenge-082/jeongoon/go/ch-2.go b/challenge-082/jeongoon/go/ch-2.go new file mode 100644 index 0000000000..10b66cf142 --- /dev/null +++ b/challenge-082/jeongoon/go/ch-2.go @@ -0,0 +1,99 @@ +/* + * note: this is different approach when compared to my other solutions + * + * checking just interleaving or not (non-recursive version) + * + * Tested with: + + * go run ch-2.go ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCABCDDEFGHIJEFKLGHIJKLMNMNOOPPQRQRSTUVSTWXYUVWXYZZ # -> 1 + * go run ch-2.go XY XX XYXX # -> 1 + * go run ch-2.go YX X XXY # -> 0 + */ + +package main + +import ( + "os" + "fmt" +) + +func isInterleaving (A string, B string, C string) bool { + Alen, Blen, Clen := len(A), len(B), len(C) + if Alen + Blen != Clen { + return false + } + + Apin, Bpin := -1, -1 + checkpingPlanB := false + + for Ai, Bi, Ci := 0, 0, 0 ;; Ci = Ai + Bi { + if checkpingPlanB { + if Bpin > 0 { + // note: it was A[Ai] == B[Bi] == C[Ci] + // and tried A already. + Bi = Bpin + 1 + Ai = Apin + Apin, Bpin = -1, -1 + checkpingPlanB = false + } else { + // there is no plan B ... + return false + } + continue + } else { + if Ci == Clen { + return true + } + if Ai == Alen { + if B[Bi:] == C[Ci:] { + return true + } else { + checkpingPlanB = true + continue + } + } else if Bi == Blen { + return A[Ai:] == C[Ci:] + } + + if A[Ai] == B[Bi] { + + if A[Ai] != C[Ci] { + checkpingPlanB = true + } else { + // remember this node + Apin, Bpin = Ai, Bi + // try plan A first + Ai++ + } + } else { + + if A[Ai] == C[Ci] { + Ai++ + } else if B[Bi] == C[Ci] { + Bi++ + } else { + checkpingPlanB = true + } + } + } + } +} + +func usage() { + fmt.Println( "Usage: go run ch-2.go " + + "<string> <string> <may be interleaved string>\n" ) +} + +func main() { + if len(os.Args[1:]) != 3 { + usage(); + os.Exit(1); + } + A, B, C := os.Args[1], os.Args[2], os.Args[3] + + if isInterleaving(A, B, C) { + fmt.Println( "1" ) + } else { + fmt.Println( "0" ) + } +} diff --git a/challenge-082/jeongoon/haskell/ch-1.hs b/challenge-082/jeongoon/haskell/ch-1.hs new file mode 100644 index 0000000000..fda6cf8772 --- /dev/null +++ b/challenge-082/jeongoon/haskell/ch-1.hs @@ -0,0 +1,23 @@ +import System.Environment +import System.Exit +import Data.Char (isNumber) +import Data.Maybe (isJust, catMaybes) + +{- test with: +runhaskell ch-1.hs 12 18 +-} + +-- from ch-081/ch-1.hs :-] +--commonDivisors :: (Integral a) => [a] -> [a] +commonDivisors [] = [] +commonDivisors xs = filter ((==0).(rem gcd')) ([1..(gcd' `div` 2)] ++ [gcd']) + where gcd' = foldr1 (\acc x -> gcd acc x) xs + +main = do + (catMaybes.map (\nStr -> + if (all isNumber nStr) then Just(read nStr :: Int) + else Nothing )) `fmap` getArgs + >>= (\nums -> + if length nums /= 2 then + die "Usage: runhaskell ch-1.hs <natural num> <natural num>" + else (putStrLn.show.commonDivisors.take 2) nums ) diff --git a/challenge-082/jeongoon/haskell/ch-2.hs b/challenge-082/jeongoon/haskell/ch-2.hs index a3fc204f5a..5dd2eff3fd 100644 --- a/challenge-082/jeongoon/haskell/ch-2.hs +++ b/challenge-082/jeongoon/haskell/ch-2.hs @@ -3,6 +3,10 @@ import System.Exit import Data.Maybe (catMaybes) import Data.List (intersect, intercalate) +{- test with: +runhaskell ch-2.hs XXY XXZ XXXXZY +-} + data WhichPart = Odd | Even deriving (Show, Eq) decomposeAsEachOddsEvensWith :: String -> [Int] -> ([String], String, String) @@ -86,7 +90,7 @@ main = do args <- getArgs; let sa = args !! 0; sb = args !! 1; sc = args !! 2 in if length args /= 3 - then die "Usage: runhaskell ch-1.hs <string A> <string B> <string C>" + then die "Usage: runhaskell ch-2.hs <string A> <string B> <string C>" else case allInterleavedCases sa sb sc of Left err -> putStrLn $ "0 as " ++ err diff --git a/challenge-082/jeongoon/perl/ch-1.pl b/challenge-082/jeongoon/perl/ch-1.pl new file mode 100644 index 0000000000..3af39cafce --- /dev/null +++ b/challenge-082/jeongoon/perl/ch-1.pl @@ -0,0 +1,47 @@ +#!/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 v5.26; +use List::Util qw(all); + +sub usage { + say 'Usage: perl ch-1.pl <natural num> <natural num>', "\n", + 'ex) perl ch-1.pl 12 18'; +} + +sub common_divisors_($$) { + # note: do not check they are natural numbers. + my ( $l, $r ) = @_; + + my @gcdFinders; + + @gcdFinders = ( + # for 0 ( == ) + sub { $l }, + # for 1 ( < ) + sub { # left hand side is smaller but trust user input if given + my ( $sm, $bg ) = @_ ? @_ : ($l, $r); + if ( $bg % $sm == 0 ) { $sm } + else { + my $i = $sm; + --$i while ( $sm % $i || $bg % $i ); + $i; + } + }, + # for -1 ( > ) + sub { $gcdFinders[1]->( $r, $l ); } + ); + + my $gcd = $gcdFinders[ $l <=> $r ]->(); + map { ( $gcd % $_ ) ? () : $_ } 1 .. $gcd; +} + +my ( $M, $N ) = @ARGV; + +( @ARGV == 2 + and + all { int($_) eq $_ and $_ > 0 } $M, $N ) or usage, exit 0; + +say "(".join(", ", common_divisors_( $M, $N )).")"; diff --git a/challenge-082/jeongoon/perl/ch-2.pl b/challenge-082/jeongoon/perl/ch-2.pl new file mode 100644 index 0000000000..e5eba1d0f0 --- /dev/null +++ b/challenge-082/jeongoon/perl/ch-2.pl @@ -0,0 +1,169 @@ +#!/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 v5.26; +use List::Util qw(all any min); + +# this will find the all the possilbe way to make interleave string + +# tested with: +# perl ch-2.pl ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCABCDDEFGHIJEFKLGHIJKLMNMNOOPPQRQRSTUVSTWXYUVWXYZZ # 1: 256 cases +# perl ch-2.pl XY XX XYXX # 1: 1 cases +# perl ch-2.pl 1X XX XXX1 # 0 + +sub usage { + say $/,'Usage: perl ch-2.pl <string> <string> <may be interleaved string>', + $/,'ex) perl ch-1.pl AY AA AYAA # only 1 case.',$/; +} + +# real entry point +sub allPossiblePartitions ($$$) { + my ( $A, $B, $C ) = @_; + my $sum = length $C; + my @sps = somePossilbeSum( 1, $sum, [], [], + sub ($) { # check if we can continue to make a permutation sequences + my $parts = shift; + @$parts <= 1 and return 1; # 1 block is too short + # because we need to compare both A,B + + my ( $splited, $o, $e ) # o: odd indexed chars(string) + # e: even indexed chars(string) + = uninterleave( $C, $parts ); + # check if *maybe* interleaved + # we will confirm later + return any { # any case of A, B vs B, A + my ($l, $r) = @$_; # left, right + + my $omin = (min (map {length} $l, $o)); + my $emin = (min (map {length} $r, $e)); + + all { + # minimum compare left vs odds + # or right vs evens + my ($m, $n, $len) = @$_; + substr( $m, 0, $len ) eq substr( $n, 0, $len ) + } [$l, $o, $omin], [$r, $e, $emin]; + } [$A,$B], [$B,$A]; + } + ); + + map { # confirm the cases if actually interleaved + if ( @$_ > 1 ) { + my @resultRow = uninterleave( $C, $_ ); + my ( $splited, $o, $e ) = @resultRow; + + if ( any { + my ( $a, $b ) = @$_; + $a eq $o and $b eq $e + } [$A, $B], [$B, $A] ) { + \@resultRow + } + else { + () # not interleaved + } + } else { + # skip if only one block, becuase it doesn't make a interleave str. + # it is okay only if A or B is empty. + # but it doesn't make sense for me + # because interleaving has no meaning if one of them is empty + () + } + } @sps; +} + +# limited permutations with repeatition and filtering ... +# find any possible cases of group of natural numbers can make $sum + +sub somePossilbeSum ( $$$$$ ); +sub somePossilbeSum ( $$$$$ ) { + my ( $n, $sum, + $parentPartitions, # store numbers into ArrayRef + # to remember current depth and totoal summation + $siblings, # possible other cases at the same level + $isValid # validator for current case + ) = @_; + return () if $sum == 0; + + my $maybeNewPartitions = [ @$parentPartitions, $n ]; + + if ( $isValid->( $maybeNewPartitions ) ) { + + if ( $n == $sum ) { # last (edge case) for parent case + # no more *next* cases in other word + # due to $n starts from 1 until meet $sum + @$siblings, [ $n ] + } + else { + # *maybe* have lower cases + my @childrenCases = somePossilbeSum( 1, # starts from 1 + ($sum - $n ), # with rest + $maybeNewPartitions, + [], # without siblings + $isValid ); + + my @expandedCurrentCases = map { [ $n, @$_ ] } @childrenCases; + + # go for next case with siblings which includes current one. + somePossilbeSum( ++$n, # next case + $sum, # with same number + $parentPartitions, # with the same parent + [ @$siblings, @expandedCurrentCases ], + $isValid ) + } + } else { + @$siblings + } +} |
