Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add sum-of-multiples exercise #103

Merged
merged 1 commit into from
Nov 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,14 @@
"prerequisites": [],
"difficulty": 3
},
{
"slug": "sum-of-multiples",
"name": "Sum of Multiples",
"uuid": "d9228f0d-816b-46eb-8ca7-dbc8cd9f782d",
"practices": [],
"prerequisites": [],
"difficulty": 3
},
{
"slug": "triangle",
"name": "Triangle",
Expand Down
2 changes: 1 addition & 1 deletion exercises/practice/diamond/diamond_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#define BUFFER_SIZE 3200

void rows(char *buffer, char letter);
extern void rows(char *buffer, char letter);

void setUp(void) {
}
Expand Down
2 changes: 1 addition & 1 deletion exercises/practice/rectangles/rectangles_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <stddef.h>

int rectangles(const char **strings);
extern int rectangles(const char **strings);

void setUp(void) {
}
Expand Down
27 changes: 27 additions & 0 deletions exercises/practice/sum-of-multiples/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Instructions

Your task is to write the code that calculates the energy points that get awarded to players when they complete a level.

The points awarded depend on two things:

- The level (a number) that the player completed.
- The base value of each magical item collected by the player during that level.

The energy points are awarded according to the following rules:

1. For each magical item, take the base value and find all the multiples of that value that are less than the level number.
2. Combine the sets of numbers.
3. Remove any duplicates.
4. Calculate the sum of all the numbers that are left.

Let's look at an example:

**The player completed level 20 and found two magical items with base values of 3 and 5.**

To calculate the energy points earned by the player, we need to find all the unique multiples of these base values that are less than level 20.

- Multiples of 3 less than 20: `{3, 6, 9, 12, 15, 18}`
- Multiples of 5 less than 20: `{5, 10, 15}`
- Combine the sets and remove duplicates: `{3, 5, 6, 9, 10, 12, 15, 18}`
- Sum the unique multiples: `3 + 5 + 6 + 9 + 10 + 12 + 15 + 18 = 78`
- Therefore, the player earns **78** energy points for completing level 20 and finding the two magical items with base values of 3 and 5.
6 changes: 6 additions & 0 deletions exercises/practice/sum-of-multiples/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Introduction

You work for a company that makes an online, fantasy-survival game.

When a player finishes a level, they are awarded energy points.
The amount of energy awarded depends on which magical items the player found while exploring that level.
19 changes: 19 additions & 0 deletions exercises/practice/sum-of-multiples/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"keiravillekode"
],
"files": {
"solution": [
"sum_of_multiples.s"
],
"test": [
"sum_of_multiples_test.c"
],
"example": [
".meta/example.s"
]
},
"blurb": "Given a number, find the sum of all the multiples of particular numbers up to but not including that number.",
"source": "A variation on Problem 1 at Project Euler",
"source_url": "https://projecteuler.net/problem=1"
}
31 changes: 31 additions & 0 deletions exercises/practice/sum-of-multiples/.meta/example.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.text
.globl sum

/* extern uint64_t sum(uint64_t limit, const uint64_t *factors, size_t factor_count); */
sum:
lsl x2, x2, #3 /* size of factors array, in bytes */
add x2, x1, x2 /* end of factors array */
mov x3, x0
mov x0, xzr /* initialize total */
cbz x3, .return

.next_number:
sub x3, x3, #1 /* number to check */
cbz x3, .return

mov x4, x1

.next_factor:
cmp x4, x2
beq .next_number

ldr x5, [x4], #8 /* load factor, post-increment */
udiv x6, x3, x5 /* quotient */
msub x7, x6, x5, x3 /* remainder */
cbnz x7, .next_factor

add x0, x0, x3 /* number x3 is a multiple of factor x5 */
b .next_number

.return:
ret
58 changes: 58 additions & 0 deletions exercises/practice/sum-of-multiples/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# This is an auto-generated file.
#
# Regenerating this file via `configlet sync` will:
# - Recreate every `description` key/value pair
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
# - Preserve any other key/value pair
#
# As user-added comments (using the # character) will be removed when this file
# is regenerated, comments can be added via a `comment` key.

[54aaab5a-ce86-4edc-8b40-d3ab2400a279]
description = "no multiples within limit"

[361e4e50-c89b-4f60-95ef-5bc5c595490a]
description = "one factor has multiples within limit"

