#+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.