Skip to content
Open
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
38 changes: 38 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,44 @@
"stack-effect"
],
"status": "wip"
},
{
"slug": "currency-conversion",
"name": "Currency Conversion",
"uuid": "380a2d4f-ea48-47a1-94f1-fc8ec0561136",
"concepts": [
"numbers"
],
"prerequisites": [
"stack-effect"
],
"status": "wip"
},
{
"slug": "cars-assemble",
"name": "Cars, Assemble!",
"uuid": "e5e68b1a-5445-4251-a56b-6a40fab662ed",
"concepts": [
"conditionals"
],
"prerequisites": [
"booleans",
"numbers"
],
"status": "wip"
},
{
"slug": "log-levels",
"name": "Log Levels",
"uuid": "2e436217-a007-438e-b553-451e10d9c459",
"concepts": [
"strings"
],
"prerequisites": [
"stack-effect",
"conditionals"
],
"status": "wip"
}
],
"practice": [
Expand Down
35 changes: 35 additions & 0 deletions exercises/concept/cars-assemble/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Hints

## General

- `cond` in [`combinators`][combinators] is the cleanest way to map a
speed to a success rate.
- The arithmetic words live in [`math`][math]; the float-to-integer
helpers `floor` and `>integer` live in
[`math.functions`][math.functions] and `math` respectively.

## 1. Calculate the success rate

- A `cond` clause is `{ [ predicate ] [ body ] }`. Each predicate
inspects the speed but should leave the stack as it found it
(a `dup` … `<test>` does that). The body usually starts with `drop`.
- Order matters: check `zero?` before `4 <=`, because `0 4 <=` is `t`.
- Use a final entry without a predicate as the default for speed `10`.

## 2. Calculate the production rate per hour

- Define `base-speed` as a `CONSTANT:` near the top of the file (just
like `expected-bake-time` in `lasagna`).
- Compute `base-speed * speed * success-rate`. One option is to use
`bi` from `kernel`: it runs two quotations on the same input and
leaves both results on the stack.

## 3. Calculate the number of working items produced per minute

- Divide the hourly rate by 60.
- Use `floor` to drop the fractional part, then `>integer` to convert
the float result into an integer.

[math]: https://docs.factorcode.org/content/vocab-math.html
[math.functions]: https://docs.factorcode.org/content/vocab-math.functions.html
[combinators]: https://docs.factorcode.org/content/vocab-combinators.html
55 changes: 55 additions & 0 deletions exercises/concept/cars-assemble/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Instructions

In this exercise you'll be writing code to analyze the production of
an assembly line in a car factory. The assembly line's speed can range
from `0` (off) to `10` (maximum).

At its lowest non-zero speed (`1`), `221` cars are produced each hour.
The production increases linearly with the speed, so at speed `4` the
line produces `4 * 221 = 884` cars per hour. However, higher speeds
increase the likelihood that faulty cars are produced, which then
have to be discarded.

You have three tasks. Each takes a single integer parameter — the
speed of the assembly line — off the stack.

## 1. Calculate the success rate

Define `success-rate` to return the probability of an item being
produced without error:

- `0`: `0.0`
- `1` to `4`: `1.0`
- `5` to `8`: `0.9`
- `9`: `0.8`
- `10`: `0.77`

```factor
10 success-rate .
! => 0.77
```

## 2. Calculate the production rate per hour

Define `production-rate-per-hour` to return the assembly line's
production rate per hour, taking the success rate into account.

You'll need to define `base-speed` first, the constant `221`.

```factor
6 production-rate-per-hour .
! => 1193.4
```

The value returned is floating-point.

## 3. Calculate the number of working items produced per minute

Define `working-items-per-minute` to return how many working cars are
produced per minute. The result is an integer — partial cars are not
counted.

```factor
6 working-items-per-minute .
! => 19
```
81 changes: 81 additions & 0 deletions exercises/concept/cars-assemble/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Introduction

This exercise introduces conditionals — choosing between two or more
courses of action based on a value. It builds on the booleans you met
in [Annalyn's Infiltration][annalyns] and the integer arithmetic from
[Currency Conversion][currency-conversion].

## Comparison words

These all live in [`math`][math] (and `kernel` for `=`):

```
= ( x y -- ? ) ! equal
< ( x y -- ? ) ! less than
<= ( x y -- ? ) ! less than or equal
> ( x y -- ? ) ! greater than
>= ( x y -- ? ) ! greater than or equal
```

```factor
3 3 = . ! => t
2 3 < . ! => t
3 3 <= . ! => t
```

## `if`, `when`, `unless`

`if` (in [`kernel`][kernel]) takes a boolean and two quotations. It
runs the first quotation when the boolean is truthy and the second
when it is falsy:

```
if ( ? then-quot else-quot -- )
```

```factor
: abs ( x -- y ) dup 0 < [ neg ] [ ] if ;
```

`when` runs its quotation only when the boolean is truthy; `unless`
only when it is falsy:

```
when ( ? quot -- )
unless ( ? quot -- )
```

## `cond`

When you have several alternative actions to choose between, `cond`
(in [`combinators`][combinators]) is the natural fit. It takes an
array of `{ predicate body }` pairs and runs the body of the first
predicate that yields a truthy value:

```factor
USING: combinators ;

: classify ( n -- label )
{
{ [ dup 0 < ] [ drop "negative" ] }
{ [ dup 0 = ] [ drop "zero" ] }
[ drop "positive" ]
} cond ;
```

A few details worth noting:

- The pairs are tried in order. The first match wins.
- An entry without a predicate (just a single quotation) at the end
acts as the default.
- Each predicate inspects the input but should leave the data stack
the way it found it — `dup ... <test>` is the usual idiom.
- The body of the chosen pair receives the same stack the predicate
saw, so it usually starts by `drop`ping the input and pushing the
result.

[annalyns]: https://exercism.org/tracks/factor/exercises/annalyns-infiltration
[currency-conversion]: https://exercism.org/tracks/factor/exercises/currency-conversion
[math]: https://docs.factorcode.org/content/vocab-math.html
[kernel]: https://docs.factorcode.org/content/vocab-kernel.html
[combinators]: https://docs.factorcode.org/content/vocab-combinators.html
5 changes: 5 additions & 0 deletions exercises/concept/cars-assemble/.docs/source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Source

Forked from the Julia track's ["Cars, Assemble!" exercise][julia-source].

[julia-source]: https://github.com/exercism/julia/tree/main/exercises/concept/cars-assemble
20 changes: 20 additions & 0 deletions exercises/concept/cars-assemble/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"authors": [
"keiravillekode"
],
"files": {
"solution": [
"cars-assemble/cars-assemble.factor"
],
"test": [
"cars-assemble/cars-assemble-tests.factor"
],
"exemplar": [
".meta/exemplar.factor"
]
},
"forked_from": [
"julia/cars-assemble"
],
"blurb": "Learn about conditionals in Factor by analyzing the production of an assembly line."
}
31 changes: 31 additions & 0 deletions exercises/concept/cars-assemble/.meta/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Design

## Goal

Introduce Factor's conditional combinators by mapping a discrete input
(speed) onto a discrete output (success rate).

## Learning objectives

- Use comparison words `=`, `<`, `<=`, `>`, `>=` from `math` and `kernel`.
- Use `if`, `when`, `unless` to choose between two quotations.
- Use `cond` from `combinators` for a chained "first matching predicate"
selection.
- Combine the `dup` … `drop` pattern with `cond` to inspect a value
without consuming it.

## Out of scope

- `case` from `combinators` for value-based dispatch.
- Multimethods, `GENERIC:`.
- Arithmetic combinators like `bi` are introduced incidentally for
task 2; deeper coverage belongs in a later exercise.

## Concepts

- `conditionals`: `if`, `when`, `unless`, and especially `cond`.

## Prerequisites

- `booleans` — taught in `annalyns-infiltration`.
- `numbers` — taught in `currency-conversion`.
19 changes: 19 additions & 0 deletions exercises/concept/cars-assemble/.meta/exemplar.factor
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
USING: combinators kernel math math.functions ;
IN: cars-assemble

CONSTANT: base-speed 221

: success-rate ( speed -- rate )
{
{ [ dup zero? ] [ drop 0.0 ] }
{ [ dup 4 <= ] [ drop 1.0 ] }
{ [ dup 8 <= ] [ drop 0.9 ] }
{ [ dup 9 = ] [ drop 0.8 ] }
[ drop 0.77 ]
} cond ;

: production-rate-per-hour ( speed -- rate )
[ base-speed * ] [ success-rate ] bi * ;

: working-items-per-minute ( speed -- count )
production-rate-per-hour 60 / floor >integer ;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
USING: cars-assemble tools.test ;
IN: cars-assemble.tests

! TASK: 1 success-rate
{ 0.0 } [ 0 success-rate ] unit-test
{ 1.0 } [ 1 success-rate ] unit-test
{ 1.0 } [ 4 success-rate ] unit-test
{ 0.9 } [ 5 success-rate ] unit-test
{ 0.8 } [ 9 success-rate ] unit-test
{ 0.77 } [ 10 success-rate ] unit-test

! TASK: 2 production-rate-per-hour
{ 0.0 } [ 0 production-rate-per-hour ] unit-test
{ 221.0 } [ 1 production-rate-per-hour ] unit-test
{ 884.0 } [ 4 production-rate-per-hour ] unit-test
{ 994.5 } [ 5 production-rate-per-hour ] unit-test
{ 1193.4 } [ 6 production-rate-per-hour ] unit-test
{ 1591.2 } [ 9 production-rate-per-hour ] unit-test
{ 1701.7 } [ 10 production-rate-per-hour ] unit-test

! TASK: 3 working-items-per-minute
{ 0 } [ 0 working-items-per-minute ] unit-test
{ 14 } [ 4 working-items-per-minute ] unit-test
{ 19 } [ 6 working-items-per-minute ] unit-test
{ 28 } [ 10 working-items-per-minute ] unit-test
13 changes: 13 additions & 0 deletions exercises/concept/cars-assemble/cars-assemble/cars-assemble.factor
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
USING: kernel ;
IN: cars-assemble

! Define base-speed.

: success-rate ( speed -- rate )
"unimplemented" throw ;

: production-rate-per-hour ( speed -- rate )
"unimplemented" throw ;

: working-items-per-minute ( speed -- count )
"unimplemented" throw ;
46 changes: 46 additions & 0 deletions exercises/concept/currency-conversion/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Hints

## General

- All the words you need live in the [`math`][math] and
[`math.functions`][math.functions] vocabularies. Add them to your
`USING:` line.

## 1. Estimate value after exchange

- Use `/` (stack effect `( x y -- x/y )`) to divide budget by rate.

## 2. Calculate currency left after an exchange

- Use `-` to subtract.

## 3. Calculate value of bills

- Use `*` to multiply.

## 4. Calculate number of bills

- The `amount` may be a float; you need an integer result.
- One approach: convert the amount to an integer first with
`floor >integer`, then divide with `/i`.
- An alternative: use `/i` directly — for an integer denominator it
also truncates the float — and then convert with `>integer`.

## 5. Calculate leftover after exchanging into bills

- Use `mod` for the remainder.

## 6. Calculate value after exchange

- Compute the *total* exchange rate: take `spread` percent of
`exchange-rate` and add it to `exchange-rate`.
- Then call `exchange-money` with the budget and total rate.
- Then call `number-of-bills` to round down to a whole number of
bills of the given denomination.
- Then call `value-of-bills` to get the final value.
- The four sub-calculations chain naturally; if your stack juggling
starts to feel awkward, the locals form (`::` with named parameters)
is fine here.

[math]: https://docs.factorcode.org/content/vocab-math.html
[math.functions]: https://docs.factorcode.org/content/vocab-math.functions.html
Loading