[e644e070-040e-4ae0-9910-93c69fc3f7ce]
description = "more than one multiple within limit"

[607d6eb9-535c-41ce-91b5-3a61da3fa57f]
description = "more than one factor with multiples within limit"

[f47e8209-c0c5-4786-b07b-dc273bf86b9b]
description = "each multiple is only counted once"

[28c4b267-c980-4054-93e9-07723db615ac]
description = "a much larger limit"

[09c4494d-ff2d-4e0f-8421-f5532821ee12]
description = "three factors"

[2d0d5faa-f177-4ad6-bde9-ebb865083751]
description = "factors not relatively prime"

[ece8f2e8-96aa-4166-bbb7-6ce71261e354]
description = "some pairs of factors relatively prime and some not"

[624fdade-6ffb-400e-8472-456a38c171c0]
description = "one factor is a multiple of another"

[949ee7eb-db51-479c-b5cb-4a22b40ac057]
description = "much larger factors"

[41093673-acbd-482c-ab80-d00a0cbedecd]
description = "all numbers are multiples of 1"

[1730453b-baaa-438e-a9c2-d754497b2a76]
description = "no factors means an empty sum"

[214a01e9-f4bf-45bb-80f1-1dce9fbb0310]
description = "the only multiple of 0 is 0"

[c423ae21-a0cb-4ec7-aeb1-32971af5b510]
description = "the factor 0 does not affect the sum of multiples of other factors"

[17053ba9-112f-4ac0-aadb-0519dd836342]
description = "solutions using include-exclude must extend to cardinality greater than 3"
36 changes: 36 additions & 0 deletions exercises/practice/sum-of-multiples/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
AS = aarch64-linux-gnu-as
CC = aarch64-linux-gnu-gcc

CFLAGS = -g -Wall -Wextra -pedantic -Werror
LDFLAGS =

ALL_LDFLAGS = -pie -Wl,--fatal-warnings

ALL_CFLAGS = -std=c99 -fPIE $(CFLAGS)
ALL_LDFLAGS += $(LDFLAGS)

C_OBJS = $(patsubst %.c,%.o,$(wildcard *.c))
AS_OBJS = $(patsubst %.s,%.o,$(wildcard *.s))
ALL_OBJS = $(filter-out example.o,$(C_OBJS) $(AS_OBJS) vendor/unity.o)

CC_CMD = $(CC) $(ALL_CFLAGS) -c -o $@ $<

all: tests
qemu-aarch64 -L /usr/aarch64-linux-gnu ./$<

tests: $(ALL_OBJS)
@$(CC) $(ALL_CFLAGS) $(ALL_LDFLAGS) -o $@ $(ALL_OBJS)

%.o: %.s
@$(AS) -o $@ $<

%.o: %.c
@$(CC_CMD)

vendor/unity.o: vendor/unity.c vendor/unity.h vendor/unity_internals.h
@$(CC_CMD)

