Skip to content

Commit

Permalink
c/high-scores: 1st iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
vpayno committed Jul 5, 2023
1 parent abb3ab9 commit 13055b6
Show file tree
Hide file tree
Showing 6 changed files with 232 additions and 71 deletions.
1 change: 1 addition & 0 deletions c/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
- [raindrops](./raindrops/README.md)
- [allergies](./allergies/README.md)
- [armstrong-numbers](./armstrong-numbers/README.md)
- [high-scores](./high-scores/README.md)
7 changes: 6 additions & 1 deletion c/high-scores/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,9 @@ The player's game scores can be read from

### Based on

Tribute to the eighties' arcade game Frogger
Tribute to the eighties' arcade game Frogger

### My Solution

- [my solution](./high_scores.c)
- [run-tests](./run-tests-c.txt)
58 changes: 58 additions & 0 deletions c/high-scores/high_scores.c
Original file line number Diff line number Diff line change
@@ -1 +1,59 @@
#include "high_scores.h"

int32_t latest(const int32_t *scores, size_t scores_len) {
if (scores_len == 0) {
return 0;
}

return scores[scores_len - 1];
}

int32_t personal_best(const int32_t *scores, size_t scores_len) {
if (scores_len == 0) {
return 0;
}

int32_t best = scores[0];
for (size_t i = 1; i < scores_len; i++) {
if (best < scores[i]) {
best = scores[i];
}
}

return best;
}

size_t personal_top_three(const int32_t *scores, size_t scores_len,
int32_t *output) {
if (scores_len == 0) {
return 0;
}

int32_t sorted[scores_len];
size_t sorted_len = 0;

memcpy(sorted, scores, sizeof(int) * scores_len);

qsort(sorted, scores_len, sizeof(scores[0]), comparator);

if (scores_len >= 3) {
output[2] = sorted[scores_len - 3];
sorted_len++;
}

if (scores_len >= 2) {
output[1] = sorted[scores_len - 2];
sorted_len++;
}

if (scores_len >= 1) {
output[0] = sorted[scores_len - 1];
sorted_len++;
}

return sorted_len;
}

int32_t comparator(const void *value1, const void *value2) {
return (*(int32_t *)value1 - *(int32_t *)value2);
}
6 changes: 6 additions & 0 deletions c/high-scores/high_scores.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#define MAX_TOP_SCORES 3

/// Return the latest score.
int32_t latest(const int32_t *scores, size_t scores_len);
Expand All @@ -15,4 +19,6 @@ int32_t personal_best(const int32_t *scores, size_t scores_len);
size_t personal_top_three(const int32_t *scores, size_t scores_len,
int32_t *output);

int32_t comparator(const void *value1, const void *value2);

#endif
104 changes: 104 additions & 0 deletions c/high-scores/run-tests-c.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
Running automated test file(s):


===============================================================================

Running: make clean
rm -rf *.o *.out *.out.dSYM

real 0m0.007s
user 0m0.001s
sys 0m0.006s

===============================================================================

Running: make test | ansifilter
Compiling tests.out
test_high_scores.c:81:test_latest_score:PASS
test_high_scores.c:82:test_personal_best:PASS
test_high_scores.c:83:test_personal_top_three_from_a_list_of_scores:PASS
test_high_scores.c:84:test_personal_top_highest_to_lowest:PASS
test_high_scores.c:85:test_personal_top_when_there_is_a_tie:PASS
test_high_scores.c:86:test_personal_top_when_there_are_less_than_3:PASS
test_high_scores.c:87:test_personal_top_when_there_is_only_one:PASS

-----------------------
7 Tests 0 Failures 0 Ignored
OK

real 0m0.132s
user 0m0.088s
sys 0m0.041s

===============================================================================

Running: make memcheck | ansifilter
Compiling memcheck
test_high_scores.c:81:test_latest_score:PASS
test_high_scores.c:82:test_personal_best:PASS
test_high_scores.c:83:test_personal_top_three_from_a_list_of_scores:PASS
test_high_scores.c:84:test_personal_top_highest_to_lowest:PASS
test_high_scores.c:85:test_personal_top_when_there_is_a_tie:PASS
test_high_scores.c:86:test_personal_top_when_there_are_less_than_3:PASS
test_high_scores.c:87:test_personal_top_when_there_is_only_one:PASS

