Skip to content

Commit

Permalink
Raindrops approaches: data-driven programming approach
Browse files Browse the repository at this point in the history
  • Loading branch information
danilopiazza committed Jan 29, 2024
1 parent 13ff1d8 commit 6276b74
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
9 changes: 9 additions & 0 deletions exercises/practice/raindrops/.approaches/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@
"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 exercises/practice/raindrops/.approaches/data-driven/content.md
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
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);
}
}
55 changes: 55 additions & 0 deletions exercises/practice/raindrops/.approaches/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

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

Expand Down Expand Up @@ -97,8 +98,62 @@ This approach uses a single call to the [`sprintf` function][sprintf] to build t
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

0 comments on commit 6276b74

Please sign in to comment.