Skip to content

Commit

Permalink
Merge branch 'main' into add-robot-name
Browse files Browse the repository at this point in the history
  • Loading branch information
ageron authored Oct 19, 2024
2 parents b4197cc + d99ef97 commit e68f899
Show file tree
Hide file tree
Showing 13 changed files with 828 additions and 20 deletions.
24 changes: 16 additions & 8 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,6 @@
"difficulty": 2,
"status": "deprecated"
},
{
"slug": "clock",
"name": "Clock",
"uuid": "b1ebc201-5d23-4953-88d7-58c82def95b3",
"practices": [],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "collatz-conjecture",
"name": "Collatz Conjecture",
Expand Down Expand Up @@ -331,6 +323,14 @@
"prerequisites": [],
"difficulty": 3
},
{
"slug": "clock",
"name": "Clock",
"uuid": "b1ebc201-5d23-4953-88d7-58c82def95b3",
"practices": [],
"prerequisites": [],
"difficulty": 3
},
{
"slug": "crypto-square",
"name": "Crypto Square",
Expand Down Expand Up @@ -858,6 +858,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 9
},
{
"slug": "sgf-parsing",
"name": "SGF Parsing",
"uuid": "21064949-0320-425e-b2f5-ba67908c1db1",
"practices": [],
"prerequisites": [],
"difficulty": 9
}
]
},
Expand Down
4 changes: 3 additions & 1 deletion config/generator_macros.j2
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,10 @@ app [main] {
isodate: "https://github.com/imclerran/roc-isodate/releases/download/v0.5.1/XHx5wx95nuICKpN8sxMwYnCme5oX_YFbJUL1s6D1feU.tar.br"
{%- elif name == "json" -%}
json: "https://github.com/lukewilliamboswell/roc-json/releases/download/0.10.2/FH4N0Sw-JSFXJfG3j54VEDPtXOoN-6I9v_IA8S18IGk.tar.br"
{%- elif name == "parser" -%}
parser: "https://github.com/lukewilliamboswell/roc-parser/releases/download/0.7.2/1usTzOOACTpnkarBX0ED3gFESzR4ROdAlt1Llf4WFzo.tar.br"
{%- elif name == "rand" -%}
rand: "https://github.com/lukewilliamboswell/roc-random/releases/download/0.3.0/hPlOciYUhWMU7BefqNzL89g84-30fTE6l2_6Y3cxIcE.tar.br",
rand: "https://github.com/lukewilliamboswell/roc-random/releases/download/0.3.0/hPlOciYUhWMU7BefqNzL89g84-30fTE6l2_6Y3cxIcE.tar.br"
{%- endif -%}
{%- endfor -%}
{%- endif %}
Expand Down
10 changes: 6 additions & 4 deletions exercises/practice/clock/.meta/Example.roc
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ minutesPerDay = 24 * 60

create : { hours ? I64, minutes ? I64 }* -> Clock
create = \{ hours ? 0, minutes ? 0 } ->
totalMinutes = ((hours * 60 + minutes) % minutesPerDay + minutesPerDay) % minutesPerDay
hours24 = (hours % 24 + minutes // 60) % 24
minutes60 = minutes % 60
totalMinutes = ((hours24 * 60 + minutes60) % minutesPerDay + minutesPerDay) % minutesPerDay
hh = totalMinutes // 60 |> Num.toU8
mm = totalMinutes % 60 |> Num.toU8
{ hour: hh, minute: mm }
Expand All @@ -18,10 +20,10 @@ toStr = \{ hour, minute } ->
add : Clock, { hours ? I64, minutes ? I64 }* -> Clock
add = \{ hour, minute }, { hours ? 0, minutes ? 0 } ->
totalHours = Num.toI64 hour + hours
totalMinutes = Num.toI64 minute + minutes
totalHours = Num.toI64 hour + (hours % 24 + minutes // 60)
totalMinutes = Num.toI64 minute + minutes % 60
create { hours: totalHours, minutes: totalMinutes }
subtract : Clock, { hours ? I64, minutes ? I64 }* -> Clock
subtract = \clock, { hours ? 0, minutes ? 0 } ->
clock |> add { hours: -hours, minutes: -minutes }
clock |> add { hours: -(hours % 24 + minutes // 60), minutes: -(minutes % 60) }
62 changes: 62 additions & 0 deletions exercises/practice/clock/.meta/additional_tests.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"cases": [
{
"description": "Can create a clock with max I64 values",
"property": "create",
"input": {
"hour": 9223372036854775807,
"minute": 9223372036854775807
},
"expected": "01:07"
},
{
"description": "Can create a clock with min I64 values",
"property": "create",
"input": {
"hour": -9223372036854775808,
"minute": -9223372036854775808
},
"expected": "21:52"
},
{
"description": "Can add max I64 values to a clock",
"property": "add",
"input": {
"hour": 23,
"minute": 59,
"value": 9223372036854775807
},
"expected": "18:06"
},
{
"description": "Can add min I64 values to a clock",
"property": "add",
"input": {
"hour": 23,
"minute": 59,
"value": -9223372036854775808
},
"expected": "05:51"
},
{
"description": "Can subtract max I64 values from a clock",
"property": "subtract",
"input": {
"hour": 23,
"minute": 59,
"value": 9223372036854775807
},
"expected": "05:52"
},
{
"description": "Can subtract min I64 values from a clock",
"property": "subtract",
"input": {
"hour": 23,
"minute": 59,
"value": -9223372036854775808
},
"expected": "18:07"
}
]
}
24 changes: 18 additions & 6 deletions exercises/practice/clock/.meta/template.j2
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@

import {{ exercise | to_pascal }} exposing [create, add, subtract, toStr]

{% for supercase in cases %}
##
## {{ supercase["description"] }}
##

{% for case in supercase["cases"] -%}
{% macro test_case(case) %}
# {{ case["description"] }}

{%- if case["property"] == "create" %}
expect
clock = create {{ plugins.to_hours_minutes_record(case["input"]) }}
Expand All @@ -33,6 +29,22 @@ expect
# this test case is not implemented yet. Perhaps you can give it a try?
{%- endif %}

{% endmacro %}

{% for supercase in cases %}
##
## {{ supercase["description"] }}
##

{% for case in supercase["cases"] -%}
{{ test_case(case) }}
{% endfor %}
{% endfor %}

##
## Extreme I64 values should not crash with overflow errors
##

{% for case in additional_cases -%}
{{ test_case(case) }}
{% endfor %}
48 changes: 47 additions & 1 deletion exercises/practice/clock/clock-test.roc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# These tests are auto-generated with test data from:
# https://github.com/exercism/problem-specifications/tree/main/exercises/clock/canonical-data.json
# File last updated on 2024-09-11
# File last updated on 2024-10-13
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br",
}
Expand Down Expand Up @@ -374,3 +374,49 @@ expect
clock2 = create {}
clock1 == clock2

##
## Extreme I64 values should not crash with overflow errors
##

# Can create a clock with max I64 values
expect
clock = create { hours: 9223372036854775807, minutes: 9223372036854775807 }
result = clock |> toStr
expected = "01:07"
result == expected

# Can create a clock with min I64 values
expect
clock = create { hours: -9223372036854775808, minutes: -9223372036854775808 }
result = clock |> toStr
expected = "21:52"
result == expected

# Can add max I64 values to a clock
expect
clock = create { hours: 23, minutes: 59 }
result = clock |> add { minutes: 9223372036854775807 } |> toStr
expected = "18:06"
result == expected

# Can add min I64 values to a clock
expect
clock = create { hours: 23, minutes: 59 }
result = clock |> add { minutes: -9223372036854775808 } |> toStr
expected = "05:51"
result == expected

# Can subtract max I64 values from a clock
expect
clock = create { hours: 23, minutes: 59 }
result = clock |> subtract { minutes: 9223372036854775807 } |> toStr
expected = "05:52"
result == expected

# Can subtract min I64 values from a clock
expect
clock = create { hours: 23, minutes: 59 }
result = clock |> subtract { minutes: -9223372036854775808 } |> toStr
expected = "18:07"
result == expected

83 changes: 83 additions & 0 deletions exercises/practice/sgf-parsing/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Instructions

Parsing a Smart Game Format string.

[SGF][sgf] is a standard format for storing board game files, in particular go.

SGF is a fairly simple format. An SGF file usually contains a single
tree of nodes where each node is a property list. The property list
contains key value pairs, each key can only occur once but may have
multiple values.

The exercise will have you parse an SGF string and return a tree structure of properties.

An SGF file may look like this:

```text
(;FF[4]C[root]SZ[19];B[aa];W[ab])
```

This is a tree with three nodes:

- The top level node has three properties: FF\[4\] (key = "FF", value
= "4"), C\[root\](key = "C", value = "root") and SZ\[19\] (key =
"SZ", value = "19"). (FF indicates the version of SGF, C is a
comment and SZ is the size of the board.)
- The top level node has a single child which has a single property:
B\[aa\]. (Black plays on the point encoded as "aa", which is the
1-1 point).
- The B\[aa\] node has a single child which has a single property:
W\[ab\].

As you can imagine an SGF file contains a lot of nodes with a single
child, which is why there's a shorthand for it.

SGF can encode variations of play. Go players do a lot of backtracking
in their reviews (let's try this, doesn't work, let's try that) and SGF
supports variations of play sequences. For example:

```text
(;FF[4](;B[aa];W[ab])(;B[dd];W[ee]))
```

Here the root node has two variations. The first (which by convention
indicates what's actually played) is where black plays on 1-1. Black was
sent this file by his teacher who pointed out a more sensible play in
the second child of the root node: `B[dd]` (4-4 point, a very standard
opening to take the corner).

A key can have multiple values associated with it. For example:

```text
(;FF[4];AB[aa][ab][ba])
```

Here `AB` (add black) is used to add three black stones to the board.

All property values will be the [SGF Text type][sgf-text].
You don't need to implement any other value type.
Although you can read the [full documentation of the Text type][sgf-text], a summary of the important points is below:

- Newlines are removed if they come immediately after a `\`, otherwise they remain as newlines.
- All whitespace characters other than newline are converted to spaces.
- `\` is the escape character.
Any non-whitespace character after `\` is inserted as-is.
Any whitespace character after `\` follows the above rules.
Note that SGF does **not** have escape sequences for whitespace characters such as `\t` or `\n`.

Be careful not to get confused between:

- The string as it is represented in a string literal in the tests
- The string that is passed to the SGF parser

Escape sequences in the string literals may have already been processed by the programming language's parser before they are passed to the SGF parser.

There are a few more complexities to SGF (and parsing in general), which
you can mostly ignore. You should assume that the input is encoded in
UTF-8, the tests won't contain a charset property, so don't worry about
that. Furthermore you may assume that all newlines are unix style (`\n`,
no `\r` or `\r\n` will be in the tests) and that no optional whitespace
between properties, nodes, etc will be in the tests.

[sgf]: https://en.wikipedia.org/wiki/Smart_Game_Format
[sgf-text]: https://www.red-bean.com/sgf/sgf4.html#text
Loading

0 comments on commit e68f899

Please sign in to comment.