Skip to content

Commit

Permalink
Add robot-simulator exercise (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
ageron authored Sep 23, 2024
1 parent f320ba6 commit e1dd4b4
Show file tree
Hide file tree
Showing 9 changed files with 340 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@
"prerequisites": [],
"difficulty": 2
},
{
"slug": "robot-simulator",
"name": "Robot Simulator",
"uuid": "609aac37-6b82-4d29-a540-bcad0e80981b",
"practices": [],
"prerequisites": [],
"difficulty": 2
},
{
"slug": "scrabble-score",
"name": "Scrabble Score",
Expand Down
25 changes: 25 additions & 0 deletions exercises/practice/robot-simulator/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Instructions

Write a robot simulator.

A robot factory's test facility needs a program to verify robot movements.

The robots have three possible movements:

- turn right
- turn left
- advance

Robots are placed on a hypothetical infinite grid, facing a particular direction (north, east, south, or west) at a set of {x,y} coordinates,
e.g., {3,8}, with coordinates increasing to the north and east.

The robot then receives a number of instructions, at which point the testing facility verifies the robot's new position, and in which direction it is pointing.

- The letter-string "RAALAL" means:
- Turn right
- Advance twice
- Turn left
- Advance once
- Turn left yet again
- Say a robot starts at {7, 3} facing north.
Then running this stream of instructions should leave it at {9, 4} facing west.
38 changes: 38 additions & 0 deletions exercises/practice/robot-simulator/.meta/Example.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module [create, move]

Direction : [North, East, South, West]
Robot : { x : I64, y : I64, direction : Direction }

create : { x ? I64, y ? I64, direction ? Direction } -> Robot
create = \{ x ? 0, y ? 0, direction ? North } ->
{ x, y, direction }

move : Robot, Str -> Robot
move = \robot, instructions ->
instructions
|> Str.toUtf8
|> List.walk robot \{ x, y, direction }, command ->
when command is
'R' ->
when direction is
North -> { x, y, direction: East }
East -> { x, y, direction: South }
South -> { x, y, direction: West }
West -> { x, y, direction: North }

'L' ->
when direction is
North -> { x, y, direction: West }
East -> { x, y, direction: North }
South -> { x, y, direction: East }
West -> { x, y, direction: South }

'A' ->
when direction is
North -> { x, y: y + 1, direction }
East -> { x: x + 1, y, direction }
South -> { x, y: y - 1, direction }
West -> { x: x - 1, y, direction }

_ -> { x, y, direction } # invalid instructions are ignored

18 changes: 18 additions & 0 deletions exercises/practice/robot-simulator/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"authors": [
"ageron"
],
"files": {
"solution": [
"RobotSimulator.roc"
],
"test": [
"robot-simulator-test.roc"
],
"example": [
".meta/Example.roc"
]
},
"blurb": "Write a robot simulator.",
"source": "Inspired by an interview question at a famous company."
}
13 changes: 13 additions & 0 deletions exercises/practice/robot-simulator/.meta/plugins.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
def to_robot(robot, with_defaults):
x = robot["position"]["x"]
y = robot["position"]["y"]
direction = robot["direction"]
fields = []
if x != 0 or not with_defaults:
fields.append(f"x : {x}")
if y != 0 or not with_defaults:
fields.append(f"y : {y}")
if direction != "north" or not with_defaults:
fields.append(f"direction : {direction.capitalize()}")
content = ", ".join(fields)
return f"{{{content}}}"
24 changes: 24 additions & 0 deletions exercises/practice/robot-simulator/.meta/template.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{%- import "generator_macros.j2" as macros with context -%}
{{ macros.canonical_ref() }}
{{ macros.header() }}

import {{ exercise | to_pascal }} exposing [create, move]

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

{% for case in supercase["cases"] -%}
# {{ case["description"] }}
expect
{%- if case["input"]["instructions"] %}
robot = create {{ plugins.to_robot(case["input"], with_defaults=True) }}
result = robot |> move {{ case["input"]["instructions"] | to_roc }}
{%- else %}
result = create {{ plugins.to_robot(case["input"], with_defaults=True) }}
{%- endif %}
result == {{ plugins.to_robot(case["expected"], with_defaults=False) }}

{% endfor %}
{% endfor %}
64 changes: 64 additions & 0 deletions exercises/practice/robot-simulator/.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.

[c557c16d-26c1-4e06-827c-f6602cd0785c]
description = "Create robot -> at origin facing north"

[bf0dffce-f11c-4cdb-8a5e-2c89d8a5a67d]
description = "Create robot -> at negative position facing south"

[8cbd0086-6392-4680-b9b9-73cf491e67e5]
description = "Rotating clockwise -> changes north to east"

[8abc87fc-eab2-4276-93b7-9c009e866ba1]
description = "Rotating clockwise -> changes east to south"

[3cfe1b85-bbf2-4bae-b54d-d73e7e93617a]
description = "Rotating clockwise -> changes south to west"

[5ea9fb99-3f2c-47bd-86f7-46b7d8c3c716]
description = "Rotating clockwise -> changes west to north"

[fa0c40f5-6ba3-443d-a4b3-58cbd6cb8d63]
description = "Rotating counter-clockwise -> changes north to west"

