-
-
Notifications
You must be signed in to change notification settings - Fork 182
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Raindrops approach: introduction * Raindrops approaches: if statements approach * Raindrops approaches: sprintf function approach * Raindrops approaches: data-driven programming approach * Apply suggestions from code review --------- Co-authored-by: Ryan Hartlage <[email protected]>
- Loading branch information
1 parent
4e49d3b
commit 39c890b
Showing
8 changed files
with
375 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{ | ||
"introduction": { | ||
"authors": [ | ||
"danilopiazza" | ||
] | ||
}, | ||
"approaches": [ | ||
{ | ||
"uuid": "830f6fb9-cd91-4c53-8b73-cbcb4585ad51", | ||
"slug": "if-statements", | ||
"title": "if Statements", | ||
"blurb": "Use multiple if statements.", | ||
"authors": [ | ||
"danilopiazza" | ||
] | ||
}, | ||
{ | ||
"uuid": "cac9cf42-cd7b-4070-8f86-5a9753d17d8e", | ||
"slug": "sprintf", | ||
"title": "sprintf Function", | ||
"blurb": "Use the sprintf function.", | ||
"authors": [ | ||
"danilopiazza" | ||
] | ||
}, | ||
{ | ||
"uuid": "ec393164-0222-4bed-9234-fc25755d8746", | ||
"slug": "data-driven", | ||
"title": "Data-Driven Programming", | ||
"blurb": "Use data-driven programming.", | ||
"authors": [ | ||
"danilopiazza" | ||
] | ||
} | ||
] | ||
} |
68 changes: 68 additions & 0 deletions
68
exercises/practice/raindrops/.approaches/data-driven/content.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
# Data-Driven Programming | ||
|
||
**raindrops.h** | ||
|
||
```c | ||
#ifndef RAINDROPS_H | ||
#define RAINDROPS_H | ||
|
||
char *convert(char result[], int drops); | ||
|
||
#endif | ||
``` | ||
|
||
**raindrops.c** | ||
|
||
```c | ||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
typedef struct { | ||
int factor; | ||
const char *sound; | ||
} sound_t; | ||
|
||
static const sound_t SOUNDS[] = { | ||
{ 3, "Pling" }, | ||
{ 5, "Plang" }, | ||
{ 7, "Plong" }, | ||
}; | ||
|
||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) | ||
|
||
char *convert(char result[], int drops) | ||
{ | ||
for (size_t i = 0; i < ARRAY_SIZE(SOUNDS); i++) { | ||
if (drops % SOUNDS[i].factor == 0) { | ||
strcat(result, SOUNDS[i].sound); | ||
} | ||
} | ||
|
||
if (strlen(result) == 0) { | ||
sprintf(result, "%d", drops); | ||
} | ||
|
||
return result; | ||
} | ||
``` | ||
First, the program defines a [structure][struct] [data type][typedef] to hold together two pieces of information: a factor and its corresponding sound. | ||
Then, an array is created to hold all the necessary data, which is used to drive the logc of the program. | ||
The body of the function does not have any knowledge of the actual data, becoming simple and flexible: | ||
- For each element of the `SOUNDS` array | ||
-- If the given number is a multiple of the current `factor` | ||
--- Then concatenate the current `sound` to the result string using the [`strcat` function][strcat]. | ||
This approach allows for extensible code: for example, new sounds could be added (or removed) without modifying the `convert` function. | ||
Finally, the [`strlen` function] checks if `result` is empty: if so, the [`sprintf` function] formats `drops` as string into `result`. | ||
[struct]: https://www.geeksforgeeks.org/structures-c/ | ||
[typedef]: https://www.geeksforgeeks.org/typedef-in-c/ | ||
[strcat]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/strcat.html | ||
[strlen]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html | ||
[sprintf]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sprintf.html |
5 changes: 5 additions & 0 deletions
5
exercises/practice/raindrops/.approaches/data-driven/snippet.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
for (size_t i = 0; i < ARRAY_SIZE(SOUNDS); i++) { | ||
if (drops % SOUNDS[i].factor == 0) { | ||
strcat(result, SOUNDS[i].sound); | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
exercises/practice/raindrops/.approaches/if-statements/content.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
# `if` Statements | ||
|
||
**raindrops.h** | ||
|
||
```c | ||
#ifndef RAINDROPS_H | ||
#define RAINDROPS_H | ||
|
||
char *convert(char result[], int drops); | ||
|
||
#endif | ||
``` | ||
|
||
**raindrops.c** | ||
|
||
```c | ||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
char *convert(char result[], int drops) | ||
{ | ||
if (drops % 3 == 0) | ||
strcat(result, "Pling"); | ||
if (drops % 5 == 0) | ||
strcat(result, "Plang"); | ||
if (drops % 7 == 0) | ||
strcat(result, "Plong"); | ||
|
||
if (strlen(result) == 0) | ||
sprintf(result, "%d", drops); | ||
|
||
return result; | ||
} | ||
``` | ||
- The first `if` statement checks if `drops` is a multiple of `3`. | ||
If so, `"Pling"` is concatenated to `result` using the [`strcat` function][strcat]. | ||
- The second `if` statement checks if `drops` is a multiple of `5`. | ||
If so, `"Plang"` is concatenated to `result` using the [`strcat` function][strcat]. | ||
- The thrd `if` statement checks if `drops` is a multiple of `7`. | ||
If so, `"Plong"` is concatenated to `result` using the [`strcat` function][strcat]. | ||
Finally, the [`strlen` function] checks if `result` is empty: if so, the [`sprintf` function] formats `drops` as string into `result`. | ||
[strcat]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/strcat.html | ||
[strlen]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html | ||
[sprintf]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sprintf.html |
6 changes: 6 additions & 0 deletions
6
exercises/practice/raindrops/.approaches/if-statements/snippet.txt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
if (drops % 3 == 0) | ||
strcat(result, "Pling"); | ||
if (drops % 5 == 0) | ||
strcat(result, "Plang"); | ||
if (drops % 7 == 0) | ||
strcat(result, "Plong"); |
159 changes: 159 additions & 0 deletions
159
exercises/practice/raindrops/.approaches/introduction.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
# Introduction | ||
|
||
There are various idioomatic ways to solve Raindrops. | ||
A straightforward and approach is to use a series of `if` statements. | ||
Another approach could look up both factors and raindrop sounds from an array, using data-driven programming to make the code as simple as possible. | ||
|
||
## General Guidance | ||
|
||
The key to solving Raindrops is to know if the input is evenly divisible by `3`, `5` and/or `7` using the [modulo operator][modulo-operator]. | ||
|
||
## Assumptions | ||
|
||
- `drops` is a non-negative, 32-bit integer (from `0` to `2,147,483,647`). | ||
- `result` has enough space to hold the largest output string, meaning 16 bytes: | ||
- 15 bytes for `"PlingPlangPlong"`, plus one for the null terminating character; | ||
- 10 bytes for the largest possible value of `drops`, plus one for `'\0'`. | ||
- `result` has been initialized as an empty string (that is, `result[0]` is `'\0'`). | ||
|
||
## Approach: `if` Statements | ||
|
||
**raindrops.h** | ||
|
||
```c | ||
#ifndef RAINDROPS_H | ||
#define RAINDROPS_H | ||
|
||
char *convert(char result[], int drops); | ||
|
||
#endif | ||
``` | ||
|
||
**raindrops.c** | ||
|
||
```c | ||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
char *convert(char result[], int drops) | ||
{ | ||
if (drops % 3 == 0) | ||
strcat(result, "Pling"); | ||
if (drops % 5 == 0) | ||
strcat(result, "Plang"); | ||
if (drops % 7 == 0) | ||
strcat(result, "Plong"); | ||
|
||
if (strlen(result) == 0) | ||
sprintf(result, "%d", drops); | ||
|
||
return result; | ||
} | ||
``` | ||
This approach uses a series of `if`-statements and string concatentation to build up the result string. | ||
For more information, check the [`if` statements approach][approach-if-statements]. | ||
## Approach: `sprintf` Function | ||
**raindrops.h** | ||
```c | ||
#ifndef RAINDROPS_H | ||
#define RAINDROPS_H | ||
char *convert(char result[], int drops); | ||
#endif | ||
``` | ||
|
||
**raindrops.c** | ||
|
||
```c | ||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
char *convert(char result[], int drops) | ||
{ | ||
sprintf(result, "%s%s%s", drops % 3 == 0 ? "Pling" : "", | ||
drops % 5 == 0 ? "Plang" : "", drops % 7 == 0 ? "Plong" : ""); | ||
|
||
if (strlen(result) == 0) | ||
sprintf(result, "%d", drops); | ||
|
||
return result; | ||
} | ||
``` | ||
This approach uses a single call to the [`sprintf` function][sprintf] to build the result string; | ||
it contains a series of [ternary conditional operators][conditional-opeator]. | ||
For more information, check the [`sprintf` functon approach][approach-sprintf]. | ||
## Approach: Data-Driven Programming | ||
**raindrops.h** | ||
```c | ||
#ifndef RAINDROPS_H | ||
#define RAINDROPS_H | ||
char *convert(char result[], int drops); | ||
#endif | ||
``` | ||
|
||
**raindrops.c** | ||
|
||
```c | ||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
typedef struct { | ||
int factor; | ||
const char *sound; | ||
} sound_t; | ||
|
||
static const sound_t SOUNDS[] = { | ||
{ 3, "Pling" }, | ||
{ 5, "Plang" }, | ||
{ 7, "Plong" }, | ||
}; | ||
|
||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) | ||
|
||
char *convert(char result[], int drops) | ||
{ | ||
for (size_t i = 0; i < ARRAY_SIZE(SOUNDS); i++) { | ||
if (drops % SOUNDS[i].factor == 0) { | ||
strcat(result, SOUNDS[i].sound); | ||
} | ||
} | ||
|
||
if (strlen(result) == 0) { | ||
sprintf(result, "%d", drops); | ||
} | ||
|
||
return result; | ||
} | ||
``` | ||
This approach puts some of the logic into data, simplifying the code. | ||
For more information, check the [data-driven approach][approach-data-driven]. | ||
[modulo-operator]: https://www.geeksforgeeks.org/modulo-operator-in-c-cpp-with-examples/ | ||
[conditional-operator]: https://www.geeksforgeeks.org/conditional-or-ternary-operator-in-c/ | ||
[sprintf]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sprintf.html | ||
[approach-if-statements]: https://exercism.org/tracks/c/exercises/raindrops/approaches/if-statements | ||
[approach-sprintf]: https://exercism.org/tracks/c/exercises/raindrops/approaches/sprintf | ||
[approach-data-driven]: https://exercism.org/tracks/c/exercises/raindrops/approaches/data-driven |
50 changes: 50 additions & 0 deletions
50
exercises/practice/raindrops/.approaches/sprintf/content.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
## `sprintf` Function | ||
|
||
**raindrops.h** | ||
|
||
```c | ||
#ifndef RAINDROPS_H | ||
#define RAINDROPS_H | ||
|
||
char *convert(char result[], int drops); | ||
|
||
#endif | ||
``` | ||
|
||
**raindrops.c** | ||
|
||
```c | ||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
#include "raindrops.h" | ||
|
||
#include <stdio.h> | ||
#include <string.h> | ||
|
||
char *convert(char result[], int drops) | ||
{ | ||
sprintf(result, "%s%s%s", drops % 3 == 0 ? "Pling" : "", | ||
drops % 5 == 0 ? "Plang" : "", drops % 7 == 0 ? "Plong" : ""); | ||
|
||
if (strlen(result) == 0) | ||
sprintf(result, "%d", drops); | ||
|
||
return result; | ||
} | ||
``` | ||
This approach allows for very concise, if not a bit obfuscated, code. | ||
A series of [ternary conditional operators][conditional-operator] check if `drops` is a multiple of `3`, `5`, or `7` respectively. | ||
If it is, the expression returns the appropriate raindrop sound (either `"Pling"`, `"Plang"` or `"Plong"`); otherwise, the result is the empty string (`""`). | ||
Then, in the same statement, a single call to the [`sprintf` function][sprintf] concatenates all the above three strings. | ||
Finally, the [`strlen` function][strlen] checks if `result` is empty: if so, `sprintf` is used again to format `drops` as string into `result`. | ||
[conditional-operator]: https://www.geeksforgeeks.org/conditional-or-ternary-operator-in-c/ | ||
[sprintf]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/sprintf.html | ||
[strlen]: https://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
sprintf(result, "%s%s%s", drops % 3 == 0 ? "Pling" : "", | ||
drops % 5 == 0 ? "Plang" : "", drops % 7 == 0 ? "Plong" : ""); |