#+title: Challenge 122 #+date: 2021-07-21 #+html_link_up: ../index.html #+export_file_name: index #+setupfile: ~/.emacs.d/org-templates/level-2.org * Task 1 - Average of Stream You are given a stream of numbers, ~@N~. Write a script to print the average of the stream at every point. Example: #+begin_src Input: @N = (10, 20, 30, 40, 50, 60, 70, 80, 90, ...) Output: 10, 15, 20, 25, 30, 35, 40, 45, 50, ... Average of first number is 10. Average of first 2 numbers (10+20)/2 = 15 Average of first 3 numbers (10+20+30)/3 = 20 Average of first 4 numbers (10+20+30+40)/4 = 25 and so on. #+end_src ** Raku - Program: [[file:raku/ch-1.raku]] The subroutine ~avg~ takes a list of numbers and returns their average. We just loop over keys of ~@nums~ and print the average upto each point. #+begin_src raku #| return average of lists. sub avg(*@list) { (sum @list) / @list.elems; } #| average of stream at every point. sub MAIN(*@nums where {$_.all ~~ Int}) { put @nums.keys.map({avg @nums[0..$_]}); } #+end_src ** C - Program: [[file:c/ch-1.c]] ~argv~ holds the input & ~argc~ holds the number of inputs. We loop over ~argv~ and convert each input to an integer and add it to ~sum~ which holds the sum of inputs upto that point and print ~sum / idx~, ~idx~ being the index of input. #+begin_src c long sum = 0; for (int idx = 1; idx < argc; idx++) { int num; const char *errstr; num = strtonum(argv[idx], INT_MIN, INT_MAX, &errstr); if (errstr != NULL) errx(1, "number is %s: %s", errstr, argv[idx]); sum += num; printf("%ld ", sum / idx); } printf("\n"); #+end_src * Task 2 - Basketball Points You are given a score ~$S~. You can win basketball points e.g. 1 point, 2 points and 3 points. Write a script to find out the different ways you can score ~$S~. Example: #+begin_src Input: $S = 4 Output: 1 1 1 1 1 1 2 1 2 1 1 3 2 1 1 2 2 3 1 Input: $S = 5 Output: 1 1 1 1 1 1 1 1 2 1 1 2 1 1 1 3 1 2 1 1 1 2 2 1 3 1 2 1 1 1 2 1 2 2 2 1 2 3 3 1 1 3 2 #+end_src ** Raku - Program: [[file:raku/ch-2.raku]] ~(0, 1, 2, 3) xx $score~ creates the list ~0..3~, ~$score~ number of times. And ~[X]~ creates cross product from those lists. - Note: It's multipled ~$score~ number of times because ~(1) xx $score~ is the maximum upto which we get ~$score~, after that the sum will exceed ~$score~, we do have 0's there which means we'll get more matches but we've already covered those cases. Say the score is 3. We have 3 lists like these: #+begin_src 0 0 0 1 1 1 2 2 2 3 3 3 #+end_src And cross product will return: #+begin_src 0, 0, 0 0, 0, 1 0, 0, 2 0, 0, 3 0, 1, 0 ... 3, 3, 3 #+end_src We loop over what the cross product returns and take the list if the sum of all elements equals to the score. #+begin_src raku #| scoring basketball points unit sub MAIN(Int $score); .put for gather for [X] ((0, 1, 2, 3) xx $score) -> @scores { take @scores if ([+] @scores) == $score; }.map(*.grep(* !== 0).join).unique.map(*.comb); #+end_src After we gather the lists of scores, remove 0's from there and then we remove duplicate entries. Duplicates entries are removed by converting them to string, using ~unique~ method and converting them back to Int. These entries occur because cross product includes them multiple times. For example, for a score of 3: Cross product will return ~0 1 2~ and ~1 2 0~, both of which will satisty the condition and we'll gather them, after removing the 0's, they become duplicates.