Skip to content

Commit

Permalink
Implement bird count in Gleam
Browse files Browse the repository at this point in the history
  • Loading branch information
Sgoettschkes committed Oct 3, 2023
1 parent 254399f commit 685cb90
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 0 deletions.
4 changes: 4 additions & 0 deletions gleam/bird-count/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.beam
*.ez
build
erl_crash.dump
32 changes: 32 additions & 0 deletions gleam/bird-count/HELP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Help

## Running the tests

To run the tests, run the command `gleam test` from within the exercise directory.

## Submitting your solution

You can submit your solution using the `exercism submit src/bird_count.gleam` command.
This command will upload your solution to the Exercism website and print the solution page's URL.

It's possible to submit an incomplete solution which allows you to:

- See how others have completed the exercise
- Request help from a mentor

## Need to get help?

If you'd like help solving the exercise, check the following pages:

- The [Gleam track's documentation](https://exercism.org/docs/tracks/gleam)
- The [Gleam track's programming category on the forum](https://forum.exercism.org/c/programming/gleam)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)

Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.

To get help if you're having trouble, you can use one of the following resources:

- [gleam.run](https://gleam.run/documentation/) is the gleam official documentation.
- [Discord](https://discord.gg/Fm8Pwmy) is the discord channel.
- [StackOverflow](https://stackoverflow.com/questions/tagged/gleam) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
31 changes: 31 additions & 0 deletions gleam/bird-count/HINTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Hints

## General

- Try to split a problem into a base case and a recursive case. For example, let's say you want to count how many cookies are there in the cookie jar with a recursive approach. A base case is an empty jar - it has zero cookies. If the jar is not empty, then the number of cookies in the jar is equal to one cookie plus the number of cookies in the jar after removing one cookie.

## 1. Check how many birds visited today

- This task doesn't need recursion.
- Accessing the first element in a list can be done using a case expression.

## 2. Increment today's count

- This task doesn't need recursion.
- Accessing the first element in a list and the rest of the list can be done using a case expression.

## 3. Check if there was a day with no visiting birds

- Use recursion to iterate over elements in the list until a day with no visiting birds is found.
- The base case is an empty list.

## 4. Calculate the total number of visiting birds

- Use recursion to iterate over every element in the list.
- The base case is an empty list.

## 5. Calculate the number of busy days

- Use recursion to iterate over every element in the list.
- The base case is an empty list.
- Use a guard for one of the case expression clauses.
113 changes: 113 additions & 0 deletions gleam/bird-count/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Bird Count

Welcome to Bird Count on Exercism's Gleam Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)

## Introduction

## Recursion

The ability for something to be defined in terms of itself is called recursion. In Gleam, recursion is most commonly found in recursive functions, which are functions that call themselves.

A recursive function needs to have at least one _base case_ and at least one _recursive case_. A _base case_ returns a value without calling the function again. A _recursive case_ calls the function again, modifying the input so that it will at some point match the base case.

```gleam
pub fn factorial(x: Int) -> Int {
case x {
// Base case
1 -> 1
// Recursive case
_ -> x * factorial(x - 1)
}
}
```

Gleam has no special syntax for looping, so all looping is done with recursion.

```gleam
pub fn list_length(list: List(String)) -> Int {
case list {
[] -> 0
[_, ..rest] -> 1 + list_length(rest)
}
}
```

Gleam also supports recursive custom types. A recursive custom type has one or more of its variants refer to itself in their contained data.

```gleam
pub type RussianDoll {
Child // Base case
Mother(RussianDoll) // Recursive case
}
```
```gleam
let very_big_doll = Mother(Mother(Mother(Child)))
let small_doll = Mother(Child)
```

## Instructions

Izzy is an avid bird watcher that keeps track of how many birds have visited her garden on any given day.

She's asked you to help bring her bird watching to a new level and implement a few tools that will help her track and process the data.

You have chosen to store the data as a list of integers. The first number in the list is the number of birds that visited your garden today, the second yesterday, and so on.

## 1. Check how many birds visited today

Implement the `bird_count.today` function. It should take a list of daily bird counts and return today's count. If the list is empty, it should return `0`.

```gleam
bird_count.today([2, 5, 1])
// -> 2
```

## 2. Increment today's count

Implement the `bird_count.increment_day_count` function. It should take a list of daily bird counts and increment the today's count by 1. If the list is empty, return `[1]`.

```gleam
bird_count.increment_day_count([4, 0, 2])
// -> [5, 0, 2]
```

## 3. Check if there was a day with no visiting birds

Implement the `bird_count.has_day_without_birds` function. It should take a list of daily bird counts. It should return `true` if there was at least one day when no birds visited the garden, and `false` otherwise.

```gleam
bird_count.has_day_without_birds([2, 0, 4])
// -> true
bird_count.has_day_without_birds([3, 8, 1, 5])
// -> false
```

## 4. Calculate the total number of visiting birds

Implement the `bird_count.total` function. It should take a list of daily bird counts and return the total number that visited your garden since you started collecting the data.

```gleam
bird_count.total([4, 0, 9, 0, 5])
// -> 18
```

## 5. Calculate the number of busy days

Some days are busier than others. A busy day is one where five or more birds have visited your garden.

Implement the `bird_count.busy_days` function. It should take a list of daily bird counts and return the number of busy days.

```gleam
bird_count.busy_days([4, 5, 0, 0, 6])
// -> 2
```

## Source

### Created by

- @lpil
11 changes: 11 additions & 0 deletions gleam/bird-count/gleam.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name = "bird_count"
version = "0.1.0"

[dependencies]
gleam_bitwise = "~> 1.2"
gleam_otp = "~> 0.7"
gleam_stdlib = "~> 0.30"
simplifile = "~> 0.1"

[dev-dependencies]
exercism_test_runner = "~> 1.4"
25 changes: 25 additions & 0 deletions gleam/bird-count/manifest.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# This file was generated by Gleam
# You typically do not need to edit this file

packages = [
{ name = "exercism_test_runner", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "glance", "gleam_json", "gleam_community_ansi", "gleam_stdlib", "simplifile", "gap"], otp_app = "exercism_test_runner", source = "hex", outer_checksum = "336FBF790841C2DC25EB77B35E76A09EFDB9771D7D813E0FDBC71A50CB79711D" },
{ name = "gap", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_stdlib"], otp_app = "gap", source = "hex", outer_checksum = "AF290C27B3FAE5FE64E1B7E9C70A9E29AA0F42429C0592D375770C1C51B79D36" },
{ name = "glance", version = "0.7.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glexer"], otp_app = "glance", source = "hex", outer_checksum = "B646A08970990D9D7A103443C5CD46F9D4297BF05F188767777FCC14ADF395EA" },
{ name = "gleam_bitwise", version = "1.3.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_bitwise", source = "hex", outer_checksum = "E2A46EE42E5E9110DAD67E0F71E7358CBE54D5EC22C526DD48CBBA3223025792" },
{ name = "gleam_community_ansi", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_bitwise", "gleam_community_colour"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "6E4E0CF2B207C1A7FCD3C21AA43514D67BC7004F21F82045CDCCE6C727A14862" },
{ name = "gleam_community_colour", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_bitwise"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "D27CE357ECB343929A8CEC3FBA0B499943A47F0EE1F589EE16AFC2DC21C61E5B" },
{ name = "gleam_erlang", version = "0.22.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "367D8B41A7A86809928ED1E7E55BFD0D46D7C4CF473440190F324AFA347109B4" },
{ name = "gleam_json", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "C6CC5BEECA525117E97D0905013AB3F8836537455645DDDD10FE31A511B195EF" },
{ name = "gleam_otp", version = "0.7.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "ED7381E90636E18F5697FD7956EECCA635A3B65538DC2BE2D91A38E61DCE8903" },
{ name = "gleam_stdlib", version = "0.31.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "6D1BC5B4D4179B9FEE866B1E69FE180AC2CE485AD90047C0B32B2CA984052736" },
{ name = "glexer", version = "0.6.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glexer", source = "hex", outer_checksum = "703D2347F5180B2BCEA4D258549B0D91DACD0905010892BAC46D04D913B84D1F" },
{ name = "simplifile", version = "0.1.14", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "10EA0207796F20488A3A166C50A189C9385333F3C9FAC187729DE7B9CE4ADDBC" },
{ name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" },
]

[requirements]
exercism_test_runner = { version = "~> 1.4" }
gleam_bitwise = { version = "~> 1.2" }
gleam_otp = { version = "~> 0.7" }
gleam_stdlib = { version = "~> 0.30" }
simplifile = { version = "~> 0.1" }
36 changes: 36 additions & 0 deletions gleam/bird-count/src/bird_count.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
pub fn today(days: List(Int)) -> Int {
case days {
[] -> 0
[first, ..] -> first
}
}

pub fn increment_day_count(days: List(Int)) -> List(Int) {
case days {
[] -> [1]
[first, ..rest] -> [first + 1, ..rest]
}
}

pub fn has_day_without_birds(days: List(Int)) -> Bool {
case days {
[] -> False
[0, ..] -> True
[_first, ..rest] -> has_day_without_birds(rest)
}
}

pub fn total(days: List(Int)) -> Int {
case days {
[] -> 0
[first, ..rest] -> first + total(rest)
}
}

pub fn busy_days(days: List(Int)) -> Int {
case days {
[] -> 0
[first, ..rest] if first >= 5 -> 1 + busy_days(rest)
[_first, ..rest] -> busy_days(rest)
}
}
76 changes: 76 additions & 0 deletions gleam/bird-count/test/bird_count_test.gleam
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import bird_count
import exercism/test_runner
import exercism/should

pub fn main() {
test_runner.main()
}

pub fn today_returns_0_if_no_birds_were_seen_test() {
bird_count.today([])
|> should.equal(0)
}

pub fn today_returns_todays_bird_count_test() {
bird_count.today([7])
|> should.equal(7)

bird_count.today([2, 4, 11, 10, 6, 8])
|> should.equal(2)
}

pub fn today_create_entry_for_today_if_no_bird_watching_data_recorded_test() {
bird_count.increment_day_count([])
|> should.equal([1])
}

pub fn today_adds_1_to_todays_bird_count_test() {
bird_count.increment_day_count([7])
|> should.equal([8])

bird_count.increment_day_count([4, 2, 1, 0, 10])
|> should.equal([5, 2, 1, 0, 10])
}

pub fn has_day_without_birds_returns_false_if_no_bird_watching_data_recorded_test() {
let assert False = bird_count.has_day_without_birds([])
}

pub fn has_day_without_birds_returns_false_if_there_are_no_zeros_in_bird_watching_data_test() {
let assert False = bird_count.has_day_without_birds([1])
}

pub fn has_day_without_birds_returns_true_if_there_are_is_at_least_one_zero_in_bird_watching_data_test() {
let assert True = bird_count.has_day_without_birds([0])
let assert True = bird_count.has_day_without_birds([4, 4, 0, 1])
let assert True = bird_count.has_day_without_birds([0, 0, 3, 0, 5, 6, 0])
}

pub fn total_zero_if_no_bird_watching_data_recorded_test() {
bird_count.total([])
|> should.equal(0)
}

pub fn total_sums_up_bird_counts_test() {
bird_count.total([4])
|> should.equal(4)

bird_count.total([3, 0, 0, 4, 4, 0, 0, 10])
|> should.equal(21)
}

pub fn busy_days_zero_if_no_bird_watching_data_recorded_test() {
bird_count.busy_days([])
|> should.equal(0)
}

pub fn busy_days_counts_days_with_bird_count_of_5_or_more_test() {
bird_count.busy_days([1])
|> should.equal(0)

bird_count.busy_days([0, 5])
|> should.equal(1)

bird_count.busy_days([0, 6, 10, 4, 4, 5, 0])
|> should.equal(3)
}

0 comments on commit 685cb90

Please sign in to comment.