Skip to content

Commit

Permalink
Add global-positioning-system exercise (#444)
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikSchierboom authored Sep 23, 2024
1 parent d6e2316 commit 33a2836
Show file tree
Hide file tree
Showing 8 changed files with 428 additions and 0 deletions.
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 1
},
{
"slug": "global-positioning-system",
"name": "Global Positioning System",
"uuid": "14d2d6a7-6d6c-4cdf-b0cb-8df1093e8f70",
"practices": [],
"prerequisites": [],
"difficulty": 1
}
],
"foregone": [
Expand Down
45 changes: 45 additions & 0 deletions exercises/practice/global-positioning-system/.docs/hints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Hints

## General

- [Wikipedia's Definite Clause Grammar page](https://en.wikipedia.org/wiki/Definite_clause_grammar) gives a great overview of DCGs
- The [Prolog DCG Primer](https://www.metalevel.at/prolog/dcg) has a very useful introduction to Prolog DCGs
- The [SWIPL dcg/basics docs](https://www.swi-prolog.org/pldoc/doc/_SWI_/library/dcg/basics.pl) lists the built-in primitives you can use

## 3. Support all whitespace (except newlines)

- There is a [built-in primitive](https://www.swi-prolog.org/pldoc/doc/_SWI_/library/dcg/basics.pl) you can use for this

## 4. Parse the latitude's hemisphere

- DCG rules can have variables like regular facts or rules
- DCG rules can have multiple declarations like regular facts or rules

## 5. Parse the longitude's hemisphere

- DCG rules can have variables like regular facts or rules
- DCG rules can have multiple declarations like regular facts or rules

## 6. Parse degrees

- There is a [built-in primitive](https://www.swi-prolog.org/pldoc/doc/_SWI_/library/dcg/basics.pl) you can use for this

## 7. Parse latitude degrees

- You can re-use the `degrees` rule
- The `{}//1` language construct can be used to invoke Prolog predicates from within a rule

## 9. Parse latitude

- The format for a latitude is: `<LATITUDE_DEGREES> <LATITUDE_HEMISPHERE>`
- Re-use the rules you've already implemented

## 10. Parse longitude

- The format for a longitude is: `<LONGITUDE_DEGREES> <LONGITUDE_HEMISPHERE>`
- Re-use the rules you've already implemented

## 11. Parse coordinate

- The format for a coordinate is: `<LATITUDE_DEGREES> <LATITUDE_HEMISPHERE>, <LONGITUDE_DEGREES> <LONGITUDE_HEMISPHERE>`
- Re-use the rules you've already implemented
151 changes: 151 additions & 0 deletions exercises/practice/global-positioning-system/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Instructions

Your task is to parse GPS coordinates.
Each coordinate is formatted using the [Decimal Degrees format](https://en.wikipedia.org/wiki/Decimal_degrees) variant with explicit hemispheres:

```text
<LATITUDE_DEGREES> <LATITUDE_HEMISPHERE>, <LONGITUDE_DEGREES> <LONGITUDE_HEMISPHERE>
```

These are the allowed values for each individual component:

- `<LATITUDE_DEGREES>`: a floating-point number in the range 0..90 (inclusive)
- `<LATITUDE_HEMISPHERE>`: either `N` or `S`
- `<LONGITUDE_DEGREES>`: a floating-point number in the range 0..180 (inclusive)
- `<LONGITUDE_HEMISPHERE>`: either `E` or `W`

For example, `"48.8584 N 2.2945 E"` parses into:

- `<LATITUDE_DEGREES>`: 48.8584
- `<LATITUDE_HEMISPHERE>`: N
- `<LONGITUDE_DEGREES>`: 2.2945
- `<LONGITUDE_HEMISPHERE>`: E

You have 11 tasks, in which you'll incrementally parse GPS coordinates.
You'll be using Prolog's [Definite Clause Grammar](https://en.wikipedia.org/wiki/Definite_clause_grammar) (DCG) support, which are designed to parse structured text.

````exercism/note
To help you get started, the stub file already includes the [`dcg/basics` library](https://www.swi-prolog.org/pldoc/doc/_SWI_/library/dcg/basics.pl) via:
```prolog
:- use_module(library(dcg/basics)).
```
````

## 1. Parse a comma

Implement the `comma` rule to parse a single comma (`","`):

```prolog
?- string_codes(",", Codes), phrase(comma, Codes).
```

## 2. Parse a space

Implement the `space` rule to parse a single space (`" "`):

```prolog
?- string_codes(" ", Codes), phrase(space, Codes).
```

## 3. Support all whitespace (except newlines)

Modify the `space` rule to parse _all_ whitespace, except for newlines:

```prolog
?- string_codes("\t", Codes), phrase(space, Codes).
?- string_codes("\n", Codes), phrase(space, Codes).
false.
```

## 4. Parse the latitude's hemisphere

The hemisphere of the latitude can be either `"N"` or `"S"`, which should be parsed to the `north` or `south` atom.
Implement the `latitude_hemisphere` rule to parse the latitude's hemisphere:

```prolog
?- string_codes("N", Codes), phrase(latitude_hemisphere(Hemisphere), Codes).
Hemisphere = north.
```

## 5. Parse the longitude's hemisphere

The hemisphere of the longitude can be either `"E"` or `"W"`, which should be parsed to the `east` or `west` atom.
Implement the `longitude_hemisphere` rule to parse the longitude's hemisphere:

```prolog
?- string_codes("E", Codes), phrase(longitude_hemisphere(Hemisphere), Codes).
Hemisphere = east.
```

## 6. Parse degrees

The degrees of a longitude or latitude ire defined as a floating-point number.
Implement the `degrees` rule to parse floating-point numbers:

```prolog
?- string_codes("748.012", Codes), phrase(degrees(Degrees), Codes).
Degrees = 748.012.
```

## 7. Parse latitude degrees

Latitude degrees are not just floating-point numbers, but floating-point numbers in the range 0..90 (inclusive).
Implement the `latitude_degrees` rule to parse latitude degrees using the above range:

```prolog
?- string_codes("48.745", Codes), phrase(latitude_degrees(Degrees), Codes).
Degrees = 48.745.
?- string_codes("117.844", Codes), phrase(latitude_degrees(Degrees), Codes).
false.
```

## 8. Parse longitude degrees

Longitude degrees are not just floating-point numbers, but floating-point numbers in the range 0..180 (inclusive).
Implement the `longitude_degrees` rule to parse longitude degrees using the above range:

```prolog
?- string_codes("178.773", Codes), phrase(longitude_degrees(Degrees), Codes).
Degrees = 178.773.
?- string_codes("-22.523", Codes), phrase(longitude_degrees(Degrees), Codes).
false.
```

## 9. Parse latitude

Latitudes have two parts: their degrees and hemisphere, which are separated by a space.
Implement the `latitude` rule to parse a latitude:

```prolog
?- string_codes("56.101 N", Codes), phrase(latitude(Degrees, Hemisphere), Codes).
Degrees = 56.101,
Hemisphere = north.
```

## 10. Parse longitude

Latitudes have two parts: their degrees and hemisphere, which are separated by a space.
Implement the `latitude` rule to parse a latitude:

```prolog
?- string_codes("143.889 W", Codes), phrase(longitude(Degrees, Hemisphere), Codes).
Degrees = 143.889,
Hemisphere = west.
```

## 11. Parse coordinate

Coordinates have two parts: their latitude and longitude, which are separated by a comma followed by a space.
Implement the `coordinate` rule to parse both the latitude (degrees and hemisphere):

```prolog
?- string_codes("48.8584 N, 2.2945 E", Codes), phrase(coordinate(Latitude, LatitudeHemisphere, Longitude, LongitudeHemisphere), Codes).
Latitude = 48.8584,
LatitudeHemisphere = north,
Longitude = 2.2945,
LongitudeHemisphere = east.
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Introduction

You're a huge fan of [geocaching](https://en.wikipedia.org/wiki/Geocaching), which combines your love for the outdoors with a love for solving puzzles.
Whilst the local geocaching website lists the GPS coordinates of all caches, it does _not_ support creating an efficient route for gathering them.
It so happens you have pathfinding software installed on your machine, but it uses a different GPS format from the geocaching website.
To feed the data into the pathfinding software, you'll need to parse the degrees and hemisphere for both the latitude and longitude of each GPS coordinate on the website.
17 changes: 17 additions & 0 deletions exercises/practice/global-positioning-system/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [
"erikschierboom"
],
"files": {
"solution": [
"global_positioning_system.pl"
],
"test": [
"global_positioning_system_tests.plt"
],
"example": [
".meta/global_positioning_system.example.pl"
]
},
"blurb": "Parse GPS coordinates into their individual components"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
:- use_module(library(dcg/basics)).

comma --> ",".
space --> white.

latitude_hemisphere(north) --> "N".
latitude_hemisphere(south) --> "S".

longitude_hemisphere(east) --> "E".
longitude_hemisphere(west) --> "W".

degrees(Degrees) --> float(Degrees).
latitude_degrees(Degrees) --> degrees(Degrees), { Degrees >= 0, Degrees =< 90 }.
longitude_degrees(Degrees) --> degrees(Degrees), { Degrees >= 0, Degrees =< 180 }.

latitude(Degrees, Hemisphere) --> latitude_degrees(Degrees), space, latitude_hemisphere(Hemisphere).
longitude(Degrees, Hemisphere) --> longitude_degrees(Degrees), space, longitude_hemisphere(Hemisphere).

coordinate(Latitude, LatitudeHemisphere, Longitude, LongitudeHemisphere) -->
latitude(Latitude, LatitudeHemisphere), comma, space, longitude(Longitude, LongitudeHemisphere).
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
:- use_module(library(dcg/basics)).

comma.
space.

latitude_hemisphere(Hemisphere).
longitude_hemisphere(Hemisphere).

degrees(Degrees).
latitude_degrees(Degrees).
longitude_degrees(Degrees).

latitude(Degrees, Hemisphere).
longitude(Degrees, Hemisphere).

coordinate(Latitude, LatitudeHemisphere, Longitude, LongitudeHemisphere).
Loading

0 comments on commit 33a2836

Please sign in to comment.