diff --git a/.tool-versions b/.tool-versions deleted file mode 100644 index 179f2a8c..00000000 --- a/.tool-versions +++ /dev/null @@ -1 +0,0 @@ -scarb 2.6.5 diff --git a/concepts/arrays/.meta/config.json b/concepts/arrays/.meta/config.json new file mode 100644 index 00000000..52914445 --- /dev/null +++ b/concepts/arrays/.meta/config.json @@ -0,0 +1,7 @@ +{ + "blurb": "", + "authors": [ + "misicnenad" + ], + "contributors": [] +} diff --git a/concepts/arrays/about.md b/concepts/arrays/about.md new file mode 100644 index 00000000..b0de00ea --- /dev/null +++ b/concepts/arrays/about.md @@ -0,0 +1 @@ +# Arrays diff --git a/concepts/arrays/introduction.md b/concepts/arrays/introduction.md new file mode 100644 index 00000000..e10b99d0 --- /dev/null +++ b/concepts/arrays/introduction.md @@ -0,0 +1 @@ +# Introduction diff --git a/concepts/arrays/links.json b/concepts/arrays/links.json new file mode 100644 index 00000000..fe51488c --- /dev/null +++ b/concepts/arrays/links.json @@ -0,0 +1 @@ +[] diff --git a/config.json b/config.json index 969f35c7..12c438d0 100644 --- a/config.json +++ b/config.json @@ -129,12 +129,24 @@ "name": "Roman Numerals", "uuid": "3fb4bd2f-bc5f-4a67-b9cc-49a786245876", "practices": [ - "tuples", - "traits", - "type-casting" + "tuples", + "traits", + "type-casting" ], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "binary-search", + "name": "Binary Search", + "uuid": "46be407d-13b8-4a7f-9a9a-4cef93485ba7", + "practices": [ + "arrays", + "enums", + "control-flow" + ], + "prerequisites": [], + "difficulty": 4 } ], "foregone": [ @@ -211,6 +223,11 @@ "uuid": "b0ea24b3-3520-42c2-9177-0550247fa2bd", "slug": "type-casting", "name": "Type Casting" + }, + { + "uuid": "6b6dafdb-7868-4089-855a-eb6735b5de5c", + "slug": "arrays", + "name": "Arrays" } ], "key_features": [ diff --git a/exercises/practice/binary-search/.docs/instructions.md b/exercises/practice/binary-search/.docs/instructions.md new file mode 100644 index 00000000..12f4358e --- /dev/null +++ b/exercises/practice/binary-search/.docs/instructions.md @@ -0,0 +1,29 @@ +# Instructions + +Your task is to implement a binary search algorithm. + +A binary search algorithm finds an item in a list by repeatedly splitting it in half, only keeping the half which contains the item we're looking for. +It allows us to quickly narrow down the possible locations of our item until we find it, or until we've eliminated all possible locations. + +~~~~exercism/caution +Binary search only works when a list has been sorted. +~~~~ + +The algorithm looks like this: + +- Find the middle element of a _sorted_ list and compare it with the item we're looking for. +- If the middle element is our item, then we're done! +- If the middle element is greater than our item, we can eliminate that element and all the elements **after** it. +- If the middle element is less than our item, we can eliminate that element and all the elements **before** it. +- If every element of the list has been eliminated then the item is not in the list. +- Otherwise, repeat the process on the part of the list that has not been eliminated. + +Here's an example: + +Let's say we're looking for the number 23 in the following sorted list: `[4, 8, 12, 16, 23, 28, 32]`. + +- We start by comparing 23 with the middle element, 16. +- Since 23 is greater than 16, we can eliminate the left half of the list, leaving us with `[23, 28, 32]`. +- We then compare 23 with the new middle element, 28. +- Since 23 is less than 28, we can eliminate the right half of the list: `[23]`. +- We've found our item. diff --git a/exercises/practice/binary-search/.docs/introduction.md b/exercises/practice/binary-search/.docs/introduction.md new file mode 100644 index 00000000..03496599 --- /dev/null +++ b/exercises/practice/binary-search/.docs/introduction.md @@ -0,0 +1,13 @@ +# Introduction + +You have stumbled upon a group of mathematicians who are also singer-songwriters. +They have written a song for each of their favorite numbers, and, as you can imagine, they have a lot of favorite numbers (like [0][zero] or [73][seventy-three] or [6174][kaprekars-constant]). + +You are curious to hear the song for your favorite number, but with so many songs to wade through, finding the right song could take a while. +Fortunately, they have organized their songs in a playlist sorted by the title — which is simply the number that the song is about. + +You realize that you can use a binary search algorithm to quickly find a song given the title. + +[zero]: https://en.wikipedia.org/wiki/0 +[seventy-three]: https://en.wikipedia.org/wiki/73_(number) +[kaprekars-constant]: https://en.wikipedia.org/wiki/6174_(number) diff --git a/exercises/practice/binary-search/.meta/config.json b/exercises/practice/binary-search/.meta/config.json new file mode 100644 index 00000000..fcf1366b --- /dev/null +++ b/exercises/practice/binary-search/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [], + "files": { + "solution": [ + "src/lib.cairo", + "Scarb.toml" + ], + "test": [ + "src/tests.cairo" + ], + "example": [ + ".meta/example.cairo" + ] + }, + "blurb": "Implement a binary search algorithm.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/Binary_search_algorithm" +} diff --git a/exercises/practice/binary-search/.meta/example.cairo b/exercises/practice/binary-search/.meta/example.cairo new file mode 100644 index 00000000..1df11abf --- /dev/null +++ b/exercises/practice/binary-search/.meta/example.cairo @@ -0,0 +1,26 @@ +pub fn find, +Copy, +PartialOrd>( + search_array: @Array, value: T +) -> Option { + let mut base = 0_usize; + let mut slice: Span = search_array.span(); + + loop { + let head = slice.slice(0, slice.len() / 2); + let mut tail = slice.slice(slice.len() / 2, slice.len() - head.len()); + if let Option::Some(middle_element) = tail.pop_front() { + if *middle_element < value { + base += head.len() + 1; + slice = tail.slice(0, tail.len()); + } else if *middle_element > value { + slice = head; + } else { + break Option::Some(base + head.len()); + } + } else { + break Option::None; + } + } +} + +#[cfg(test)] +mod tests; diff --git a/exercises/practice/binary-search/.meta/tests.toml b/exercises/practice/binary-search/.meta/tests.toml new file mode 100644 index 00000000..61e2b068 --- /dev/null +++ b/exercises/practice/binary-search/.meta/tests.toml @@ -0,0 +1,43 @@ +# 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. + +[b55c24a9-a98d-4379-a08c-2adcf8ebeee8] +description = "finds a value in an array with one element" + +[73469346-b0a0-4011-89bf-989e443d503d] +description = "finds a value in the middle of an array" + +[327bc482-ab85-424e-a724-fb4658e66ddb] +description = "finds a value at the beginning of an array" + +[f9f94b16-fe5e-472c-85ea-c513804c7d59] +description = "finds a value at the end of an array" + +[f0068905-26e3-4342-856d-ad153cadb338] +description = "finds a value in an array of odd length" + +[fc316b12-c8b3-4f5e-9e89-532b3389de8c] +description = "finds a value in an array of even length" + +[da7db20a-354f-49f7-a6a1-650a54998aa6] +description = "identifies that a value is not included in the array" + +[95d869ff-3daf-4c79-b622-6e805c675f97] +description = "a value smaller than the array's smallest value is not found" + +[8b24ef45-6e51-4a94-9eac-c2bf38fdb0ba] +description = "a value larger than the array's largest value is not found" + +[f439a0fa-cf42-4262-8ad1-64bf41ce566a] +description = "nothing is found in an empty array" + +[2c353967-b56d-40b8-acff-ce43115eed64] +description = "nothing is found when the left and right bounds cross" diff --git a/exercises/practice/binary-search/Scarb.toml b/exercises/practice/binary-search/Scarb.toml new file mode 100644 index 00000000..59336f43 --- /dev/null +++ b/exercises/practice/binary-search/Scarb.toml @@ -0,0 +1,4 @@ +[package] +name = "binary_search" +version = "0.1.0" +edition = "2023_11" diff --git a/exercises/practice/binary-search/src/lib.cairo b/exercises/practice/binary-search/src/lib.cairo new file mode 100644 index 00000000..080c6cc6 --- /dev/null +++ b/exercises/practice/binary-search/src/lib.cairo @@ -0,0 +1,8 @@ +pub fn find(search_array: @Array, value: usize) -> Option { + panic!( + "Using the binary search algorithm, find the element '{value}' in the array '{search_array:?}' and return its index." + ) +} + +#[cfg(test)] +mod tests; diff --git a/exercises/practice/binary-search/src/tests.cairo b/exercises/practice/binary-search/src/tests.cairo new file mode 100644 index 00000000..9a65558d --- /dev/null +++ b/exercises/practice/binary-search/src/tests.cairo @@ -0,0 +1,81 @@ +use binary_search::find; + +#[test] +fn finds_a_value_in_an_array_with_one_element() { + let arr: Array = array![6]; + assert_eq!(find(@arr, 6), Option::Some(0)); +} + +#[test] +fn finds_first_value_in_an_array_with_two_element() { + let arr: Array = array![1, 2]; + assert_eq!(find(@arr, 1), Option::Some(0)); +} + +#[test] +fn finds_second_value_in_an_array_with_two_element() { + let arr: Array = array![1, 2]; + assert_eq!(find(@arr, 2), Option::Some(1)); +} + +#[test] +fn finds_a_value_in_the_middle_of_an_array() { + let arr: Array = array![1, 3, 4, 6, 8, 9, 11]; + assert_eq!(find(@arr, 6), Option::Some(3)); +} + +#[test] +fn finds_a_value_at_the_beginning_of_an_array() { + let arr: Array = array![1, 3, 4, 6, 8, 9, 11]; + assert_eq!(find(@arr, 1), Option::Some(0)); +} + +#[test] +fn finds_a_value_at_the_end_of_an_array() { + let arr: Array = array![1, 3, 4, 6, 8, 9, 11]; + assert_eq!(find(@arr, 11), Option::Some(6)); +} + +#[test] +fn finds_a_value_in_an_array_of_odd_length() { + let arr: Array = array![1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 634]; + assert_eq!(find(@arr, 144), Option::Some(9)); +} + +#[test] +fn finds_a_value_in_an_array_of_even_length() { + let arr: Array = array![1, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]; + assert_eq!(find(@arr, 21), Option::Some(5)); +} + +const OPTION_NONE: Option = Option::None; + +#[test] +fn identifies_that_a_value_is_not_included_in_the_array() { + let arr: Array = array![1, 3, 4, 6, 8, 9, 11]; + assert_eq!(find(@arr, 7), OPTION_NONE); +} + +#[test] +fn a_value_smaller_than_the_arrays_smallest_value_is_not_found() { + let arr: Array = array![1, 3, 4, 6, 8, 9, 11]; + assert_eq!(find(@arr, 0), OPTION_NONE); +} + +#[test] +fn a_value_larger_than_the_arrays_largest_value_is_not_found() { + let arr: Array = array![1, 3, 4, 6, 8, 9, 11]; + assert_eq!(find(@arr, 13), OPTION_NONE); +} + +#[test] +fn nothing_is_found_in_an_empty_array() { + let arr: Array = array![]; + assert_eq!(find(@arr, 1), OPTION_NONE); +} + +#[test] +fn nothing_is_found_when_the_left_and_right_bounds_cross() { + let arr: Array = array![1, 2]; + assert_eq!(find(@arr, 0), OPTION_NONE); +}