[da33d734-831f-445c-9907-d66d7d2a92e2]
description = "Rotating counter-clockwise -> changes west to south"

[bd1ca4b9-4548-45f4-b32e-900fc7c19389]
description = "Rotating counter-clockwise -> changes south to east"

[2de27b67-a25c-4b59-9883-bc03b1b55bba]
description = "Rotating counter-clockwise -> changes east to north"

[f0dc2388-cddc-4f83-9bed-bcf46b8fc7b8]
description = "Moving forward one -> facing north increments Y"

[2786cf80-5bbf-44b0-9503-a89a9c5789da]
description = "Moving forward one -> facing south decrements Y"

[84bf3c8c-241f-434d-883d-69817dbd6a48]
description = "Moving forward one -> facing east increments X"

[bb69c4a7-3bbf-4f64-b415-666fa72d7b04]
description = "Moving forward one -> facing west decrements X"

[e34ac672-4ed4-4be3-a0b8-d9af259cbaa1]
description = "Follow series of instructions -> moving east and north from README"

[f30e4955-4b47-4aa3-8b39-ae98cfbd515b]
description = "Follow series of instructions -> moving west and north"

[3e466bf6-20ab-4d79-8b51-264165182fca]
description = "Follow series of instructions -> moving west and south"

[41f0bb96-c617-4e6b-acff-a4b279d44514]
description = "Follow series of instructions -> moving east and north"
12 changes: 12 additions & 0 deletions exercises/practice/robot-simulator/RobotSimulator.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module [create, move]

Direction : [North, East, South, West]
Robot : { x : I64, y : I64, direction : Direction }

create : { x ? I64, y ? I64, direction ? Direction } -> Robot
create = \{ x ? 0, y ? 0, direction ? North } ->
crash "Please implement the 'create' function"

move : Robot, Str -> Robot
move = \robot, instructions ->
crash "Please implement the 'move' function"
138 changes: 138 additions & 0 deletions exercises/practice/robot-simulator/robot-simulator-test.roc
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# These tests are auto-generated with test data from:
# https://github.com/exercism/problem-specifications/tree/main/exercises/robot-simulator/canonical-data.json
# File last updated on 2024-09-23
app [main] {
pf: platform "https://github.com/roc-lang/basic-cli/releases/download/0.15.0/SlwdbJ-3GR7uBWQo6zlmYWNYOxnvo8r6YABXD-45UOw.tar.br",
}

main =
Task.ok {}

import RobotSimulator exposing [create, move]

##
## Create robot
##

# at origin facing north
expect
result = create {}
result == { x: 0, y: 0, direction: North }

# at negative position facing south
expect
result = create { x: -1, y: -1, direction: South }
result == { x: -1, y: -1, direction: South }

##
## Rotating clockwise
##

# changes north to east
expect
robot = create {}
result = robot |> move "R"
result == { x: 0, y: 0, direction: East }

# changes east to south
expect
robot = create { direction: East }
result = robot |> move "R"
result == { x: 0, y: 0, direction: South }

# changes south to west
expect
robot = create { direction: South }
result = robot |> move "R"
result == { x: 0, y: 0, direction: West }

# changes west to north
expect
robot = create { direction: West }
result = robot |> move "R"
result == { x: 0, y: 0, direction: North }

##
## Rotating counter-clockwise
##

# changes north to west
expect
robot = create {}
result = robot |> move "L"
result == { x: 0, y: 0, direction: West }

# changes west to south
expect
robot = create { direction: West }
result = robot |> move "L"
result == { x: 0, y: 0, direction: South }

# changes south to east
expect
robot = create { direction: South }
result = robot |> move "L"
result == { x: 0, y: 0, direction: East }

# changes east to north
expect
robot = create { direction: East }
result = robot |> move "L"
result == { x: 0, y: 0, direction: North }

##
## Moving forward one
##

# facing north increments Y
expect
robot = create {}
result = robot |> move "A"
result == { x: 0, y: 1, direction: North }

# facing south decrements Y
expect
robot = create { direction: South }
result = robot |> move "A"
result == { x: 0, y: -1, direction: South }

# facing east increments X
expect
robot = create { direction: East }
result = robot |> move "A"
result == { x: 1, y: 0, direction: East }

# facing west decrements X
expect
robot = create { direction: West }
result = robot |> move "A"
result == { x: -1, y: 0, direction: West }

##
## Follow series of instructions
##

# moving east and north from README
expect
robot = create { x: 7, y: 3 }
result = robot |> move "RAALAL"
result == { x: 9, y: 4, direction: West }

# moving west and north
expect
robot = create {}
result = robot |> move "LAAARALA"
result == { x: -4, y: 1, direction: West }

# moving west and south
expect
robot = create { x: 2, y: -7, direction: East }
result = robot |> move "RRAAAAALA"
result == { x: -3, y: -8, direction: South }

# moving east and north
expect
robot = create { x: 8, y: 4, direction: South }
result = robot |> move "LAAARRRALLLL"
result == { x: 11, y: 5, direction: North }

0 comments on commit e1dd4b4

Please sign in to comment.