aboutsummaryrefslogtreecommitdiff
path: root/challenge-126
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2021-08-19 18:12:45 +0100
committerGitHub <noreply@github.com>2021-08-19 18:12:45 +0100
commitc7d75187939cdebeb0503bdbef98bce019c7ca5e (patch)
treebe18d0acabd786da406dc30925859318d1fda104 /challenge-126
parente60d34206cecbc7f62070350426a57aadaf0f4de (diff)
parente56822de5dcdc476448520fc573f42da4c7c6247 (diff)
downloadperlweeklychallenge-club-c7d75187939cdebeb0503bdbef98bce019c7ca5e.tar.gz
perlweeklychallenge-club-c7d75187939cdebeb0503bdbef98bce019c7ca5e.tar.bz2
perlweeklychallenge-club-c7d75187939cdebeb0503bdbef98bce019c7ca5e.zip
Merge pull request #4745 from andinus/master
Add Challenge 126
Diffstat (limited to 'challenge-126')
-rw-r--r--challenge-126/andinus/README206
-rw-r--r--challenge-126/andinus/README.org144
-rw-r--r--challenge-126/andinus/blog-1.txt1
-rw-r--r--challenge-126/andinus/blog-2.txt1
-rw-r--r--challenge-126/andinus/c/ch-1.c32
-rw-r--r--challenge-126/andinus/raku/ch-1.raku5
-rw-r--r--challenge-126/andinus/raku/ch-2.raku79
-rw-r--r--challenge-126/andinus/raku/input5
8 files changed, 365 insertions, 108 deletions
diff --git a/challenge-126/andinus/README b/challenge-126/andinus/README
index 796b1d2086..535d2258c5 100644
--- a/challenge-126/andinus/README
+++ b/challenge-126/andinus/README
@@ -1,39 +1,44 @@
━━━━━━━━━━━━━━━
- CHALLENGE 122
+ CHALLENGE 126
Andinus
━━━━━━━━━━━━━━━
- 2021-07-21
+ 2021-08-19
Table of Contents
─────────────────
-Task 1 - Average of Stream
-Task 2 - Basketball Points
+Task 1 - Count Numbers
+Task 2 - Minesweeper Game
-Task 1 - Average of Stream
-══════════════════════════
+Task 1 - Count Numbers
+══════════════════════
- You are given a stream of numbers, `@N'.
+ You are given a positive integer `$N'.
- Write a script to print the average of the stream at every point.
+ Write a script to print count of numbers from 1 to `$N' that don’t
+ contain digit 1.
Example:
┌────
- │ Input: @N = (10, 20, 30, 40, 50, 60, 70, 80, 90, ...)
- │ Output: 10, 15, 20, 25, 30, 35, 40, 45, 50, ...
+ │ Input: $N = 15
+ │ Output: 8
- │ 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.
+ │ There are 8 numbers between 1 and 15 that don't contain digit 1.
+ │ 2, 3, 4, 5, 6, 7, 8, 9.
+ │
+ │ Input: $N = 25
+ │ Output: 13
+ │
+ │ There are 13 numbers between 1 and 25 that don't contain digit 1.
+ │ 2, 3, 4, 5, 6, 7, 8, 9, 20, 22, 23, 24, 25.
└────
@@ -42,18 +47,12 @@ 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.
+ Loop over `1..$N' and grep for numbers that don't have `1'. `hyper'
+ hints the compiler that this can be run in parallel.
┌────
- │ #| 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..$_]});
- │ }
+ │ print .join: ', ' with (1..$N).hyper.grep(*.comb.grep(1).elems == 0);
+ │ put '.';
└────
@@ -62,61 +61,72 @@ 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.
+ `argv' holds the input & `argc' holds the number of inputs. The input
+ should be a single integer so `argc' should be equal to 2. After
+ checking for that, we check if valid integer was passed.
+
+ After checks, we loop over all numbers from 1 to `num' (passed value)
+ and check if they contain digit `1'. The check is performed by
+ converting `num' to a string and matching for '1' in the string. If we
+ find it then we set the flag to false and don't print the number,
+ otherwise we print it.
┌────
- │ 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]);
+ │ if (argc != 2) {
+ │ puts("Usage: ./ch-1 <number>");
+ │ exit(0);
+ │ }
- │ sum += num;
- │ printf("%ld ", sum / idx);
+ │ const char *errstr;
+ │ int num = strtonum(argv[1], 1, INT_MAX, &errstr);
+ │ if (errstr != NULL)
+ │ errx(1, "number is %s: %s", errstr, argv[1]);
+ │
+ │ for (int idx = 1; idx <= num; idx++) {
+ │ bool take = true;
+ │
+ │ int str_size = 1 + snprintf(NULL, 0, "%d", idx);
+ │ char *num_str = calloc(str_size, sizeof(char));
+ │ snprintf(num_str, str_size, "%d", idx);
+ │
+ │ for (int x = 0; num_str[x] != '\0'; x++)
+ │ if (num_str[x] == '1') take = false;
+ │ free(num_str);
+ │
+ │ if (take == true) printf("%d ", idx);
│ }
│ printf("\n");
└────
-Task 2 - Basketball Points
-══════════════════════════
+Task 2 - Minesweeper Game
+═════════════════════════
- You are given a score `$S'.
+ You are given a rectangle with points marked with either x or *.
+ Please consider the x as a land mine.
- You can win basketball points e.g. 1 point, 2 points and 3 points.
+ Write a script to print a rectangle with numbers and x as in the
+ Minesweeper game.
- Write a script to find out the different ways you can score `$S'.
+ A number in a square of the minesweeper game indicates the
+ number of mines within the neighbouring squares (usually
+ 8), also implies that there are no bombs on that square.
Example:
┌────
- │ Input: $S = 4
- │ Output: 1 1 1 1
- │ 1 1 2
- │ 1 2 1
- │ 1 3
- │ 2 1 1
- │ 2 2
- │ 3 1
+ │ Input:
+ │ x * * * x * x x x x
+ │ * * * * * * * * * x
+ │ * * * * x * x * x *
+ │ * * * x x * * * * *
+ │ x * * * x * * * * x
- │ 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
+ │ Output:
+ │ x 1 0 1 x 2 x x x x
+ │ 1 1 0 2 2 4 3 5 5 x
+ │ 0 0 1 3 x 3 x 2 x 2
+ │ 1 1 1 x x 4 1 2 2 2
+ │ x 1 1 3 x 2 0 0 1 x
└────
@@ -125,52 +135,32 @@ 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.
+ `@rect' holds the challenge grids and `@grids' holds the solution. We
+ loop over every cell and if it's not a land mine then we loop over
+ it's neighbors and find the number of neighboring land mines and set
+ it's value.
- Say the score is 3. We have 3 lists like these:
+ The neighbors is returned by `neighbors' subroutine which is adapted
+ from `Octans::Neighbors' (projects/octans) which was adapted from my
+ 2020 AoC day 11's solution.
┌────
- │ 0 0 0
- │ 1 1 1
- │ 2 2 2
- │ 3 3 3
- └────
-
- And cross product will return:
-
- ┌────
- │ 0, 0, 0
- │ 0, 0, 1
- │ 0, 0, 2
- │ 0, 0, 3
- │ 0, 1, 0
- │ ...
- │ 3, 3, 3
- └────
-
- We loop over what the cross product returns and take the list if the
- sum of all elements equals to the score.
-
- ┌────
- │ #| scoring basketball points
- │ unit sub MAIN(Int $score);
+ │ my @rect = $input.IO.lines.map(*.words.cache);
+ │ die "Not rectangle" unless [==] @rect.map(*.elems);
- │ .put for gather for [X] ((0, 1, 2, 3) xx $score) -> @scores {
- │ take @scores if ([+] @scores) == $score;
- │ }.map(*.grep(* !== 0).join).unique.map(*.comb);
+ │ my @grid;
+ │ for 0 .. @rect.end -> $r {
+ │ for 0 .. @rect[$r].end -> $c {
+ │ given @rect[$r][$c] {
+ │ when "x" { @grid[$r][$c] = @rect[$r][$c] }
+ │ when "*" {
+ │ @grid[$r][$c] = 0;
+ │ for neighbors(@rect, $r, $c).List -> $pos {
+ │ @grid[$r][$c]++ if @rect[$pos[0]][$pos[1]] eq "x";
+ │ }
+ │ }
+ │ }
+ │ }
+ │ }
+ │ .put for @grid;
└────
-
- 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.
diff --git a/challenge-126/andinus/README.org b/challenge-126/andinus/README.org
new file mode 100644
index 0000000000..d9408ac98b
--- /dev/null
+++ b/challenge-126/andinus/README.org
@@ -0,0 +1,144 @@
+#+title: Challenge 126
+#+date: 2021-08-19
+#+html_link_up: ../index.html
+#+export_file_name: index
+#+setupfile: ~/.emacs.d/org-templates/level-2.org
+
+* Task 1 - Count Numbers
+
+You are given a positive integer ~$N~.
+
+Write a script to print count of numbers from 1 to ~$N~ that don’t contain
+digit 1.
+
+Example:
+#+begin_src
+Input: $N = 15
+Output: 8
+
+ There are 8 numbers between 1 and 15 that don't contain digit 1.
+ 2, 3, 4, 5, 6, 7, 8, 9.
+
+Input: $N = 25
+Output: 13
+
+ There are 13 numbers between 1 and 25 that don't contain digit 1.
+ 2, 3, 4, 5, 6, 7, 8, 9, 20, 22, 23, 24, 25.
+#+end_src
+
+** Raku
+
+- Program: [[file:raku/ch-1.raku]]
+
+Loop over ~1..$N~ and grep for numbers that don't have ~1~. ~hyper~ hints the
+compiler that this can be run in parallel.
+
+#+begin_src raku
+print .join: ', ' with (1..$N).hyper.grep(*.comb.grep(1).elems == 0);
+put '.';
+#+end_src
+
+** C
+
+- Program: [[file:c/ch-1.c]]
+
+~argv~ holds the input & ~argc~ holds the number of inputs. The input should
+be a single integer so ~argc~ should be equal to 2. After checking for
+that, we check if valid integer was passed.
+
+After checks, we loop over all numbers from 1 to ~num~ (passed value) and
+check if they contain digit ~1~. The check is performed by converting ~num~
+to a string and matching for '1' in the string. If we find it then we
+set the flag to false and don't print the number, otherwise we print it.
+
+#+begin_src c
+if (argc != 2) {
+ puts("Usage: ./ch-1 <number>");
+ exit(0);
+ }
+
+const char *errstr;
+int num = strtonum(argv[1], 1, INT_MAX, &errstr);
+if (errstr != NULL)
+ errx(1, "number is %s: %s", errstr, argv[1]);
+
+for (int idx = 1; idx <= num; idx++) {
+ bool take = true;
+
+ int str_size = 1 + snprintf(NULL, 0, "%d", idx);
+ char *num_str = calloc(str_size, sizeof(char));
+ snprintf(num_str, str_size, "%d", idx);
+
+ for (int x = 0; num_str[x] != '\0'; x++)
+ if (num_str[x] == '1') take = false;
+ free(num_str);
+
+ if (take == true) printf("%d ", idx);
+ }
+printf("\n");
+#+end_src
+
+* Task 2 - Minesweeper Game
+
+You are given a rectangle with points marked with either x or *. Please
+consider the x as a land mine.
+
+Write a script to print a rectangle with numbers and x as in the
+Minesweeper game.
+
+#+begin_quote
+A number in a square of the minesweeper game indicates the number of
+mines within the neighbouring squares (usually 8), also implies that
+there are no bombs on that square.
+#+end_quote
+
+Example:
+#+begin_src
+Input:
+ x * * * x * x x x x
+ * * * * * * * * * x
+ * * * * x * x * x *
+ * * * x x * * * * *
+ x * * * x * * * * x
+
+Output:
+ x 1 0 1 x 2 x x x x
+ 1 1 0 2 2 4 3 5 5 x
+ 0 0 1 3 x 3 x 2 x 2
+ 1 1 1 x x 4 1 2 2 2
+ x 1 1 3 x 2 0 0 1 x
+#+end_src
+
+** Raku
+
+- Program: [[file:raku/ch-2.raku]]
+
+~@rect~ holds the challenge grids and ~@grids~ holds the solution. We loop
+over every cell and if it's not a land mine then we loop over it's
+neighbors and find the number of neighboring land mines and set it's
+value.
+
+The neighbors is returned by ~neighbors~ subroutine which is adapted from
+~Octans::Neighbors~ (projects/octans) which was adapted from my 2020 AoC
+day 11's solution.
+
+#+begin_src raku
+my @rect = $input.IO.lines.map(*.words.cache);
+die "Not rectangle" unless [==] @rect.map(*.elems);
+
+my @grid;
+for 0 .. @rect.end -> $r {
+ for 0 .. @rect[$r].end -> $c {
+ given @rect[$r][$c] {
+ when "x" { @grid[$r][$c] = @rect[$r][$c] }
+ when "*" {
+ @grid[$r][$c] = 0;
+ for neighbors(@rect, $r, $c).List -> $pos {
+ @grid[$r][$c]++ if @rect[$pos[0]][$pos[1]] eq "x";
+ }
+ }
+ }
+ }
+}
+.put for @grid;
+#+end_src
diff --git a/challenge-126/andinus/blog-1.txt b/challenge-126/andinus/blog-1.txt
new file mode 100644
index 0000000000..3225883855
--- /dev/null
+++ b/challenge-126/andinus/blog-1.txt
@@ -0,0 +1 @@
+https://andinus.tilde.institute/pwc/challenge-126/
diff --git a/challenge-126/andinus/blog-2.txt b/challenge-126/andinus/blog-2.txt
new file mode 100644
index 0000000000..3225883855
--- /dev/null
+++ b/challenge-126/andinus/blog-2.txt
@@ -0,0 +1 @@
+https://andinus.tilde.institute/pwc/challenge-126/
diff --git a/challenge-126/andinus/c/ch-1.c b/challenge-126/andinus/c/ch-1.c
new file mode 100644
index 0000000000..c946cfab65
--- /dev/null
+++ b/challenge-126/andinus/c/ch-1.c
@@ -0,0 +1,32 @@
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <limits.h>
+
+int main(int argc, char *argv[]) {
+ if (argc != 2) {
+ puts("Usage: ./ch-1 <number>");
+ exit(0);
+ }
+
+ const char *errstr;
+ int num = strtonum(argv[1], 1, INT_MAX, &errstr);
+ if (errstr != NULL)
+ errx(1, "number is %s: %s", errstr, argv[1]);
+
+ for (int idx = 1; idx <= num; idx++) {
+ bool take = true;
+
+ int str_size = 1 + snprintf(NULL, 0, "%d", idx);
+ char *num_str = calloc(str_size, sizeof(char));
+ snprintf(num_str, str_size, "%d", idx);
+
+ for (int x = 0; num_str[x] != '\0'; x++)
+ if (num_str[x] == '1') take = false;
+ free(num_str);
+
+ if (take == true) printf("%d ", idx);
+ }
+ printf("\n");
+}
diff --git a/challenge-126/andinus/raku/ch-1.raku b/challenge-126/andinus/raku/ch-1.raku
new file mode 100644
index 0000000000..f5b873b95b
--- /dev/null
+++ b/challenge-126/andinus/raku/ch-1.raku
@@ -0,0 +1,5 @@
+#| natural numbers that don't contain digit 1
+sub MAIN(UInt $N where * > 1) {
+ print .join: ', ' with (1..$N).hyper.grep(*.comb.grep(1).elems == 0);
+ put '.';
+}
diff --git a/challenge-126/andinus/raku/ch-2.raku b/challenge-126/andinus/raku/ch-2.raku
new file mode 100644
index 0000000000..a580082f04
--- /dev/null
+++ b/challenge-126/andinus/raku/ch-2.raku
@@ -0,0 +1,79 @@
+#| minesweeper game
+sub MAIN(Str $input where *.IO.f = "input") {
+ my @rect = $input.IO.lines.map(*.words.cache);
+ die "Not rectangle" unless [==] @rect.map(*.elems);
+
+ my @grid;
+ for 0 .. @rect.end -> $r {
+ for 0 .. @rect[$r].end -> $c {
+ given @rect[$r][$c] {
+ when "x" { @grid[$r][$c] = @rect[$r][$c] }
+ when "*" {
+ @grid[$r][$c] = 0;
+ for neighbors(@rect, $r, $c).List -> $pos {
+ @grid[$r][$c]++ if @rect[$pos[0]][$pos[1]] eq "x";
+ }
+ }
+ }
+ }
+ }
+ .put for @grid;
+}
+
+#| neighbors returns the neighbors of given index. Neighbors are
+#| cached in @neighbors array. This way we don't have to compute them
+#| everytime neighbors subroutine is called for the same position.
+sub neighbors(
+ @puzzle, Int $y, Int $x --> List
+) is export {
+ # @directions is holding a list of directions we can move in. It's
+ # used later for neighbors subroutine.
+ # $y, $x
+ state List @directions = (( +1, +0 ), # bottom
+ ( +1, +1 ), # bottom-right
+ ( +1, -1 ), # bottom-left
+ ( -1, +0 ), # top
+ ( -1, +1 ), # top-right
+ ( -1, -1 ), # top-left
+ ( +0, +1 ), # right
+ ( +0, -1 ), # left
+ );
+
+ # @neighbors holds the neighbors of given position.
+ state Array @neighbors;
+
+ if @puzzle[$y][$x] {
+ # Don't re-compute neighbors.
+ unless @neighbors[$y][$x] {
+ # Set it to an empty array because otherwise if it has no
+ # neighbors then it would've be recomputed everytime
+ # neighbors() was called.
+ @neighbors[$y][$x] = [];
+
+ my Int $pos-x;
+ my Int $pos-y;
+
+ # Starting from the intital position of $y, $x we move to
+ # each direction according to the values specified in
+ # @directions array. In this case we're just trying to
+ # move in 4 directions (top, bottom, left & right).
+ direction: for @directions -> $direction {
+ $pos-y = $y + $direction[0];
+ $pos-x = $x + $direction[1];
+
+ # If movement in this direction is out of puzzle grid
+ # boundary then move on to next direction.
+ next direction unless @puzzle[$pos-y][$pos-x];
+
+ # If neighbors exist in this direction then add them
+ # to @neighbors[$y][$x] array.
+ push @neighbors[$y][$x], [$pos-y, $pos-x];
+ }
+ }
+ } else {
+ # If it's out of boundary then return no neighbor.
+ @neighbors[$y][$x] = [];
+ }
+
+ return @neighbors[$y][$x];
+}
diff --git a/challenge-126/andinus/raku/input b/challenge-126/andinus/raku/input
new file mode 100644
index 0000000000..e211219443
--- /dev/null
+++ b/challenge-126/andinus/raku/input
@@ -0,0 +1,5 @@
+x * * * x * x x x x
+* * * * * * * * * x
+* * * * x * x * x *
+* * * x x * * * * *
+x * * * x * * * * x