Skip to content

Commit

Permalink
Add book-store exercise (#137)
Browse files Browse the repository at this point in the history
  • Loading branch information
keiravillekode authored Dec 27, 2024
1 parent 6846e72 commit 43eedee
Show file tree
Hide file tree
Showing 12 changed files with 3,784 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,14 @@
"prerequisites": [],
"difficulty": 7
},
{
"slug": "book-store",
"name": "Book Store",
"uuid": "a01d25e1-021c-40ed-983e-fdda79556aaa",
"practices": [],
"prerequisites": [],
"difficulty": 8
},
{
"slug": "meetup",
"name": "Meetup",
Expand Down
61 changes: 61 additions & 0 deletions exercises/practice/book-store/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Instructions

To try and encourage more sales of different books from a popular 5 book series, a bookshop has decided to offer discounts on multiple book purchases.

One copy of any of the five books costs $8.

If, however, you buy two different books, you get a 5% discount on those two books.

If you buy 3 different books, you get a 10% discount.

If you buy 4 different books, you get a 20% discount.

If you buy all 5, you get a 25% discount.

Note that if you buy four books, of which 3 are different titles, you get a 10% discount on the 3 that form part of a set, but the fourth book still costs $8.

Your mission is to write code to calculate the price of any conceivable shopping basket (containing only books of the same series), giving as big a discount as possible.

For example, how much does this basket of books cost?

- 2 copies of the first book
- 2 copies of the second book
- 2 copies of the third book
- 1 copy of the fourth book
- 1 copy of the fifth book

One way of grouping these 8 books is:

- 1 group of 5 (1st, 2nd,3rd, 4th, 5th)
- 1 group of 3 (1st, 2nd, 3rd)

This would give a total of:

- 5 books at a 25% discount
- 3 books at a 10% discount

Resulting in:

- 5 × (100% - 25%) × $8 = 5 × $6.00 = $30.00, plus
- 3 × (100% - 10%) × $8 = 3 × $7.20 = $21.60

Which equals $51.60.

However, a different way to group these 8 books is:

- 1 group of 4 books (1st, 2nd, 3rd, 4th)
- 1 group of 4 books (1st, 2nd, 3rd, 5th)

This would give a total of:

- 4 books at a 20% discount
- 4 books at a 20% discount

Resulting in:

- 4 × (100% - 20%) × $8 = 4 × $6.40 = $25.60, plus
- 4 × (100% - 20%) × $8 = 4 × $6.40 = $25.60

Which equals $51.20.

And $51.20 is the price with the biggest discount.
19 changes: 19 additions & 0 deletions exercises/practice/book-store/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"authors": [
"keiravillekode"
],
"files": {
"solution": [
"book_store.s"
],
"test": [
"book_store_test.c"
],
"example": [
".meta/example.s"
]
},
"blurb": "To try and encourage more sales of different books from a popular 5 book series, a bookshop has decided to offer discounts of multiple-book purchases.",
"source": "Inspired by the harry potter kata from Cyber-Dojo.",
"source_url": "https://cyber-dojo.org"
}
122 changes: 122 additions & 0 deletions exercises/practice/book-store/.meta/example.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
.text
.globl total

/* void count(size_t basket_count, const uint16_t *basket, uint16_t *tally); */
count:
lsl x0, x0, #1 /* number of bytes occupied by array */
cbz x0, .return

.loop:
sub x0, x0, #2
ldrh w10, [x1, x0] /* book */
lsl w10, w10, #1
ldrh w11, [x2, x10]
add w11, w11, #1 /* increment tally */
strh w11, [x2, x10]
cbnz x0, .loop

.return:
ret

/* extern void sort(uint16_t *tally) */
sort:
mov w9, #4 /* offsets 4..10 for books 2..5 */

.outer:
ldrh w12, [x0, x9]
mov w10, w9 /* offset for inner loop of insertion sort */

.inner:
sub w11, w10, #2
cbz w11, .exit

ldrh w13, [x0, x11]
cmp w13, w12
bge .exit

strh w13, [x0, x10]
mov w10, w11
b .inner

.exit:
strh w12, [x0, x10]

add w9, w9, #2
cmp w9, #10
ble .outer

ret

