From f0749fdd43fc1c98170ca312777fb999ef674329 Mon Sep 17 00:00:00 2001 From: Myoungjin JEON Date: Thu, 22 Oct 2020 15:20:14 +1100 Subject: [ch-083/jeongoon] Go, Perl Solution added --- challenge-083/jeongoon/go/ch-1.go | 32 ++++ challenge-083/jeongoon/go/ch-2.go | 190 +++++++++++++++++++++ challenge-083/jeongoon/perl/CombinationsIndex.pm | 123 +++++++++++++ challenge-083/jeongoon/perl/ch-1.pl | 31 ++++ challenge-083/jeongoon/perl/ch-2.pl | 79 +++++++++ challenge-083/jeongoon/raku/ch-2.raku | 22 ++- challenge-083/jeongoon/raku/ch-2.without-race.raku | 23 --- .../jeongoon/raku/ch-2.yet-another-race.raku | 38 +++-- 8 files changed, 498 insertions(+), 40 deletions(-) create mode 100644 challenge-083/jeongoon/go/ch-1.go create mode 100644 challenge-083/jeongoon/go/ch-2.go create mode 100644 challenge-083/jeongoon/perl/CombinationsIndex.pm create mode 100644 challenge-083/jeongoon/perl/ch-1.pl create mode 100644 challenge-083/jeongoon/perl/ch-2.pl delete mode 100644 challenge-083/jeongoon/raku/ch-2.without-race.raku (limited to 'challenge-083') diff --git a/challenge-083/jeongoon/go/ch-1.go b/challenge-083/jeongoon/go/ch-1.go new file mode 100644 index 0000000000..d4f073f3e3 --- /dev/null +++ b/challenge-083/jeongoon/go/ch-1.go @@ -0,0 +1,32 @@ +package main + +import ( + "os" + "fmt" + "strings" +) + +func usage() { + fmt.Println( "Usage: go run ch-1.go \"a single string\"" ) +} + +func main() { + if len(os.Args[1:]) != 1 { + usage() + os.Exit(1); + } + + words := strings.Split( os.Args[1], " " ); + if len(words) < 3 { + fmt.Fprintln( os.Stderr, + "words must contain at least three words" ) + os.Exit(2); + } + + middleCharsExceptWhitespace := 0 + for _, c := range words[ 1 : len(words)-1 ] { + middleCharsExceptWhitespace += len(c) + } + + fmt.Println( middleCharsExceptWhitespace ) +} diff --git a/challenge-083/jeongoon/go/ch-2.go b/challenge-083/jeongoon/go/ch-2.go new file mode 100644 index 0000000000..60433a850f --- /dev/null +++ b/challenge-083/jeongoon/go/ch-2.go @@ -0,0 +1,190 @@ +package main + +import ( + "os" + "fmt" + "strconv" +) + +func usage() { + fmt.Println( "Usage: go run ch-2.go ..." ); +} + +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) +} + +/* + * Another my own version of making combinations without recursive call + * explanation in perl: + * https://github.com/jeongoon/pwc-by-me/blob/master/075/perl/CombinationsIndex.pm + * I found that this implementation very fast in Perl, + * so it will be the same in golang especially when compiled. + */ + +func combinationsIndex( M int, N int ) [][]int { + // M: number of selection ( 0 ... (M-1) ) + // N: number of choice + if M < N { + return [][]int{} + } + + initRoomSize := M - N + room := make([]int, N) + pos := make([]int, N) + // https://stackoverflow.com/questions/39984957/is-it-possible-to-initialize-slice-with-specific-values + for i := range room { + room[i] = initRoomSize + } + for i := range pos { + pos[i] = i + } + + var combis [][]int + new_case := make([]int, N) + copy(new_case, pos) + combis = append( [][]int{}, new_case ) + + cursor := N - 1 // initial: index of last elements in selection + + for { + if room[cursor] > 0 { + room[cursor]-- + pos[cursor]++ + new_case := make([]int, N) + copy(new_case, pos) + combis = append(combis, new_case) + } else { + cursor_moved := false + for i := cursor; i > 0; i-- { + if room[i-1] > 0 { + cursor = i-1 + cursor_moved = true + break + } + } + if cursor_moved { + new_room := room[cursor] - 1 + base_pos := pos[cursor]; + for p, i := 1, cursor; i < N; i++ { + room[i] = new_room + pos[i] = base_pos + p + p++ // p++, i++ not working on for() + } + new_case := make([]int, N) + copy(new_case, pos) + combis = append(combis, new_case) + cursor = N - 1 + } else { + break + } + } + + } + + return combis +} + +func main() { + if len(os.Args[1:]) < 1 { + usage(); + os.Exit(1); + } + + var N []Nat + all_good := true + debug := false + + for _, str := range os.Args[1:] { + if MaybeNat(str).isNatural() { + N = append(N, MaybeNat(str).Nat()) + } else { + all_good = false + break + } + } + + if ! all_good { + usage(); + os.Exit(2); + } + + lenN := len(N) + if lenN == 1 { + // already minimum: no need to change + fmt.Println( "0" ); + // but not error + os.Exit(0); + } + + totalSum := 0 + maxNum := 0 + for _, n := range N { + totalSum += int(n) + if maxNum < int(n) { + maxNum = int(n) + } + } + + minPositiveSum := totalSum + minPositiveElems := len(N) + for i := 1; i < lenN; i++ { + for _, cb := range combinationsIndex(lenN, i) { + negativeGroupSum := 0 + for _, idx := range cb { + negativeGroupSum += int(N[idx]) + } + + diff := totalSum - 2 * negativeGroupSum + maybeNewElems := len(cb) + + if debug { + fmt.Println( "before: ", diff, + " with ", maybeNewElems, + " <=> ", minPositiveSum, + " with ", minPositiveElems ) + } + + if diff >= 0 && + minPositiveSum >= diff { + if minPositiveSum == diff { + if minPositiveElems > maybeNewElems { + minPositiveElems = maybeNewElems + } + } else { // minPositiveElems > diff + minPositiveElems = maybeNewElems + } + + minPositiveSum = diff + } + + if debug { + fmt.Println( "after: ", diff, + " with ", maybeNewElems, + " <=> ", minPositiveSum, + " with ", minPositiveElems ) + } + + if minPositiveSum == 0 && minPositiveElems == 1 { + break; + } + } + } + fmt.Println( minPositiveElems ) +} diff --git a/challenge-083/jeongoon/perl/CombinationsIndex.pm b/challenge-083/jeongoon/perl/CombinationsIndex.pm new file mode 100644 index 0000000000..385c8905cd --- /dev/null +++ b/challenge-083/jeongoon/perl/CombinationsIndex.pm @@ -0,0 +1,123 @@ +# -*- Mode: cperl; cperl-indent-level:4; tab-width: 8; indent-tabs-mode: nil -*- +# Copyright (c) 2013,2020 JEON Myoungjin + +package CombinationsIndex; +use strict; use warnings; + +use version 0.77; our $VERSION = version->declare( 'v0.3' ); + +use parent 'Exporter'; +our @EXPORT_OK = qw(combinationsIndex); + +=pod + +=head1 Basic concept + +If we find the combintions when choosing 3 digits from index of 0 .. 4 +which shown below + + 0 1 2 3 4 + ^1 ^2 ^3 initial selection: index position: ( 0, 1, 2 ) + +to get next combination we can move ^3 cursor from 2 to 3 + + 0 1 2 3 4 + ^1 ^2 ^3 note: ^3 can move up to 4 + +as you can see ^3 can only go up to 4, next movement we can imagine is that +moving ^2 to next one and ^3 is just followed by ^2 +and next movement will be again ^3 to the index 4 + + 0 1 2 3 4 => 0 1 2 3 4 => 0 1 2 3 4 + ^1 ^2 ^3 ^1 ^2 ^3 ^1 ^2 ^3 + +and last case of combinations will be + + 0 1 2 3 4 + ^1 ^2 ^3 + +so I make two arrays to record + 1. where each cursor is pointing now, + 2. how many rooms left for each cursor to move + +and also remember what is the current cursor move next. + +so we can also make combinations without recursive routine. + +=cut + +sub combinationsIndex ( $$ ) { + # I changed the order of arguments since v0.3 + my $M = $_[0]; # choice" 0 .. ($M - 1) + my $N = $_[1]; # number of selection + + my @result; + + # minimum sanity check + if ( $M < $N ) { + warn "unable to choose $N from given selection of $M"; + return (); + } + + my ( @room, # number of spaces(rooms) each + @pos, # current position of cursor + $next_csr # next cursor to move + ); + + # set initial values ... + { + # each finger can move to right number of ( M-N ) space(s). + @room = ( $M-$N ) x $N; + @pos = 0 .. ($N - 1); + $next_csr = $N - 1; # last cursor at rightmost + + # initial record; note: use not index number but real value + push @result, [ @pos ]; + } + + { + if ( $room[$next_csr] > 0 ) { + # current csr can move to right so just do it. + ++$pos[ $next_csr]; + --$room[$next_csr]; # room decreased of course + + # and make a record + push @result, [ @pos ]; + redo; + } + else { + # no more room to move + # so find the next cursor to move + my $found = 0; + for ( my $i = $next_csr; $i > 0; --$i ) { + if ( $room[ $i-1 ] > 0 ) { + $next_csr = $i-1; + $found = 1; + last ; + } + } + + if ( $found ) { + # move all the cursors which are starts from + # $next_csr to last one + @pos[ $next_csr .. ($N-1) ] + = map { $pos[$next_csr] + $_ } 1 .. ($N-$next_csr); + # note: all these finger has same room when moved + @room[ $next_csr .. ($N-1) ] + = ( $room[ $next_csr ] - 1 ) x ($N-$next_csr); + + # and make a record + push @result, [ @pos ]; + + # next finger to move will be ($N-1) + # or even if it is not next loop will find anohter + $next_csr = ($N-1); + + redo; # if we can move next cursor + } + } + } + @result; +} + +!!"^^"; diff --git a/challenge-083/jeongoon/perl/ch-1.pl b/challenge-083/jeongoon/perl/ch-1.pl new file mode 100644 index 0000000000..6db83a6e0b --- /dev/null +++ b/challenge-083/jeongoon/perl/ch-1.pl @@ -0,0 +1,31 @@ +#!/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(sum); + +sub usage { + say 'Usage: perl ch-1.pl ', "\n", + 'ex) perl ch-1.pl "Perl Weekly Challenge"'; +} + +package main; + +my @words; + +@ARGV == 1 or usage, exit 1; +@words = split /\s/, $ARGV[0]; +@words > 2 or usage, exit 2; + +say( + sum + map {length} # count each length + @words[ + 1 # from the second word + .. + $#words-1 # to the second last one + ] + ); diff --git a/challenge-083/jeongoon/perl/ch-2.pl b/challenge-083/jeongoon/perl/ch-2.pl new file mode 100644 index 0000000000..75af463b95 --- /dev/null +++ b/challenge-083/jeongoon/perl/ch-2.pl @@ -0,0 +1,79 @@ +#!/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 sum); + +use FindBin; +use lib ( $FindBin::Bin ); +use CombinationsIndex v0.3 qw(combinationsIndex); + +sub usage { + say 'Usage: perl ch-2.pl [-d|--debug] ... ', "\n", + 'ex) perl ch-2.pl 12 2 10'; +} + +sub combinations ($$$) { + my ( $indexCount, $minSelection, $maxSelection ) = @_; + map { combinationsIndex( $indexCount, $_ ) } + $minSelection .. $maxSelection; +} + +package main; + +my @N = grep { ! /-(h|-*help)/ } @ARGV; +@N == @ARGV or usage, exit 0; + +@N = grep { ! /-(d|-*debug)/ } @ARGV; +our $d = @N != @ARGV; + +( @N > 0 + and + all { int($_) eq $_ and $_ > 0 } @N ) or usage, exit 1; + +@N == 1 and ( say( "0" ), exit 0 ); # already mimimum + +my $totalSum = sum @N; +my $halfLen = int( .5 * @N ); # reduce the combinations in half + +# initial values ... +my $minElems = +@N; +my $minSum = $totalSum; + +for my $combi ( combinations( +@N, 1, $halfLen ) ) { + my $aSum = sum @N[ @$combi ]; + my $bSum = $totalSum - $aSum; + + my $curr = + ( # $aSum == $bSum + [ 0, ( scalar @$combi < $halfLen + ? scalar @$combi : scalar( @N - @$combi) ) ], + # $aSum > $bSum + [ $aSum - $bSum, scalar ( @N - @$combi) ], + # $aSum < $bSum + [ $bSum - $aSum, scalar @$combi ] )[ $aSum <=> $bSum ]; + + print "[sum: $$curr[0], elems: $$curr[1]] with @N[@$combi] ... " if $d; + + if ( $$curr[0] > $minSum ) { # minimum sum not changed + say "skipped." if $d; + next; + } + elsif ( $$curr[0] < $minSum ) { # minimum sum cahnged + # so does minimum elements + say "**minium sum changed**" if $d; + ( $minSum, $minElems ) = @$curr; + } + elsif ( $$curr[1] < $minElems ) { # minimum sum is same + # also elements is less + say "**minimum count changed**" if $d; + $minElems = $$curr[1]; + } + else { + say "" if $d; + } +} + +say $minElems; diff --git a/challenge-083/jeongoon/raku/ch-2.raku b/challenge-083/jeongoon/raku/ch-2.raku index 45fbdcee95..0506ce2dc8 100644 --- a/challenge-083/jeongoon/raku/ch-2.raku +++ b/challenge-083/jeongoon/raku/ch-2.raku @@ -7,7 +7,27 @@ use v6.d; multi MAIN ($n where * > 0) { say 0 } + +# without race multi MAIN (*@n where { @n.all ~~ Int and @n.all > 0 }) { + my $s = @n.sum; + @n.combinations( 1..^ @n ). + map( + -> \n { + with $s - 2 * n.sum { # same as ( $s- n.sum ) - n.sum + next if $_ < 0; + $_ => n.elems + } + } ). + min. + value. + say +} + +# tested with: raku jeongoon/raku/ch-2.raku --r 12 7 4 5 6 9 20 12 7 4 5 6 9 20 9 4 2 1 13 +# finished in under 4 seconds on my laptop +multi MAIN ( Bool:D :$r, *@n where { @n.all ~~ Int and @n.all > 0 }) { + $*ERR.say( "using race ..." ); my $s = @n.sum; @n.combinations( 1..^ @n ). race( :8degree:500batch ). @@ -18,7 +38,7 @@ multi MAIN (*@n where { @n.all ~~ Int and @n.all > 0 }) { $_ => n.elems } } ). - race( :8degree:5000batch ). + race( :8degree:500batch ). min. value. say diff --git a/challenge-083/jeongoon/raku/ch-2.without-race.raku b/challenge-083/jeongoon/raku/ch-2.without-race.raku deleted file mode 100644 index 26dc21fbec..0000000000 --- a/challenge-083/jeongoon/raku/ch-2.without-race.raku +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env raku -# -*- Mode: Raku; indent-tabs-mode: nil; coding: utf-8 -*- -# vim: set et ts=4 sw=4: - -# personal-blog: https://dev.to/jeongoon/weekly-challenge-083-task-2-raku-2cjm - -use v6.d; - -multi MAIN ($n where * > 0) { say 0 } -multi MAIN (*@n where { @n.all ~~ Int and @n.all > 0 }) { - my $s = @n.sum; - @n.combinations( 1..^ @n ). - map( - -> \n { - with $s - 2 * n.sum { # same as ( $s- n.sum ) - n.sum - next if $_ < 0; - $_ => n.elems - } - } ). - min. - value. - say -} diff --git a/challenge-083/jeongoon/raku/ch-2.yet-another-race.raku b/challenge-083/jeongoon/raku/ch-2.yet-another-race.raku index 911d0f2136..6e0a952d6d 100644 --- a/challenge-083/jeongoon/raku/ch-2.yet-another-race.raku +++ b/challenge-083/jeongoon/raku/ch-2.yet-another-race.raku @@ -3,34 +3,40 @@ # vim: set et ts=4 sw=4: # personal-blog: https://dev.to/jeongoon/weekly-challenge-083-task-2-raku-2cjm -# I hoped that this will be faster but it wasn't :-/ +# I wished this implementation faster but it wasn't +# I guess Raku doesn't like conditional flow control +# so... generating is simpler and faster than filtering ?? use v6.d; multi MAIN ($n where * > 0) { say 0 } multi MAIN (*@n where { @n.all ~~ Int and @n.all > 0 }) { - my \B = @n.Bag; - my \S = @n.sum; + my \TotalSum = @n.sum; my $half-len-floor = @n.elems div 2; - @n.combinations( 1.. $half-len-floor ). - race( :8degree:1000batch ). + @n.combinations( 1.. $half-len-floor ). # reduced combinations length + race( :8degree:500batch ). map( - -> $G + -> $grp # current combination { - my $a = $G.sum; # sum of selected group - my $b = (S - $G.sum); - given $a - $b { - if $_ < 0 { - -$_ => $G.elems - } elsif $_ == 0 { - |( 0 => $G.elems, 0 => (B (-) $G.Bag).total ) - } else { - $_ => (B (-) $G.Bag).total + my $a = $grp.sum; # sum of selected group + my $b = (TotalSum - $grp.sum); + given $a cmp $b { + when Less { + ($b-$a) => $grp.elems + } + when More { + ($a-$b) => @n.elems - $grp.elems + } + default { + 0 => ($grp.elems < $half-len-floor + # using shorter elems + ?? $grp.elems !! @n.elems - $grp.elems) } } } ). - race( :8degree:1000batch ). + race( :8degree:500batch ). min. + value. say } -- cgit From 3282b099dcb30ad58ffae21953a0b70cf1a6c02d Mon Sep 17 00:00:00 2001 From: Tyler Wardhaugh Date: Mon, 19 Oct 2020 15:27:48 -0700 Subject: Ch83: prep for challenge --- challenge-083/tyler-wardhaugh/clojure/README.md | 8 ++++---- challenge-083/tyler-wardhaugh/clojure/deps.edn | 7 +++---- challenge-083/tyler-wardhaugh/clojure/pom.xml | 14 +++++++------- challenge-083/tyler-wardhaugh/lua/README.md | 6 +++--- 4 files changed, 17 insertions(+), 18 deletions(-) (limited to 'challenge-083') diff --git a/challenge-083/tyler-wardhaugh/clojure/README.md b/challenge-083/tyler-wardhaugh/clojure/README.md index 546cb8db65..bf37bd62cc 100644 --- a/challenge-083/tyler-wardhaugh/clojure/README.md +++ b/challenge-083/tyler-wardhaugh/clojure/README.md @@ -1,4 +1,4 @@ -# tw.weekly.c82 +# tw.weekly.c83 The Weekly Challenge - #082 - Tyler Wardhaugh @@ -7,7 +7,7 @@ The Weekly Challenge - #082 - Tyler Wardhaugh Run the project directly (shows default output from both tasks): - $ clojure -M -m tw.weekly.c82.core + $ clojure -M -m tw.weekly.c83.core Run the project's tests (which are samples from the task descriptions): @@ -15,11 +15,11 @@ Run the project's tests (which are samples from the task descriptions): Run Task #1 with input - $ clojure -M -m tw.weekly.c82.t1 M N + $ clojure -M -m tw.weekly.c83.t1 S Run Task #2 with input: - $ clojure -M -m tw.weekly.c82.t2 S1 S2 + $ clojure -M -m tw.weekly.c83.t2 A1 A2 A3... ## Project Template diff --git a/challenge-083/tyler-wardhaugh/clojure/deps.edn b/challenge-083/tyler-wardhaugh/clojure/deps.edn index c692c74c45..4d1263a667 100644 --- a/challenge-083/tyler-wardhaugh/clojure/deps.edn +++ b/challenge-083/tyler-wardhaugh/clojure/deps.edn @@ -1,6 +1,5 @@ {:paths ["src" "resources"] - :deps {org.clojure/clojure {:mvn/version "1.10.1"} - org.clojure/math.numeric-tower {:mvn/version "0.0.4"}} + :deps {org.clojure/clojure {:mvn/version "1.10.1"}} :aliases {:test {:extra-paths ["test"] :extra-deps {org.clojure/test.check {:mvn/version "1.0.0"}}} @@ -11,5 +10,5 @@ :main-opts ["-m" "cognitect.test-runner" "-d" "test"]} :uberjar {:extra-deps {seancorfield/depstar {:mvn/version "1.0.94"}} - :main-opts ["-m" "hf.depstar.uberjar" "tw.weekly.c82.jar" - "-C" "-m" "tw.weekly.c82"]}}} + :main-opts ["-m" "hf.depstar.uberjar" "tw.weekly.c83.jar" + "-C" "-m" "tw.weekly.c83"]}}} diff --git a/challenge-083/tyler-wardhaugh/clojure/pom.xml b/challenge-083/tyler-wardhaugh/clojure/pom.xml index 92eb55d64a..7d5a4bb861 100644 --- a/challenge-083/tyler-wardhaugh/clojure/pom.xml +++ b/challenge-083/tyler-wardhaugh/clojure/pom.xml @@ -2,11 +2,11 @@ 4.0.0 tw.weekly - tw.weekly.c82 + tw.weekly.c83 0.1.0-SNAPSHOT - tw.weekly.c82 - Challenge #082 - https://github.com/tw.weekly/tw.weekly.c82 + tw.weekly.c83 + Challenge #083 + https://github.com/tw.weekly/tw.weekly.c83 Eclipse Public License @@ -19,9 +19,9 @@ - https://github.com/tw.weekly/tw.weekly.c82 - scm:git:git://github.com/tw.weekly/tw.weekly.c82.git - scm:git:ssh://git@github.com/tw.weekly/tw.weekly.c82.git + https://github.com/tw.weekly/tw.weekly.c83 + scm:git:git://github.com/tw.weekly/tw.weekly.c83.git + scm:git:ssh://git@github.com/tw.weekly/tw.weekly.c83.git HEAD diff --git a/challenge-083/tyler-wardhaugh/lua/README.md b/challenge-083/tyler-wardhaugh/lua/README.md index 8247d79487..35e8606521 100644 --- a/challenge-083/tyler-wardhaugh/lua/README.md +++ b/challenge-083/tyler-wardhaugh/lua/README.md @@ -1,17 +1,17 @@ # The Weekly Challenge -The Weekly Challenge - #081 - Tyler Wardhaugh +The Weekly Challenge - #083 - Tyler Wardhaugh ## Usage Run Task 1: - $ ./run.lua ch-1 M N + $ ./run.lua ch-1 S Run Task 2: - $ ./run.lua ch-2 A B C + $ ./run.lua ch-2 A1 A2 A3... Run the project's tests (all the samples from the task descriptions plus some others): -- cgit From 6d5ddbe7022db87dfad43294a8e29eaf841e910e Mon Sep 17 00:00:00 2001 From: Tyler Wardhaugh Date: Mon, 19 Oct 2020 15:53:17 -0700 Subject: Ch83 (Clojure): Task 1 --- .../clojure/src/tw/weekly/c83/core.clj | 9 ++++++ .../clojure/src/tw/weekly/c83/t1.clj | 32 ++++++++++++++++++++++ .../clojure/test/tw/weekly/c83_test.clj | 9 ++++++ 3 files changed, 50 insertions(+) create mode 100644 challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj create mode 100644 challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t1.clj create mode 100644 challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj (limited to 'challenge-083') diff --git a/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj new file mode 100644 index 0000000000..03b7eadc2c --- /dev/null +++ b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj @@ -0,0 +1,9 @@ +(ns tw.weekly.c83.core + (:require [tw.weekly.c83.t1 :as t1]) + (:gen-class)) + +(defn -main + "Run all tasks" + [& _] + (println "Task #1") + (t1/-main)) diff --git a/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t1.clj b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t1.clj new file mode 100644 index 0000000000..36ca66aec0 --- /dev/null +++ b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t1.clj @@ -0,0 +1,32 @@ +(ns tw.weekly.c83.t1 + (:require [clojure.string :as str])) + +;;; Task description for TASK #1 › Words Length +; Submitted by: Mohammad S Anwar +; You are given a string $S with 3 or more words. +; +; Write a script to find the length of the string except the first and last words ignoring whitespace. +; +; Example 1: +; Input: $S = "The Weekly Challenge" +; Output: 6 +; +; +; Example 2: +; Input: $S = "The purpose of our lives is to be happy" +; Output: 23 +; +;;; + +(defn inner-words-length + "Return the combined length of the inner words, ignoring whitespace." + [s] + (let [source (->> (str/split s #" ") (drop 1) (drop-last 1))] + (transduce (map count) + source))) + +(defn -main + "Run Task 1 with a strings S, defaulting to the first example given in the task description." + [& args] + (let [S (or (some-> args first) "The Weekly Challenge") + len (inner-words-length S)] + (println len))) diff --git a/challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj b/challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj new file mode 100644 index 0000000000..870b3e6164 --- /dev/null +++ b/challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj @@ -0,0 +1,9 @@ +(ns tw.weekly.c83-test + (:require [clojure.test :refer [deftest is testing]] + [tw.weekly.c83.t1 :refer [inner-words-length]])) + +(deftest task-1 + (testing "Task 1, Words Length" + (is (= (inner-words-length "The Weekly Challenge") 6)) + (is (= (inner-words-length "The purpose of our lives is to be happy") 23)) + (is (= (inner-words-length "Zero when-no-inner-words-exist!") 0)))) -- cgit From 3ff04e2945a99a6750d833a0d764a36d181a933b Mon Sep 17 00:00:00 2001 From: Tyler Wardhaugh Date: Mon, 19 Oct 2020 23:10:26 -0700 Subject: Ch83 (Clojure): Task 2 --- challenge-083/tyler-wardhaugh/clojure/deps.edn | 4 +- .../clojure/src/tw/weekly/c83/core.clj | 5 +- .../clojure/src/tw/weekly/c83/t2.clj | 55 ++++++++++++++++++++++ .../clojure/test/tw/weekly/c83_test.clj | 8 +++- 4 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t2.clj (limited to 'challenge-083') diff --git a/challenge-083/tyler-wardhaugh/clojure/deps.edn b/challenge-083/tyler-wardhaugh/clojure/deps.edn index 4d1263a667..e3e3cdbca6 100644 --- a/challenge-083/tyler-wardhaugh/clojure/deps.edn +++ b/challenge-083/tyler-wardhaugh/clojure/deps.edn @@ -1,5 +1,7 @@ {:paths ["src" "resources"] - :deps {org.clojure/clojure {:mvn/version "1.10.1"}} + :deps {org.clojure/clojure {:mvn/version "1.10.1"} + org.clojure/math.combinatorics {:mvn/version "0.1.6"} + net.cgrand/xforms {:mvn/version "0.19.2"}} :aliases {:test {:extra-paths ["test"] :extra-deps {org.clojure/test.check {:mvn/version "1.0.0"}}} diff --git a/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj index 03b7eadc2c..d25ddca2de 100644 --- a/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj +++ b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/core.clj @@ -1,9 +1,12 @@ (ns tw.weekly.c83.core (:require [tw.weekly.c83.t1 :as t1]) + (:require [tw.weekly.c83.t2 :as t2]) (:gen-class)) (defn -main "Run all tasks" [& _] (println "Task #1") - (t1/-main)) + (t1/-main) + (println "Task #2") + (t2/-main)) diff --git a/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t2.clj b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t2.clj new file mode 100644 index 0000000000..1dc22c8372 --- /dev/null +++ b/challenge-083/tyler-wardhaugh/clojure/src/tw/weekly/c83/t2.clj @@ -0,0 +1,55 @@ +(ns tw.weekly.c83.t2 + (:require [clojure.edn :as edn]) + (:require [clojure.math.combinatorics :as combo]) + (:require [net.cgrand.xforms :as x])) + +;;; Task description for +; TASK #2 › Flip Array +; Submitted by: Mohammad S Anwar +; You are given an array @A of positive numbers. +; +; Write a script to flip the sign of some members of the given array so that +; the sum of the all members is minimum non-negative. +; +; Given an array of positive elements, you have to flip the sign of some of its +; elements such that the resultant sum of the elements of array should be +; minimum non-negative(as close to zero as possible). Return the minimum no. of +; elements whose sign needs to be flipped such that the resultant sum is +; minimum non-negative. +; +; Example 1: +; Input: @A = (3, 10, 8) +; Output: 1 + +; Explanation: +; Flipping the sign of just one element 10 gives the result 1 i.e. (3) + (-10) + (8) = 1 +; +; +; Example 2: +; Input: @A = (12, 2, 10) +; Output: 1 +; +; Explanation: +; Flipping the sign of just one element 12 gives the result 0 i.e. (-12) + (2) + (10) = 0 +; +;;; + +(defn flip-array + "Determine the minimum number of 'flips' needed to produce the smallest non-negative sum." + [coll] + (let [source (->> coll (map (juxt - +)) (apply combo/cartesian-product)) + xf (comp + (x/by-key (partial reduce +) (x/into [])) + (remove (comp neg? first)) + x/min + x/vals + cat + (map (comp count (partial filter neg?))))] + (reduce min ##Inf (eduction xf source)))) + +(defn -main + "Run Task 2 with an array of integers, defaulting to the example given in the task description." + [& args] + (let [A (or (some->> args (map edn/read-string)) [3 10 8]) + minimum (flip-array A)] + (println minimum))) diff --git a/challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj b/challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj index 870b3e6164..ff8aafb9bb 100644 --- a/challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj +++ b/challenge-083/tyler-wardhaugh/clojure/test/tw/weekly/c83_test.clj @@ -1,9 +1,15 @@ (ns tw.weekly.c83-test (:require [clojure.test :refer [deftest is testing]] - [tw.weekly.c83.t1 :refer [inner-words-length]])) + [tw.weekly.c83.t1 :refer [inner-words-length]] + [tw.weekly.c83.t2 :refer [flip-array]])) (deftest task-1 (testing "Task 1, Words Length" (is (= (inner-words-length "The Weekly Challenge") 6)) (is (= (inner-words-length "The purpose of our lives is to be happy") 23)) (is (= (inner-words-length "Zero when-no-inner-words-exist!") 0)))) + +(deftest task-2 + (testing "Task 2, Flip Array" + (is (= (flip-array [3 10 8]) 1)) + (is (= (flip-array [12 2 10]) 1)))) -- cgit From 920558f8349af8c94676f68b5f9ca2b38574c23f Mon Sep 17 00:00:00 2001 From: Tyler Wardhaugh Date: Tue, 20 Oct 2020 11:30:35 -0700 Subject: Ch83 (Lua): Task 1 --- challenge-083/tyler-wardhaugh/lua/ch-1.lua | 20 ++++++++++++++++++++ challenge-083/tyler-wardhaugh/lua/run.lua | 9 +++++++++ challenge-083/tyler-wardhaugh/lua/test.lua | 12 ++++++++++++ 3 files changed, 41 insertions(+) create mode 100755 challenge-083/tyler-wardhaugh/lua/ch-1.lua create mode 100755 challenge-083/tyler-wardhaugh/lua/run.lua create mode 100755 challenge-083/tyler-wardhaugh/lua/test.lua (limited to 'challenge-083') diff --git a/challenge-083/tyler-wardhaugh/lua/ch-1.lua b/challenge-083/tyler-wardhaugh/lua/ch-1.lua new file mode 100755 index 0000000000..cb4f35d915 --- /dev/null +++ b/challenge-083/tyler-wardhaugh/lua/ch-1.lua @@ -0,0 +1,20 @@ +#!/usr/bin/env lua + +local t1 = {} + +function t1.inner_words_length(s) + local inner = s:match("^%S+%s+%f[%S](.*)%f[%s]%s+%S+$") + if inner then + return inner:gsub("%s+", ""):len() + else + return 0 + end +end + +function t1.run(args) + local s = args[1] + local len = t1.inner_words_length(s) + print(len) +end + +return t1 diff --git a/challenge-083/tyler-wardhaugh/lua/run.lua b/challenge-083/tyler-wardhaugh/lua/run.lua new file mode 100755 index 0000000000..c6e7473bee --- /dev/null +++ b/challenge-083/tyler-wardhaugh/lua/run.lua @@ -0,0 +1,9 @@ +#!/usr/bin/env lua + +local filename = arg[1] +local run_args = table.move(arg, 2, #arg, 1, {}) + +io.write(string.format("Running task from '%s' with {%s}:\n", + filename, table.concat(run_args, ", "))) + +require(filename).run(run_args) diff --git a/challenge-083/tyler-wardhaugh/lua/test.lua b/challenge-083/tyler-wardhaugh/lua/test.lua new file mode 100755 index 0000000000..731b0807b9 --- /dev/null +++ b/challenge-083/tyler-wardhaugh/lua/test.lua @@ -0,0 +1,12 @@ +#!/usr/bin/env lua + +require 'busted.runner'() + +describe("Task 1, Words Length", function() + local t1 = require'ch-1' + it("produces correct results for the examples", function() + assert.are.same(t1.inner_words_length"The Weekly Challenge", 6) + assert.are.same(t1.inner_words_length"The purpose of our lives is to be happy", 23) + assert.are.same(t1.inner_words_length"Zero when-no-inner-words-exist!", 0) + end) +end) -- cgit From 392152e581a9176e9013e786b2d8f94e0ebb3b57 Mon Sep 17 00:00:00 2001 From: Tyler Wardhaugh Date: Tue, 20 Oct 2020 12:36:44 -0700 Subject: Ch83 (Lua): Task 2 --- challenge-083/tyler-wardhaugh/lua/ch-2.lua | 34 ++++++++++++++++++++++++++++++ challenge-083/tyler-wardhaugh/lua/test.lua | 8 +++++++ 2 files changed, 42 insertions(+) create mode 100755 challenge-083/tyler-wardhaugh/lua/ch-2.lua (limited to 'challenge-083') diff --git a/challenge-083/tyler-wardhaugh/lua/ch-2.lua b/challenge-083/tyler-wardhaugh/lua/ch-2.lua new file mode 100755 index 0000000000..bf900a864e --- /dev/null +++ b/challenge-083/tyler-wardhaugh/lua/ch-2.lua @@ -0,0 +1,34 @@ +#!/usr/bin/env lua + +local t2 = {} + +function t2.flip_array(coll) + local min_flips = math.maxinteger + local min_sum = math.maxinteger + local max_bits = 2^#coll - 1 + + local cur_num, cur_sum, is_neg + for bits = 1, max_bits do + cur_num, cur_sum, is_neg = 0, 0, 0 + for i, v in ipairs(coll) do + is_neg = bits & 2^(i-1) == 0 + cur_num = cur_num + (is_neg and 1 or 0) + cur_sum = cur_sum + v * (is_neg and -1 or 1) + end + + if 0 <= cur_sum and cur_sum <= min_sum then + min_flips = math.min(cur_num, min_flips) + min_sum = cur_sum + end + end + + return min_flips +end + + +function t2.run(args) + local minimum = t2.flip_array(args) + print(minimum) +end + +return t2 diff --git a/challenge-083/tyler-wardhaugh/lua/test.lua b/challenge-083/tyler-wardhaugh/lua/test.lua index 731b0807b9..7fa7effa5f 100755 --- a/challenge-083/tyler-wardhaugh/lua/test.lua +++ b/challenge-083/tyler-wardhaugh/lua/test.lua @@ -10,3 +10,11 @@ describe("Task 1, Words Length", function() assert.are.same(t1.inner_words_length"Zero when-no-inner-words-exist!", 0) end) end) + +describe("Task 2, Flip Array", function() + local t2 = require'ch-2' + it("produces correct results for the examples", function() + assert.are.same(t2.flip_array({3, 10, 8}), 1) + assert.are.same(t2.flip_array({12, 2, 10}), 1) + end) +end) -- cgit From 9a510abb7e11b23abd13ca572d161e6506bb127c Mon Sep 17 00:00:00 2001 From: Myoungjin JEON Date: Thu, 22 Oct 2020 22:48:34 +1100 Subject: [ch-083/jeongoon] Haskell Solution added --- challenge-083/jeongoon/haskell/Combinations.hs | 25 ++++++++++++ challenge-083/jeongoon/haskell/ch-1.hs | 20 ++++++++++ challenge-083/jeongoon/haskell/ch-2.hs | 53 ++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 challenge-083/jeongoon/haskell/Combinations.hs create mode 100644 challenge-083/jeongoon/haskell/ch-1.hs create mode 100644 challenge-083/jeongoon/haskell/ch-2.hs (limited to 'challenge-083') diff --git a/challenge-083/jeongoon/haskell/Combinations.hs b/challenge-083/jeongoon/haskell/Combinations.hs new file mode 100644 index 0000000000..f8c5324f43 --- /dev/null +++ b/challenge-083/jeongoon/haskell/Combinations.hs @@ -0,0 +1,25 @@ +{- Copyright (c) 2020 JEON Myoungjin -} + +module Combinations + ( combinations + ) where + +combinations :: [a] -> Int -> [[a]] +combinations [] _ = [] +combinations (m:ms) 1 = [m] : (combinations ms 1) +combinations [_] 2 = [] +combinations [e,f] 2 = sequence [ [e],[f] ] +combinations (m:ms) 2 = sequence [ [m], ms ] ++ (combinations ms 2) +combinations mls n = + case totalLen `compare` n of + LT -> [] + EQ -> [mls] + _ -> [ let leaders = map (mls!!) ids + in leaders ++ followers | + ids <- combinations [ 0 .. room ] n', + let skipCount = (last ids) + 1, + followers <- (combinations (drop skipCount mls) 2) ] + where + totalLen = length mls + room = totalLen - 2 + n' = n - 2 diff --git a/challenge-083/jeongoon/haskell/ch-1.hs b/challenge-083/jeongoon/haskell/ch-1.hs new file mode 100644 index 0000000000..1d108ae629 --- /dev/null +++ b/challenge-083/jeongoon/haskell/ch-1.hs @@ -0,0 +1,20 @@ +import System.Environment +import System.Exit + +{- test with: +runhaskell ch-1.hs "Perl W e e k l y Challenge" # output: 6 +-} +main = do + args <- getArgs; + if length args /= 1 + then die "Usage: runhaskell ch-1.hs [a] -> Int +answerFlipArray nums + | totalSum == 1 = 0 + | otherwise = answerWith totalSum totalLen numCombis + where + totalSum = sum nums + totalLen = length nums + halfLen = totalLen `div` 2 + numCombis = (foldr1 (++) . + map (combinations nums)) + [ 1 .. halfLen ] + + answerWith _ minElems [] = minElems + answerWith minSum minElems (aCombi:otherCombis) = + case (positiveSum `compare` minSum) of + LT -> answerWith positiveSum newElems otherCombis + EQ -> answerWith minSum (min newElems minElems) otherCombis + GT -> answerWith minSum minElems otherCombis + where + len = length aCombi + sm = sum aCombi + sm' = totalSum - sm + (positiveSum, newElems) = + case (sm `compare` sm') of + LT -> ( sm' - sm, len ) + EQ -> ( 0, (min len (totalLen - len)) ) + GT -> ( sm - sm', (totalLen - len) ) + +main = do + (catMaybes.map (\nStr -> + if (all isNumber nStr) then Just(read nStr :: Int) + else Nothing )) `fmap` getArgs + >>= (\nums -> + if length nums < 1 then + die "Usage: runhaskell ch-2.hs ..." + else + putStrLn $ show ( answerFlipArray nums ) ) -- cgit