-----------------------
7 Tests 0 Failures 0 Ignored
OK
Memory check passed

real 0m0.135s
user 0m0.098s
sys 0m0.037s

===============================================================================

Running: clang-check-16 ./high_scores.c ./test_high_scores.c ./high_scores.h --

real 0m0.043s
user 0m0.027s
sys 0m0.016s

===============================================================================

Running: clang-tidy-16 ./high_scores.c ./test_high_scores.c ./high_scores.h -checks=*,-llvm-header-guard,-llvmlibc-restrict-system-libc-headers -- | head -n 100
2579 warnings generated.
6383 warnings generated.
8958 warnings generated.
Suppressed 8953 warnings (8953 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well.
/home/vpayno/git_vpayno/exercism-workspace/c/high-scores/high_scores.c:17:5: warning: kernel performance could be improved by unrolling this loop with a '#pragma unroll' directive [altera-unroll-loops]
for (size_t i = 1; i < scores_len; i++) {
^
/home/vpayno/git_vpayno/exercism-workspace/c/high-scores/high_scores.c:35:5: warning: Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11 [clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling]
memcpy(sorted, scores, sizeof(int) * scores_len);
^~~~~~
/home/vpayno/git_vpayno/exercism-workspace/c/high-scores/high_scores.c:35:5: note: Call to function 'memcpy' is insecure as it does not provide security checks introduced in the C11 standard. Replace with analogous functions that support length arguments or provides boundary checks such as 'memcpy_s' in case of C11
memcpy(sorted, scores, sizeof(int) * scores_len);
^~~~~~
/home/vpayno/git_vpayno/exercism-workspace/c/high-scores/test_high_scores.c:5:47: warning: macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
^
( )
/home/vpayno/git_vpayno/exercism-workspace/c/high-scores/test_high_scores.c:7:1: warning: replace macro with enum [modernize-macro-to-enum]
#define TOP_SCORES_ARRAY_SIZE (3)
^~~~~~~~
=
/home/vpayno/git_vpayno/exercism-workspace/c/high-scores/test_high_scores.c:7:9: warning: macro 'TOP_SCORES_ARRAY_SIZE' defines an integral constant; prefer an enum instead [modernize-macro-to-enum]
#define TOP_SCORES_ARRAY_SIZE (3)
^

real 0m0.250s
user 0m0.224s
sys 0m0.026s

===============================================================================

Running: clang-format-16 -style=file -i ./high_scores.c ./test_high_scores.c ./high_scores.h

real 0m0.021s
user 0m0.012s
sys 0m0.009s

===============================================================================

127 changes: 57 additions & 70 deletions c/high-scores/test_high_scores.c
Original file line number Diff line number Diff line change
@@ -1,103 +1,90 @@
#include "test-framework/unity.h"
#include "high_scores.h"
#include "test-framework/unity.h"
#include <string.h>

#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0]))

#define TOP_SCORES_ARRAY_SIZE (3)

void setUp(void)
{
}
void setUp(void) {}

void tearDown(void)
{
}
void tearDown(void) {}

static void check_personal_top_three(const int32_t *scores, size_t scores_len,
const int32_t *expected,
size_t expected_len)
{
int32_t top_scores[TOP_SCORES_ARRAY_SIZE] = { 0 };
size_t expected_len) {
int32_t top_scores[TOP_SCORES_ARRAY_SIZE] = {0};

size_t actual_len = personal_top_three(scores, scores_len, top_scores);
size_t actual_len = personal_top_three(scores, scores_len, top_scores);

TEST_ASSERT_EQUAL_INT32(expected_len, actual_len);
TEST_ASSERT_EQUAL_INT32(expected_len, actual_len);

if (expected_len > 0) {
TEST_ASSERT_EQUAL_INT32_ARRAY(expected, top_scores, expected_len);
}
if (expected_len > 0) {
TEST_ASSERT_EQUAL_INT32_ARRAY(expected, top_scores, expected_len);
}
}

static void test_latest_score(void)
{
const int scores[] = { 100, 0, 90, 30 };
TEST_ASSERT_EQUAL_INT(latest(scores, ARRAY_SIZE(scores)), 30);
static void test_latest_score(void) {
const int scores[] = {100, 0, 90, 30};
TEST_ASSERT_EQUAL_INT(latest(scores, ARRAY_SIZE(scores)), 30);
}

static void test_personal_best(void)
{
TEST_IGNORE(); // delete this line to run test
const int scores[] = { 40, 100, 70 };
TEST_ASSERT_EQUAL_INT(personal_best(scores, ARRAY_SIZE(scores)), 100);
static void test_personal_best(void) {
// TEST_IGNORE(); // delete this line to run test
const int scores[] = {40, 100, 70};
TEST_ASSERT_EQUAL_INT(personal_best(scores, ARRAY_SIZE(scores)), 100);
}

static void test_personal_top_three_from_a_list_of_scores(void)
{
TEST_IGNORE();
const int scores[] = { 10, 30, 90, 30, 100, 20, 10, 0, 30, 40, 40, 70, 70 };
const int expected[] = { 100, 90, 70 };
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
static void test_personal_top_three_from_a_list_of_scores(void) {
// TEST_IGNORE();
const int scores[] = {10, 30, 90, 30, 100, 20, 10, 0, 30, 40, 40, 70, 70};
const int expected[] = {100, 90, 70};
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
}

static void test_personal_top_highest_to_lowest(void)
{
TEST_IGNORE();
const int scores[] = { 20, 10, 30 };
const int expected[] = { 30, 20, 10 };
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
static void test_personal_top_highest_to_lowest(void) {
// TEST_IGNORE();
const int scores[] = {20, 10, 30};
const int expected[] = {30, 20, 10};
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
}

static void test_personal_top_when_there_is_a_tie(void)
{
TEST_IGNORE();
const int scores[] = { 40, 20, 40, 30 };
const int expected[] = { 40, 40, 30 };
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
static void test_personal_top_when_there_is_a_tie(void) {
// TEST_IGNORE();
const int scores[] = {40, 20, 40, 30};
const int expected[] = {40, 40, 30};
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
}

static void test_personal_top_when_there_are_less_than_3(void)
{
TEST_IGNORE();
const int scores[] = { 30, 70 };
const int expected[] = { 70, 30 };
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
static void test_personal_top_when_there_are_less_than_3(void) {
// TEST_IGNORE();
const int scores[] = {30, 70};
const int expected[] = {70, 30};
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
}

static void test_personal_top_when_there_is_only_one(void)
{
TEST_IGNORE();
const int scores[] = { 40 };
const int expected[] = { 40 };
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
static void test_personal_top_when_there_is_only_one(void) {
// TEST_IGNORE();
const int scores[] = {40};
const int expected[] = {40};
check_personal_top_three(scores, ARRAY_SIZE(scores), expected,
ARRAY_SIZE(expected));
}

int main(void)
{
UnityBegin("test_high_scores.c");
int main(void) {
UnityBegin("test_high_scores.c");

RUN_TEST(test_latest_score);
RUN_TEST(test_personal_best);
RUN_TEST(test_personal_top_three_from_a_list_of_scores);
RUN_TEST(test_personal_top_highest_to_lowest);
RUN_TEST(test_personal_top_when_there_is_a_tie);
RUN_TEST(test_personal_top_when_there_are_less_than_3);
RUN_TEST(test_personal_top_when_there_is_only_one);
RUN_TEST(test_latest_score);
RUN_TEST(test_personal_best);
RUN_TEST(test_personal_top_three_from_a_list_of_scores);
RUN_TEST(test_personal_top_highest_to_lowest);
RUN_TEST(test_personal_top_when_there_is_a_tie);
RUN_TEST(test_personal_top_when_there_are_less_than_3);
RUN_TEST(test_personal_top_when_there_is_only_one);

return UnityEnd();
return UnityEnd();
}

0 comments on commit 13055b6

Please sign in to comment.