/* void difference(uint16_t *tally); */
difference:
ldrh w10, [x0, #10]
ldrh w11, [x0, #8]
sub w12, w11, w10
strh w12, [x0, #8] /* tally[4] - tally[5] */

ldrh w10, [x0, #6]
sub w12, w10, w11
strh w12, [x0, #6] /* tally[3] - tally[4] */

ldrh w11, [x0, #4]
sub w12, w11, w10
strh w12, [x0, #4] /* tally[2] - tally[3] */

ldrh w10, [x0, #2]
sub w12, w10, w11
strh w12, [x0, #2] /* tally[1] - tally[2] */
ret

/* void adjust(uint16_t *tally); */
adjust:
ldrh w11, [x0, #6]
ldrh w12, [x0, #8]
ldrh w13, [x0, #10]
cmp w11, w13
csel w14, w11, w13, lt /* smallest of tallies for 3 and 5 books */

sub w11, w11, w14
sub w13, w13, w14 /* replace each pair of groups of 3 and 5 books */
lsl w14, w14, #1 /* with pairs of groups of 4 books */
add w12, w12, w14
strh w11, [x0, #6]
strh w12, [x0, #8]
strh w13, [x0, #10]
ret

/* uint32_t score(uint16_t *tally); */
score:
ldrh w11, [x0, #2]
mov w10, #800 /* price of 1 book */
mul w12, w10, w11

ldrh w11, [x0, #4]
mov w10, #1520 /* price of 2 books */
madd w12, w10, w11, w12

ldrh w11, [x0, #6]
mov w10, #2160 /* price of 3 books */
madd w12, w10, w11, w12

ldrh w11, [x0, #8]
mov w10, #2560 /* price of 4 books */
madd w12, w10, w11, w12

ldrh w11, [x0, #10]
mov w10, #3000 /* price of 5 books */
madd w0, w10, w11, w12
ret

/* extern uint32_t total(size_t basket_count, const uint16_t *basket); */
total:
mov x15, lr /* save return address */
stp xzr, xzr, [sp, #-16]!
mov x2, sp
bl count
mov x0, sp
bl sort
bl difference
bl adjust
bl score
add sp, sp, #16
ret x15
64 changes: 64 additions & 0 deletions exercises/practice/book-store/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# 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.

[17146bd5-2e80-4557-ab4c-05632b6b0d01]
description = "Only a single book"

[cc2de9ac-ff2a-4efd-b7c7-bfe0f43271ce]
description = "Two of the same book"

[5a86eac0-45d2-46aa-bbf0-266b94393a1a]
description = "Empty basket"

[158bd19a-3db4-4468-ae85-e0638a688990]
description = "Two different books"

[f3833f6b-9332-4a1f-ad98-6c3f8e30e163]
description = "Three different books"

[1951a1db-2fb6-4cd1-a69a-f691b6dd30a2]
description = "Four different books"

[d70f6682-3019-4c3f-aede-83c6a8c647a3]
description = "Five different books"

[78cacb57-911a-45f1-be52-2a5bd428c634]
description = "Two groups of four is cheaper than group of five plus group of three"

[f808b5a4-e01f-4c0d-881f-f7b90d9739da]
description = "Two groups of four is cheaper than groups of five and three"

[fe96401c-5268-4be2-9d9e-19b76478007c]
description = "Group of four plus group of two is cheaper than two groups of three"

[68ea9b78-10ad-420e-a766-836a501d3633]
description = "Two each of first four books and one copy each of rest"

[c0a779d5-a40c-47ae-9828-a340e936b866]
description = "Two copies of each book"

[18fd86fe-08f1-4b68-969b-392b8af20513]
description = "Three copies of first book and two each of remaining"

[0b19a24d-e4cf-4ec8-9db2-8899a41af0da]
description = "Three each of first two books and two each of remaining books"

[bb376344-4fb2-49ab-ab85-e38d8354a58d]
description = "Four groups of four are cheaper than two groups each of five and three"

[5260ddde-2703-4915-b45a-e54dbbac4303]
description = "Check that groups of four are created properly even when there are more groups of three than groups of five"

[b0478278-c551-4747-b0fc-7e0be3158b1f]
description = "One group of one and four is cheaper than one group of two and three"

[cf868453-6484-4ae1-9dfc-f8ee85bbde01]
description = "One group of one and two plus three groups of four is cheaper than one group of each size"
36 changes: 36 additions & 0 deletions exercises/practice/book-store/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/book-store/book_store.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.text
.globl total

total:
ret
Loading

0 comments on commit 43eedee

Please sign in to comment.