clean:
@rm -f *.o vendor/*.o tests

.PHONY: all clean
5 changes: 5 additions & 0 deletions exercises/practice/sum-of-multiples/sum_of_multiples.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.text
.globl sum

sum:
ret
129 changes: 129 additions & 0 deletions exercises/practice/sum-of-multiples/sum_of_multiples_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#include "vendor/unity.h"

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

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

extern uint64_t sum(uint64_t limit, const uint64_t *factors, size_t factor_count);

void setUp(void) {
}

void tearDown(void) {
}

void test_no_multiples_within_limit(void) {
const uint64_t factors[] = {3, 5};
TEST_ASSERT_EQUAL_UINT64(0, sum(1, factors, ARRAY_SIZE(factors)));
}

void test_one_factor_has_multiples_within_limit(void) {
TEST_IGNORE();
const uint64_t factors[] = {3, 5};
TEST_ASSERT_EQUAL_UINT64(3, sum(4, factors, ARRAY_SIZE(factors)));
}

void test_more_than_one_multiple_within_limit(void) {
TEST_IGNORE();
const uint64_t factors[] = {3};
TEST_ASSERT_EQUAL_UINT64(9, sum(7, factors, ARRAY_SIZE(factors)));
}

void test_more_than_one_factor_with_multiples_within_limit(void) {
TEST_IGNORE();
const uint64_t factors[] = {3, 5};
TEST_ASSERT_EQUAL_UINT64(23, sum(10, factors, ARRAY_SIZE(factors)));
}

void test_each_multiple_is_only_counted_once(void) {
TEST_IGNORE();
const uint64_t factors[] = {3, 5};
TEST_ASSERT_EQUAL_UINT64(2318, sum(100, factors, ARRAY_SIZE(factors)));
}

void test_a_much_larger_limit(void) {
TEST_IGNORE();
const uint64_t factors[] = {3, 5};
TEST_ASSERT_EQUAL_UINT64(233168, sum(1000, factors, ARRAY_SIZE(factors)));
}

void test_three_factors(void) {
TEST_IGNORE();
const uint64_t factors[] = {7, 13, 17};
TEST_ASSERT_EQUAL_UINT64(51, sum(20, factors, ARRAY_SIZE(factors)));
}

void test_factors_not_relatively_prime(void) {
TEST_IGNORE();
const uint64_t factors[] = {4, 6};
TEST_ASSERT_EQUAL_UINT64(30, sum(15, factors, ARRAY_SIZE(factors)));
}

void test_some_pairs_of_factors_relatively_prime_and_some_not(void) {
TEST_IGNORE();
const uint64_t factors[] = {5, 6, 8};
TEST_ASSERT_EQUAL_UINT64(4419, sum(150, factors, ARRAY_SIZE(factors)));
}

void test_one_factor_is_a_multiple_of_another(void) {
TEST_IGNORE();
const uint64_t factors[] = {5, 25};
TEST_ASSERT_EQUAL_UINT64(275, sum(51, factors, ARRAY_SIZE(factors)));
}

void test_much_larger_factors(void) {
TEST_IGNORE();
const uint64_t factors[] = {43, 47};
TEST_ASSERT_EQUAL_UINT64(2203160, sum(10000, factors, ARRAY_SIZE(factors)));
}

void test_all_numbers_are_multiples_of_1(void) {
TEST_IGNORE();
const uint64_t factors[] = {1};
TEST_ASSERT_EQUAL_UINT64(4950, sum(100, factors, ARRAY_SIZE(factors)));
}

void test_no_factors_means_an_empty_sum(void) {
TEST_IGNORE();
TEST_ASSERT_EQUAL_UINT64(0, sum(10000, NULL, 0));
}

void test_the_only_multiple_of_0_is_0(void) {
TEST_IGNORE();
const uint64_t factors[] = {0};
TEST_ASSERT_EQUAL_UINT64(0, sum(1, factors, ARRAY_SIZE(factors)));
}

void test_the_factor_0_does_not_affect_the_sum_of_multiples_of_other_factors(void) {
TEST_IGNORE();
const uint64_t factors[] = {3, 0};
TEST_ASSERT_EQUAL_UINT64(3, sum(4, factors, ARRAY_SIZE(factors)));
}

void test_solutions_using_includeexclude_must_extend_to_cardinality_greater_than_3(void) {
TEST_IGNORE();
const uint64_t factors[] = {2, 3, 5, 7, 11};
TEST_ASSERT_EQUAL_UINT64(39614537, sum(10000, factors, ARRAY_SIZE(factors)));
}

int main(void) {
UNITY_BEGIN();
RUN_TEST(test_no_multiples_within_limit);
RUN_TEST(test_one_factor_has_multiples_within_limit);
RUN_TEST(test_more_than_one_multiple_within_limit);
RUN_TEST(test_more_than_one_factor_with_multiples_within_limit);
RUN_TEST(test_each_multiple_is_only_counted_once);
RUN_TEST(test_a_much_larger_limit);
RUN_TEST(test_three_factors);
RUN_TEST(test_factors_not_relatively_prime);
RUN_TEST(test_some_pairs_of_factors_relatively_prime_and_some_not);
RUN_TEST(test_one_factor_is_a_multiple_of_another);
RUN_TEST(test_much_larger_factors);
RUN_TEST(test_all_numbers_are_multiples_of_1);
RUN_TEST(test_no_factors_means_an_empty_sum);
RUN_TEST(test_the_only_multiple_of_0_is_0);
RUN_TEST(test_the_factor_0_does_not_affect_the_sum_of_multiples_of_other_factors);
RUN_TEST(test_solutions_using_includeexclude_must_extend_to_cardinality_greater_than_3);
return UNITY_END();
}
Loading