Add sum-of-multiples exercise (#150)

This commit is contained in:
Erik Schierboom
2024-04-26 14:01:33 +02:00
committed by GitHub
parent e9543b39cf
commit 77458fd9d0
9 changed files with 379 additions and 0 deletions

View File

@@ -300,6 +300,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 3
},
{
"slug": "sum-of-multiples",
"name": "Sum of Multiples",
"uuid": "ba8ff915-21eb-4372-838b-7fb456d27fa8",
"practices": [],
"prerequisites": [],
"difficulty": 3
}
]
},

View File

@@ -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.

View File

@@ -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.

View File

@@ -0,0 +1,19 @@
{
"authors": [
"erikschierboom"
],
"files": {
"solution": [
"sum-of-multiples.8th"
],
"test": [
"test.8th"
],
"example": [
".meta/example.8th"
]
},
"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"
}

View File

@@ -0,0 +1,7 @@
: multiples \ n n -- n
dup 0 n:> if 2dup ( const r> swap a:push >r dup step ) -rot swap loop then
;
: sum \ a n -- n
a:new >r n:1- swap ' multiples a:map 2drop r> ' n:cmp a:sort ' n:= a:uniq ' n:+ 0 a:reduce
;

View File

@@ -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"

View File

@@ -0,0 +1,162 @@
needs console/loaded
\ -----------------------------------------------------------------
ns: test
-1 var, test-count
var tests-passed
var tests-failed
var tests-skipped
true var, run-test
\ Some utility words
: array-insens-dot \ x -- \\ removes leading space on stringified arrays
dup >kind ns:a n:=
if
>s s:trim
then
.
;
: test-passed \ s x x -- \\ test name, expected value, actual value
2drop
1 tests-passed n:+!
con:green con:onBlack . space " ... OK" . con:white con:onBlack cr
;
: test-skipped \ s --
1 tests-skipped n:+!
con:cyan con:onBlack . space " ... SKIPPED" . con:white con:onBlack cr
;
: test-failed \ s x x -- \\ test name, expected value, actual value
1 tests-failed n:+!
rot
con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr
" Actual: «" . array-insens-dot "»" . cr
" Expected: «" . array-insens-dot "»" . cr cr
;
: isword? \ x -- x f
dup >kind ns:w n:=
;
: run-test? \ -- T
run-test @ if true else "RUN_ALL_TESTS" getenv n:>bool then
;
\ Num passed + num skipped + num failed should == num tests
: all-tests-run? \ -- T
tests-passed @ tests-skipped @ tests-failed @ n:+ n:+
test-count @ n:=
;
\ returns true if x is a date, false otherwise
: date? \ x -- x T
dup >kind ns:d n:=
;
\ adapted from 8th forum -- https://8th-dev.com/forum/index.php/topic,2745.0.html
: eq? \ x x -- T
\ are the items the same kind?
2dup >kind swap >kind n:=
!if 2drop false ;then
\ same kind: try different comparators
number? if n:= ;then
string? if s:= ;then
array? if ' eq? a:= 2nip ;then
map? if ' eq? m:= 2nip ;then
date? if d:= ;then
\ otherwise fall back to 'lazy evaluation'
l: =
;
: check-depth \ ... n -- ...
dup>r
n:1+ depth n:=
!if
con:red con:onBlack
"PANIC: expected stack depth to be " . r> . cr
"Stack is:" . cr
.s cr
255 die
then
rdrop
;
\ -----------------------------------------------------------------
\ status report at end of run
( all-tests-run?
!if con:red con:onBlack "... FAIL - not all tests completed" . con:white con:onBlack cr then
) onexit
\ Print a summary of the tests run
( con:white con:onBlack
test-count @ . space "tests planned - " .
tests-passed @ . space "passed - " .
tests-skipped @ . space "skipped - " .
tests-failed @ . space "failed" . cr
) onexit
\ -----------------------------------------------------------------
\ The public-facing words
\ -----------------------------------------------------------------
: equal? \ s x w -- | s w x --
run-test? !if 2drop test-skipped ;; then
isword? !if swap then
w:exec
3 check-depth
2dup \ so test-failed can show actual and expected
eq? if test-passed else test-failed then
;
: true? \ s w --
run-test? !if drop test-skipped ;; then
w:exec
2 check-depth
true swap dup \ so test-failed can show actual and expected
if test-passed else test-failed then
;
: false? \ s w --
run-test? !if drop test-skipped ;; then
w:exec
2 check-depth
false swap dup \ so test-failed can show actual and expected
!if test-passed else test-failed then
;
: null? \ s w --
run-test? !if drop test-skipped ;; then
w:exec
2 check-depth
null swap dup \ so test-failed can show actual and expected
G:null? nip if test-passed else test-failed then
;
: SKIP-REST-OF-TESTS false run-test ! ;
: tests \ n --
test-count !
;
\ Set the exit status:
\ 0 = all OK
\ 1 = not all tests were run (some error occurred)
\ 2 = some tests failed
: end-of-tests \ --
all-tests-run?
if
tests-failed @ 0 n:= if 0 else 2 then
else
1
then
die
;

View File

@@ -0,0 +1,3 @@
: sum \ a n -- n
;

View File

@@ -0,0 +1,89 @@
"sum-of-multiples.8th" f:include
needs exercism/test
with: test
16 tests
"no multiples within limit"
( [3,5] 1 sum )
0
equal?
SKIP-REST-OF-TESTS
"one factor has multiples within limit"
( [3,5] 4 sum )
3
equal?
"more than one multiple within limit"
( [3] 7 sum )
9
equal?
"more than one factor with multiples within limit"
( [3,5] 10 sum )
23
equal?
"each multiple is only counted once"
( [3,5] 100 sum )
2318
equal?
"a much larger limit"
( [3,5] 1000 sum )
233168
equal?
"three factors"
( [7,13,17] 20 sum )
51
equal?
"factors not relatively prime"
( [4,6] 15 sum )
30
equal?
"some pairs of factors relatively prime and some not"
( [5,6,8] 150 sum )
4419
equal?
"one factor is a multiple of another"
( [5,25] 51 sum )
275
equal?
"much larger factors"
( [43,47] 10000 sum )
2203160
equal?
"all numbers are multiples of 1"
( [1] 100 sum )
4950
equal?
"no factors means an empty sum"
( [] 10000 sum )
0
equal?
"the only multiple of 0 is 0"
( [0] 1 sum )
0
equal?
"the factor 0 does not affect the sum of multiples of other factors"
( [3,0] 4 sum )
3
equal?
"solutions using include-exclude must extend to cardinality greater than 3"
( [2,3,5,7,11] 10000 sum )
39614537
equal?
end-of-tests
;with