From d3b30acaff897cd6a934e5e50d74f919c617a628 Mon Sep 17 00:00:00 2001 From: Robert Monnet Date: Tue, 3 Feb 2026 11:07:51 -0500 Subject: [PATCH 1/5] Created Binary Search Tree --- config.json | 8 ++ .../binary-search-tree/.docs/instructions.md | 70 ++++++++++++ .../binary-search-tree/.meta/config.json | 18 +++ .../binary-search-tree/.meta/example.odin | 11 ++ .../binary-search-tree/.meta/tests.toml | 40 +++++++ .../binary_search_tree.odin | 22 ++++ .../binary_search_tree_test.odin | 103 ++++++++++++++++++ 7 files changed, 272 insertions(+) create mode 100644 exercises/practice/binary-search-tree/.docs/instructions.md create mode 100644 exercises/practice/binary-search-tree/.meta/config.json create mode 100644 exercises/practice/binary-search-tree/.meta/example.odin create mode 100644 exercises/practice/binary-search-tree/.meta/tests.toml create mode 100644 exercises/practice/binary-search-tree/binary_search_tree.odin create mode 100644 exercises/practice/binary-search-tree/binary_search_tree_test.odin diff --git a/config.json b/config.json index 6e034b6..b8d01ca 100644 --- a/config.json +++ b/config.json @@ -409,6 +409,14 @@ "prerequisites": [], "difficulty": 5 }, + { + "slug": "binary-search-tree", + "name": "Binary Search Tree", + "uuid": "52957e98-b5c5-46c7-a55c-d5e14a12652f", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "book-store", "name": "Book Store", diff --git a/exercises/practice/binary-search-tree/.docs/instructions.md b/exercises/practice/binary-search-tree/.docs/instructions.md new file mode 100644 index 0000000..7625220 --- /dev/null +++ b/exercises/practice/binary-search-tree/.docs/instructions.md @@ -0,0 +1,70 @@ +# Instructions + +Insert and search for numbers in a binary tree. + +When we need to represent sorted data, an array does not make a good data structure. + +Say we have the array `[1, 3, 4, 5]`, and we add 2 to it so it becomes `[1, 3, 4, 5, 2]`. +Now we must sort the entire array again! +We can improve on this by realizing that we only need to make space for the new item `[1, nil, 3, 4, 5]`, and then adding the item in the space we added. +But this still requires us to shift many elements down by one. + +Binary Search Trees, however, can operate on sorted data much more efficiently. + +A binary search tree consists of a series of connected nodes. +Each node contains a piece of data (e.g. the number 3), a variable named `left`, and a variable named `right`. +The `left` and `right` variables point at `nil`, or other nodes. +Since these other nodes in turn have other nodes beneath them, we say that the left and right variables are pointing at subtrees. +All data in the left subtree is less than or equal to the current node's data, and all data in the right subtree is greater than the current node's data. + +For example, if we had a node containing the data 4, and we added the data 2, our tree would look like this: + +![A graph with root node 4 and a single child node 2.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2.svg) + +```text + 4 + / + 2 +``` + +If we then added 6, it would look like this: + +![A graph with root node 4 and two child nodes 2 and 6.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2-6.svg) + +```text + 4 + / \ + 2 6 +``` + +If we then added 3, it would look like this + +![A graph with root node 4, two child nodes 2 and 6, and a grandchild node 3.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2-6-3.svg) + +```text + 4 + / \ + 2 6 + \ + 3 +``` + +And if we then added 1, 5, and 7, it would look like this + +![A graph with root node 4, two child nodes 2 and 6, and four grandchild nodes 1, 3, 5 and 7.](https://assets.exercism.org/images/exercises/binary-search-tree/tree-4-2-6-1-3-5-7.svg) + +```text + 4 + / \ + / \ + 2 6 + / \ / \ + 1 3 5 7 +``` + +## Credit + +The images were created by [habere-et-dispertire][habere-et-dispertire] using [PGF/TikZ][pgf-tikz] by Till Tantau. + +[habere-et-dispertire]: https://exercism.org/profiles/habere-et-dispertire +[pgf-tikz]: https://en.wikipedia.org/wiki/PGF/TikZ diff --git a/exercises/practice/binary-search-tree/.meta/config.json b/exercises/practice/binary-search-tree/.meta/config.json new file mode 100644 index 0000000..f4f27ad --- /dev/null +++ b/exercises/practice/binary-search-tree/.meta/config.json @@ -0,0 +1,18 @@ +{ + "authors": [ + "rmonnet" + ], + "files": { + "solution": [ + "binary_search_tree.odin" + ], + "test": [ + "binary_search_tree_test.odin" + ], + "example": [ + ".meta/example.odin" + ] + }, + "blurb": "Insert and search for numbers in a binary tree.", + "source": "Josh Cheek" +} diff --git a/exercises/practice/binary-search-tree/.meta/example.odin b/exercises/practice/binary-search-tree/.meta/example.odin new file mode 100644 index 0000000..ce9d130 --- /dev/null +++ b/exercises/practice/binary-search-tree/.meta/example.odin @@ -0,0 +1,11 @@ +package binary_search_tree + +data :: proc() -> string { + // Implement this procedure. + return "" +} + +sorted_data :: proc() -> string { + // Implement this procedure. + return "" +} diff --git a/exercises/practice/binary-search-tree/.meta/tests.toml b/exercises/practice/binary-search-tree/.meta/tests.toml new file mode 100644 index 0000000..c7d3202 --- /dev/null +++ b/exercises/practice/binary-search-tree/.meta/tests.toml @@ -0,0 +1,40 @@ +# 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. + +[e9c93a78-c536-4750-a336-94583d23fafa] +description = "data is retained" + +[7a95c9e8-69f6-476a-b0c4-4170cb3f7c91] +description = "insert data at proper node -> smaller number at left node" + +[22b89499-9805-4703-a159-1a6e434c1585] +description = "insert data at proper node -> same number at left node" + +[2e85fdde-77b1-41ed-b6ac-26ce6b663e34] +description = "insert data at proper node -> greater number at right node" + +[dd898658-40ab-41d0-965e-7f145bf66e0b] +description = "can create complex tree" + +[9e0c06ef-aeca-4202-b8e4-97f1ed057d56] +description = "can sort data -> can sort single number" + +[425e6d07-fceb-4681-a4f4-e46920e380bb] +description = "can sort data -> can sort if second number is smaller than first" + +[bd7532cc-6988-4259-bac8-1d50140079ab] +description = "can sort data -> can sort if second number is same as first" + +[b6d1b3a5-9d79-44fd-9013-c83ca92ddd36] +description = "can sort data -> can sort if second number is greater than first" + +[d00ec9bd-1288-4171-b968-d44d0808c1c8] +description = "can sort data -> can sort complex tree" diff --git a/exercises/practice/binary-search-tree/binary_search_tree.odin b/exercises/practice/binary-search-tree/binary_search_tree.odin new file mode 100644 index 0000000..4ced9f8 --- /dev/null +++ b/exercises/practice/binary-search-tree/binary_search_tree.odin @@ -0,0 +1,22 @@ +package binary_search_tree + +Binary_Search_Tree :: struct {} + +bst_make :: proc() -> Binary_Search_Tree { + // Implement this procedure. + return Binary_Search_Tree +} + +bst_destroy :: proc(bst: ^Binary_Search_Tree) { + // Implement this procedure +} + +data :: proc() -> string { + // Implement this procedure. + return "" +} + +sorted_data :: proc() -> string { + // Implement this procedure. + return "" +} diff --git a/exercises/practice/binary-search-tree/binary_search_tree_test.odin b/exercises/practice/binary-search-tree/binary_search_tree_test.odin new file mode 100644 index 0000000..671181f --- /dev/null +++ b/exercises/practice/binary-search-tree/binary_search_tree_test.odin @@ -0,0 +1,103 @@ +package binary_search_tree + +import "core:testing" + +@(test) +/// description = data is retained +test_data_is_retained :: proc(t: ^testing.T) { + input := `{"treeData":["4"]}` + result := data(input) + expected := {"data":"4","left":null,"right":null} + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = insert data at proper node -> smaller number at left node +test_insert_data_at_proper_node___smaller_number_at_left_node :: proc(t: ^testing.T) { + input := `{"treeData":["4","2"]}` + result := data(input) + expected := {"data":"4","left":{"data":"2","left":null,"right":null},"right":null} + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = insert data at proper node -> same number at left node +test_insert_data_at_proper_node___same_number_at_left_node :: proc(t: ^testing.T) { + input := `{"treeData":["4","4"]}` + result := data(input) + expected := {"data":"4","left":{"data":"4","left":null,"right":null},"right":null} + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = insert data at proper node -> greater number at right node +test_insert_data_at_proper_node___greater_number_at_right_node :: proc(t: ^testing.T) { + input := `{"treeData":["4","5"]}` + result := data(input) + expected := {"data":"4","left":null,"right":{"data":"5","left":null,"right":null}} + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = can create complex tree +test_can_create_complex_tree :: proc(t: ^testing.T) { + input := `{"treeData":["4","2","6","1","3","5","7"]}` + result := data(input) + expected := {"data":"4","left":{"data":"2","left":{"data":"1","left":null,"right":null},"right":{"data":"3","left":null,"right":null}},"right":{"data":"6","left":{"data":"5","left":null,"right":null},"right":{"data":"7","left":null,"right":null}}} + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = can sort data -> can sort single number +test_can_sort_data___can_sort_single_number :: proc(t: ^testing.T) { + input := `{"treeData":["2"]}` + result := sorted_data(input) + expected := ["2"] + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = can sort data -> can sort if second number is smaller than first +test_can_sort_data___can_sort_if_second_number_is_smaller_than_first :: proc(t: ^testing.T) { + input := `{"treeData":["2","1"]}` + result := sorted_data(input) + expected := ["1","2"] + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = can sort data -> can sort if second number is same as first +test_can_sort_data___can_sort_if_second_number_is_same_as_first :: proc(t: ^testing.T) { + input := `{"treeData":["2","2"]}` + result := sorted_data(input) + expected := ["2","2"] + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = can sort data -> can sort if second number is greater than first +test_can_sort_data___can_sort_if_second_number_is_greater_than_first :: proc(t: ^testing.T) { + input := `{"treeData":["2","3"]}` + result := sorted_data(input) + expected := ["2","3"] + + testing.expect_value(t, result, expected) +} + +@(test) +/// description = can sort data -> can sort complex tree +test_can_sort_data___can_sort_complex_tree :: proc(t: ^testing.T) { + input := `{"treeData":["2","1","3","6","7","5"]}` + result := sorted_data(input) + expected := ["1","2","3","5","6","7"] + + testing.expect_value(t, result, expected) +} From 9328426a8d9a01a876c1067045ea857914d88eeb Mon Sep 17 00:00:00 2001 From: Robert Monnet Date: Tue, 3 Feb 2026 14:59:45 -0500 Subject: [PATCH 2/5] Completed fixing the tests and implementing the example solution For some reason, the problem spec shows tests verifying the structure of the tree nodes and other tests verifying the tree content is sorted. Since we leave it to the student to implement the Node data structure we can't really check the structure of the tree itself. The set of tests checking the structure of the tree after various combinations of `insert()` is redundant with the tests checking the tree is properly sorted since the only way to get the values sorted is to have the tree structure correct so we skiped these redundant tests (and marked them so in tests.toml). The alternative would be to provide the structure of the Node to the student to ensure we can test it. This doesn't seem as interesting an exercise. --- .../binary-search-tree/.meta/example.odin | 67 ++++++++- .../binary-search-tree/.meta/tests.toml | 10 ++ .../binary_search_tree.odin | 18 +-- .../binary_search_tree_test.odin | 140 +++++++++--------- 4 files changed, 149 insertions(+), 86 deletions(-) diff --git a/exercises/practice/binary-search-tree/.meta/example.odin b/exercises/practice/binary-search-tree/.meta/example.odin index ce9d130..010f30d 100644 --- a/exercises/practice/binary-search-tree/.meta/example.odin +++ b/exercises/practice/binary-search-tree/.meta/example.odin @@ -1,11 +1,66 @@ package binary_search_tree -data :: proc() -> string { - // Implement this procedure. - return "" +import "core:fmt" + +Tree :: ^Node + +Node :: struct { + value: int, + left: Tree, + right: Tree, +} + +destroy_tree :: proc(t: Tree) { + if t == nil { return } + destroy_tree(t.left) + destroy_tree(t.right) + free(t) +} + +insert :: proc(t: ^Tree, value: int) { + + if t^ == nil { + t^ = new(Node) + t^.value = value + return + } + + if value <= t^.value { + insert(&t^.left, value) + } else { + insert(&t^.right, value) + } } -sorted_data :: proc() -> string { - // Implement this procedure. - return "" +sorted_data :: proc(t: Tree) -> []int { + + if t == nil { return nil } + + acc: [dynamic]int + collect_data(t, &acc) + return acc[:] +} + +collect_data :: proc(t: Tree, acc: ^[dynamic]int) { + + if t == nil { return } + collect_data(t.left, acc) + append(acc, t.value) + collect_data(t.right, acc) +} + +main :: proc() { + + data := [?]int{4, 2} + input: Tree + for v in data[:] { + insert(&input, v) + } + result := sorted_data(input) + defer { + destroy_tree(input) + delete(result) + } + fmt.printf("%#v\n", input) + fmt.println(result) } diff --git a/exercises/practice/binary-search-tree/.meta/tests.toml b/exercises/practice/binary-search-tree/.meta/tests.toml index c7d3202..7ca4500 100644 --- a/exercises/practice/binary-search-tree/.meta/tests.toml +++ b/exercises/practice/binary-search-tree/.meta/tests.toml @@ -10,19 +10,29 @@ # is regenerated, comments can be added via a `comment` key. [e9c93a78-c536-4750-a336-94583d23fafa] +comment = "Intentionally omitted, redundant with 'can sort data -> can sort single number'" description = "data is retained" +include = false [7a95c9e8-69f6-476a-b0c4-4170cb3f7c91] +comment = "Intentionally omitted, redundant with 'can sort data -> can sort if second number is smaller than first'" description = "insert data at proper node -> smaller number at left node" +include = false [22b89499-9805-4703-a159-1a6e434c1585] +comment = "Intentionally omitted, redundant with 'can sort data -> can sort if second number is same as first'" description = "insert data at proper node -> same number at left node" +include = false [2e85fdde-77b1-41ed-b6ac-26ce6b663e34] +comment = "Intentionally omitted, redundant with 'can sort data -> can sort if second number is greater than first'" description = "insert data at proper node -> greater number at right node" +include = false [dd898658-40ab-41d0-965e-7f145bf66e0b] +comment = "Intentionally omitted, redundant with 'can sort data -> can sort complex tree'" description = "can create complex tree" +include = false [9e0c06ef-aeca-4202-b8e4-97f1ed057d56] description = "can sort data -> can sort single number" diff --git a/exercises/practice/binary-search-tree/binary_search_tree.odin b/exercises/practice/binary-search-tree/binary_search_tree.odin index 4ced9f8..1eb8f21 100644 --- a/exercises/practice/binary-search-tree/binary_search_tree.odin +++ b/exercises/practice/binary-search-tree/binary_search_tree.odin @@ -1,22 +1,20 @@ package binary_search_tree -Binary_Search_Tree :: struct {} +Tree :: ^Node -bst_make :: proc() -> Binary_Search_Tree { - // Implement this procedure. - return Binary_Search_Tree +Node :: struct { + // Implement the Node data structure. } -bst_destroy :: proc(bst: ^Binary_Search_Tree) { - // Implement this procedure +destroy_tree :: proc(t: Tree) { + // Implement this procedure. } -data :: proc() -> string { +insert :: proc(t: ^Tree, value: int) { // Implement this procedure. - return "" } -sorted_data :: proc() -> string { +sorted_data :: proc(t: Tree) -> []int { // Implement this procedure. - return "" + return nil } diff --git a/exercises/practice/binary-search-tree/binary_search_tree_test.odin b/exercises/practice/binary-search-tree/binary_search_tree_test.odin index 671181f..7af72bc 100644 --- a/exercises/practice/binary-search-tree/binary_search_tree_test.odin +++ b/exercises/practice/binary-search-tree/binary_search_tree_test.odin @@ -1,103 +1,103 @@ package binary_search_tree +import "core:fmt" import "core:testing" -@(test) -/// description = data is retained -test_data_is_retained :: proc(t: ^testing.T) { - input := `{"treeData":["4"]}` - result := data(input) - expected := {"data":"4","left":null,"right":null} - - testing.expect_value(t, result, expected) -} - -@(test) -/// description = insert data at proper node -> smaller number at left node -test_insert_data_at_proper_node___smaller_number_at_left_node :: proc(t: ^testing.T) { - input := `{"treeData":["4","2"]}` - result := data(input) - expected := {"data":"4","left":{"data":"2","left":null,"right":null},"right":null} - - testing.expect_value(t, result, expected) -} - -@(test) -/// description = insert data at proper node -> same number at left node -test_insert_data_at_proper_node___same_number_at_left_node :: proc(t: ^testing.T) { - input := `{"treeData":["4","4"]}` - result := data(input) - expected := {"data":"4","left":{"data":"4","left":null,"right":null},"right":null} - - testing.expect_value(t, result, expected) -} - -@(test) -/// description = insert data at proper node -> greater number at right node -test_insert_data_at_proper_node___greater_number_at_right_node :: proc(t: ^testing.T) { - input := `{"treeData":["4","5"]}` - result := data(input) - expected := {"data":"4","left":null,"right":{"data":"5","left":null,"right":null}} - - testing.expect_value(t, result, expected) -} - -@(test) -/// description = can create complex tree -test_can_create_complex_tree :: proc(t: ^testing.T) { - input := `{"treeData":["4","2","6","1","3","5","7"]}` - result := data(input) - expected := {"data":"4","left":{"data":"2","left":{"data":"1","left":null,"right":null},"right":{"data":"3","left":null,"right":null}},"right":{"data":"6","left":{"data":"5","left":null,"right":null},"right":{"data":"7","left":null,"right":null}}} - - testing.expect_value(t, result, expected) -} - @(test) /// description = can sort data -> can sort single number test_can_sort_data___can_sort_single_number :: proc(t: ^testing.T) { - input := `{"treeData":["2"]}` - result := sorted_data(input) - expected := ["2"] - testing.expect_value(t, result, expected) + data := [?]int{2} + input: Tree + for v in data[:] { + insert(&input, v) + } + result := sorted_data(input) + defer { + destroy_tree(input) + delete(result) + } + expect_slices(t, result, []int{2}) + } @(test) /// description = can sort data -> can sort if second number is smaller than first test_can_sort_data___can_sort_if_second_number_is_smaller_than_first :: proc(t: ^testing.T) { - input := `{"treeData":["2","1"]}` - result := sorted_data(input) - expected := ["1","2"] - testing.expect_value(t, result, expected) + data := [?]int{2, 1} + input: Tree + for v in data[:] { + insert(&input, v) + } + result := sorted_data(input) + defer { + destroy_tree(input) + delete(result) + } + expect_slices(t, result, []int{1, 2}) } @(test) /// description = can sort data -> can sort if second number is same as first test_can_sort_data___can_sort_if_second_number_is_same_as_first :: proc(t: ^testing.T) { - input := `{"treeData":["2","2"]}` - result := sorted_data(input) - expected := ["2","2"] - testing.expect_value(t, result, expected) + data := [?]int{2, 2} + input: Tree + for v in data[:] { + insert(&input, v) + } + result := sorted_data(input) + defer { + destroy_tree(input) + delete(result) + } + expect_slices(t, result, []int{2, 2}) } @(test) /// description = can sort data -> can sort if second number is greater than first test_can_sort_data___can_sort_if_second_number_is_greater_than_first :: proc(t: ^testing.T) { - input := `{"treeData":["2","3"]}` - result := sorted_data(input) - expected := ["2","3"] - testing.expect_value(t, result, expected) + data := [?]int{2, 3} + input: Tree + for v in data[:] { + insert(&input, v) + } + result := sorted_data(input) + defer { + destroy_tree(input) + delete(result) + } + expect_slices(t, result, []int{2, 3}) } @(test) /// description = can sort data -> can sort complex tree test_can_sort_data___can_sort_complex_tree :: proc(t: ^testing.T) { - input := `{"treeData":["2","1","3","6","7","5"]}` - result := sorted_data(input) - expected := ["1","2","3","5","6","7"] - testing.expect_value(t, result, expected) + data := [?]int{4, 2, 1, 3, 6, 7, 5} + input: Tree + for v in data[:] { + insert(&input, v) + } + result := sorted_data(input) + defer { + destroy_tree(input) + delete(result) + } + expect_slices(t, result, []int{1, 2, 3, 4, 5, 6, 7}) +} + +// Helper function to compare two slices and provide meaningful error messages. +expect_slices :: proc(t: ^testing.T, actual, expected: []$E, loc := #caller_location) { + + result := fmt.aprintf("%v", actual) + exp_str := fmt.aprintf("%v", expected) + defer { + delete(result) + delete(exp_str) + } + + testing.expect_value(t, result, exp_str, loc = loc) } From 0b5414075701438063a7dee1bce20f91d136f908 Mon Sep 17 00:00:00 2001 From: Robert Monnet Date: Tue, 3 Feb 2026 15:09:19 -0500 Subject: [PATCH 3/5] Remove testing code in example solution --- .../binary-search-tree/.meta/example.odin | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/exercises/practice/binary-search-tree/.meta/example.odin b/exercises/practice/binary-search-tree/.meta/example.odin index 010f30d..ed3c445 100644 --- a/exercises/practice/binary-search-tree/.meta/example.odin +++ b/exercises/practice/binary-search-tree/.meta/example.odin @@ -1,7 +1,5 @@ package binary_search_tree -import "core:fmt" - Tree :: ^Node Node :: struct { @@ -48,19 +46,3 @@ collect_data :: proc(t: Tree, acc: ^[dynamic]int) { append(acc, t.value) collect_data(t.right, acc) } - -main :: proc() { - - data := [?]int{4, 2} - input: Tree - for v in data[:] { - insert(&input, v) - } - result := sorted_data(input) - defer { - destroy_tree(input) - delete(result) - } - fmt.printf("%#v\n", input) - fmt.println(result) -} From 517e6dbeb8c4f79719fe27e8ec23a40e2c75265b Mon Sep 17 00:00:00 2001 From: Robert Monnet Date: Wed, 4 Feb 2026 13:46:36 -0500 Subject: [PATCH 4/5] Implemented comments from PR review Included the definition of Node in the solution stub, this is acceptable since "there is only one way to implement a binary search tree". With the Node definition, we can re-include the five skipped tests that just check that the constructed tree has the expected structure for all constructed nodes. Remove the include/comment from tests.toml that documented the skipped tests. Note that the resulting additional tests are way messier than in a language like Ruby. The main reasons are: 1. Odin tests are more verbose than ruby tests (`testing.expect...()`) 2. We need to deal with null nodes in the tree. Each node we want to check needs to be non-nil or this will crash the test. --- .../binary-search-tree/.meta/tests.toml | 10 - .../binary_search_tree.odin | 4 +- .../binary_search_tree_test.odin | 172 +++++++++++++++++- 3 files changed, 167 insertions(+), 19 deletions(-) diff --git a/exercises/practice/binary-search-tree/.meta/tests.toml b/exercises/practice/binary-search-tree/.meta/tests.toml index 7ca4500..c7d3202 100644 --- a/exercises/practice/binary-search-tree/.meta/tests.toml +++ b/exercises/practice/binary-search-tree/.meta/tests.toml @@ -10,29 +10,19 @@ # is regenerated, comments can be added via a `comment` key. [e9c93a78-c536-4750-a336-94583d23fafa] -comment = "Intentionally omitted, redundant with 'can sort data -> can sort single number'" description = "data is retained" -include = false [7a95c9e8-69f6-476a-b0c4-4170cb3f7c91] -comment = "Intentionally omitted, redundant with 'can sort data -> can sort if second number is smaller than first'" description = "insert data at proper node -> smaller number at left node" -include = false [22b89499-9805-4703-a159-1a6e434c1585] -comment = "Intentionally omitted, redundant with 'can sort data -> can sort if second number is same as first'" description = "insert data at proper node -> same number at left node" -include = false [2e85fdde-77b1-41ed-b6ac-26ce6b663e34] -comment = "Intentionally omitted, redundant with 'can sort data -> can sort if second number is greater than first'" description = "insert data at proper node -> greater number at right node" -include = false [dd898658-40ab-41d0-965e-7f145bf66e0b] -comment = "Intentionally omitted, redundant with 'can sort data -> can sort complex tree'" description = "can create complex tree" -include = false [9e0c06ef-aeca-4202-b8e4-97f1ed057d56] description = "can sort data -> can sort single number" diff --git a/exercises/practice/binary-search-tree/binary_search_tree.odin b/exercises/practice/binary-search-tree/binary_search_tree.odin index 1eb8f21..e007e85 100644 --- a/exercises/practice/binary-search-tree/binary_search_tree.odin +++ b/exercises/practice/binary-search-tree/binary_search_tree.odin @@ -3,7 +3,9 @@ package binary_search_tree Tree :: ^Node Node :: struct { - // Implement the Node data structure. + value: int, + left: Tree, + right: Tree, } destroy_tree :: proc(t: Tree) { diff --git a/exercises/practice/binary-search-tree/binary_search_tree_test.odin b/exercises/practice/binary-search-tree/binary_search_tree_test.odin index 7af72bc..90dcaa0 100644 --- a/exercises/practice/binary-search-tree/binary_search_tree_test.odin +++ b/exercises/practice/binary-search-tree/binary_search_tree_test.odin @@ -1,11 +1,167 @@ package binary_search_tree import "core:fmt" -import "core:testing" +import tt "core:testing" + +@(test) +/// description = data is retained +test_data_is_retained :: proc(t: ^tt.T) { + + data := [?]int{4} + tree: Tree + for v in data[:] { + insert(&tree, v) + } + defer destroy_tree(tree) + + tt.expect(t, tree != nil, "didn't expect tree to be null") + if tree == nil { return } + tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) + tt.expect(t, tree.left == nil, "expected tree.left to be nil") + tt.expect(t, tree.right == nil, "expected tree.right to be nil") +} + +@(test) +/// description = insert data at proper node -> smaller number at left node +test_insert_data_at_proper_node___smaller_number_at_left_node :: proc(t: ^tt.T) { + + data := [?]int{4, 2} + tree: Tree + for v in data[:] { + insert(&tree, v) + } + defer destroy_tree(tree) + + tt.expect(t, tree != nil, "didn't expect tree to be null") + if tree == nil { return } + tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) + tt.expect(t, tree.left != nil, "didn't expect tree.left to be nil") + if tree.left == nil { return } + tt.expectf(t, tree.left.value == 2, "expected tree.left.value to be 2 but got %d", tree.value) + tt.expect(t, tree.left.left == nil, "expected tree.left.left to be nil") + tt.expect(t, tree.left.right == nil, "expected tree.left.right to be nil") + tt.expect(t, tree.right == nil, "expected tree.right to be nil") +} + +@(test) +/// description = insert data at proper node -> same number at left node +test_insert_data_at_proper_node___same_number_at_left_node :: proc(t: ^tt.T) { + + data := [?]int{4, 4} + tree: Tree + for v in data[:] { + insert(&tree, v) + } + defer destroy_tree(tree) + + tt.expect(t, tree != nil, "didn't expect tree to be null") + if tree == nil { return } + tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) + tt.expect(t, tree.left != nil, "didn't expect tree.left to be nil") + if tree.left == nil { return } + tt.expectf(t, tree.left.value == 4, "expected tree.left.value to be 4 but got %d", tree.value) + tt.expect(t, tree.left.left == nil, "expected tree.left.left to be nil") + tt.expect(t, tree.left.right == nil, "expected tree.left.right to be nil") + tt.expect(t, tree.right == nil, "expected tree.right to be nil") +} + +@(test) +/// description = insert data at proper node -> greater number at right node +test_insert_data_at_proper_node___greater_number_at_right_node :: proc(t: ^tt.T) { + + data := [?]int{4, 5} + tree: Tree + for v in data[:] { + insert(&tree, v) + } + defer destroy_tree(tree) + + tt.expect(t, tree != nil, "didn't expect tree to be null") + if tree == nil { return } + tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) + tt.expect(t, tree.left == nil, "expected tree.left to be nil") + tt.expect(t, tree.right != nil, "didn't expect tree.right to be nil") + if tree.right == nil { return } + tt.expectf( + t, + tree.right.value == 5, + "expected tree.right.value to be 5 but got %d", + tree.value, + ) + tt.expect(t, tree.right.right == nil, "expected tree.right.right to be nil") + tt.expect(t, tree.right.right == nil, "expected tree.left.right to be nil") +} + +@(test) +/// description = can create complex tree +test_can_create_complex_tree :: proc(t: ^tt.T) { + + data := [?]int{4, 2, 6, 1, 3, 5, 7} + tree: Tree + for v in data[:] { + insert(&tree, v) + } + defer destroy_tree(tree) + + tt.expect(t, tree != nil, "didn't expect tree to be null") + if tree == nil { return } + tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) + tt.expect(t, tree.left != nil, "didn't expect tree.left to be nil") + if tree.left == nil { return } + tt.expectf(t, tree.left.value == 2, "expected tree.right.value to be 2 but got %d", tree.value) + tt.expect(t, tree.left.left != nil, "didn't expect tree.left.left to be nil") + if tree.left.left == nil { return } + tt.expectf( + t, + tree.left.left.value == 1, + "expected tree.left.left.value to be 1 but got %d", + tree.value, + ) + tt.expect(t, tree.left.left.left == nil, "expected tree.left.left.left to be nil") + tt.expect(t, tree.left.left.right == nil, "expected tree.left.left.right to be nil") + tt.expect(t, tree.left.right != nil, "didn't expect tree.left.right to be nil") + if tree.left.right == nil { return } + tt.expectf( + t, + tree.left.right.value == 3, + "expected tree.left.right.value to be 3 but got %d", + tree.value, + ) + tt.expect(t, tree.left.right.left == nil, "expected tree.left.right.left to be nil") + tt.expect(t, tree.left.right.right == nil, "expected tree.left.right.right to be nil") + tt.expectf(t, tree.right != nil, "didn't expect tree.right to be nil") + if tree.right == nil { return } + tt.expectf( + t, + tree.right.value == 6, + "expected tree.right.value to be 6 but got %d", + tree.value, + ) + tt.expect(t, tree.right.left != nil, "didn't expect tree.right.left to be nil") + if tree.right.left == nil { return } + tt.expectf( + t, + tree.right.left.value == 5, + "expected tree.right.left.value to be 5 but got %d", + tree.value, + ) + tt.expect(t, tree.right.left.left == nil, "expected tree.right.left.left to be nil") + tt.expect(t, tree.right.left.right == nil, "expected tree.right.left.right to be nil") + tt.expect(t, tree.right.right != nil, "didn't expect tree.right.right to be nil") + if tree.right.right == nil { return } + tt.expectf( + t, + tree.right.right.value == 7, + "expected tree.right.right.value to be 7 but got %d", + tree.value, + ) + tt.expect(t, tree.right.right.left == nil, "expected tree.right.right.left to be nil") + tt.expect(t, tree.right.right.right == nil, "expected tree.right.right.right to be nil") +} @(test) /// description = can sort data -> can sort single number -test_can_sort_data___can_sort_single_number :: proc(t: ^testing.T) { +test_can_sort_data___can_sort_single_number :: proc(t: ^tt.T) { data := [?]int{2} input: Tree @@ -23,7 +179,7 @@ test_can_sort_data___can_sort_single_number :: proc(t: ^testing.T) { @(test) /// description = can sort data -> can sort if second number is smaller than first -test_can_sort_data___can_sort_if_second_number_is_smaller_than_first :: proc(t: ^testing.T) { +test_can_sort_data___can_sort_if_second_number_is_smaller_than_first :: proc(t: ^tt.T) { data := [?]int{2, 1} input: Tree @@ -40,7 +196,7 @@ test_can_sort_data___can_sort_if_second_number_is_smaller_than_first :: proc(t: @(test) /// description = can sort data -> can sort if second number is same as first -test_can_sort_data___can_sort_if_second_number_is_same_as_first :: proc(t: ^testing.T) { +test_can_sort_data___can_sort_if_second_number_is_same_as_first :: proc(t: ^tt.T) { data := [?]int{2, 2} input: Tree @@ -57,7 +213,7 @@ test_can_sort_data___can_sort_if_second_number_is_same_as_first :: proc(t: ^test @(test) /// description = can sort data -> can sort if second number is greater than first -test_can_sort_data___can_sort_if_second_number_is_greater_than_first :: proc(t: ^testing.T) { +test_can_sort_data___can_sort_if_second_number_is_greater_than_first :: proc(t: ^tt.T) { data := [?]int{2, 3} input: Tree @@ -74,7 +230,7 @@ test_can_sort_data___can_sort_if_second_number_is_greater_than_first :: proc(t: @(test) /// description = can sort data -> can sort complex tree -test_can_sort_data___can_sort_complex_tree :: proc(t: ^testing.T) { +test_can_sort_data___can_sort_complex_tree :: proc(t: ^tt.T) { data := [?]int{4, 2, 1, 3, 6, 7, 5} input: Tree @@ -90,7 +246,7 @@ test_can_sort_data___can_sort_complex_tree :: proc(t: ^testing.T) { } // Helper function to compare two slices and provide meaningful error messages. -expect_slices :: proc(t: ^testing.T, actual, expected: []$E, loc := #caller_location) { +expect_slices :: proc(t: ^tt.T, actual, expected: []$E, loc := #caller_location) { result := fmt.aprintf("%v", actual) exp_str := fmt.aprintf("%v", expected) @@ -99,5 +255,5 @@ expect_slices :: proc(t: ^testing.T, actual, expected: []$E, loc := #caller_loca delete(exp_str) } - testing.expect_value(t, result, exp_str, loc = loc) + tt.expect_value(t, result, exp_str, loc = loc) } From 1250dcac72ad6d668768403e56beeabe378dccd9 Mon Sep 17 00:00:00 2001 From: Robert Monnet Date: Wed, 4 Feb 2026 21:16:48 -0500 Subject: [PATCH 5/5] Removed comments about nil on failed tests --- .../binary_search_tree_test.odin | 124 +++++++----------- 1 file changed, 47 insertions(+), 77 deletions(-) diff --git a/exercises/practice/binary-search-tree/binary_search_tree_test.odin b/exercises/practice/binary-search-tree/binary_search_tree_test.odin index 90dcaa0..6697791 100644 --- a/exercises/practice/binary-search-tree/binary_search_tree_test.odin +++ b/exercises/practice/binary-search-tree/binary_search_tree_test.odin @@ -14,11 +14,11 @@ test_data_is_retained :: proc(t: ^tt.T) { } defer destroy_tree(tree) - tt.expect(t, tree != nil, "didn't expect tree to be null") + tt.expect(t, tree != nil) if tree == nil { return } - tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) - tt.expect(t, tree.left == nil, "expected tree.left to be nil") - tt.expect(t, tree.right == nil, "expected tree.right to be nil") + tt.expect_value(t, tree.value, 4) + tt.expect(t, tree.left == nil) + tt.expect(t, tree.right == nil) } @(test) @@ -32,15 +32,15 @@ test_insert_data_at_proper_node___smaller_number_at_left_node :: proc(t: ^tt.T) } defer destroy_tree(tree) - tt.expect(t, tree != nil, "didn't expect tree to be null") + tt.expect(t, tree != nil) if tree == nil { return } - tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) - tt.expect(t, tree.left != nil, "didn't expect tree.left to be nil") + tt.expect_value(t, tree.value, 4) + tt.expect(t, tree.left != nil) if tree.left == nil { return } - tt.expectf(t, tree.left.value == 2, "expected tree.left.value to be 2 but got %d", tree.value) - tt.expect(t, tree.left.left == nil, "expected tree.left.left to be nil") - tt.expect(t, tree.left.right == nil, "expected tree.left.right to be nil") - tt.expect(t, tree.right == nil, "expected tree.right to be nil") + tt.expect_value(t, tree.left.value, 2) + tt.expect(t, tree.left.left == nil) + tt.expect(t, tree.left.right == nil) + tt.expect(t, tree.right == nil) } @(test) @@ -54,15 +54,15 @@ test_insert_data_at_proper_node___same_number_at_left_node :: proc(t: ^tt.T) { } defer destroy_tree(tree) - tt.expect(t, tree != nil, "didn't expect tree to be null") + tt.expect(t, tree != nil) if tree == nil { return } - tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) - tt.expect(t, tree.left != nil, "didn't expect tree.left to be nil") + tt.expect_value(t, tree.value, 4) + tt.expect(t, tree.left != nil) if tree.left == nil { return } - tt.expectf(t, tree.left.value == 4, "expected tree.left.value to be 4 but got %d", tree.value) - tt.expect(t, tree.left.left == nil, "expected tree.left.left to be nil") - tt.expect(t, tree.left.right == nil, "expected tree.left.right to be nil") - tt.expect(t, tree.right == nil, "expected tree.right to be nil") + tt.expect_value(t, tree.left.value, 4) + tt.expect(t, tree.left.left == nil) + tt.expect(t, tree.left.right == nil) + tt.expect(t, tree.right == nil) } @(test) @@ -76,20 +76,15 @@ test_insert_data_at_proper_node___greater_number_at_right_node :: proc(t: ^tt.T) } defer destroy_tree(tree) - tt.expect(t, tree != nil, "didn't expect tree to be null") + tt.expect(t, tree != nil) if tree == nil { return } - tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) - tt.expect(t, tree.left == nil, "expected tree.left to be nil") - tt.expect(t, tree.right != nil, "didn't expect tree.right to be nil") + tt.expect_value(t, tree.value, 4) + tt.expect(t, tree.left == nil) + tt.expect(t, tree.right != nil) if tree.right == nil { return } - tt.expectf( - t, - tree.right.value == 5, - "expected tree.right.value to be 5 but got %d", - tree.value, - ) - tt.expect(t, tree.right.right == nil, "expected tree.right.right to be nil") - tt.expect(t, tree.right.right == nil, "expected tree.left.right to be nil") + tt.expect_value(t, tree.right.value, 5) + tt.expect(t, tree.right.right == nil) + tt.expect(t, tree.right.right == nil) } @(test) @@ -103,60 +98,35 @@ test_can_create_complex_tree :: proc(t: ^tt.T) { } defer destroy_tree(tree) - tt.expect(t, tree != nil, "didn't expect tree to be null") + tt.expect(t, tree != nil) if tree == nil { return } - tt.expectf(t, tree.value == 4, "expected tree.value to be 4 but got %d", tree.value) - tt.expect(t, tree.left != nil, "didn't expect tree.left to be nil") + tt.expect_value(t, tree.value, 4) + tt.expect(t, tree.left != nil) if tree.left == nil { return } - tt.expectf(t, tree.left.value == 2, "expected tree.right.value to be 2 but got %d", tree.value) - tt.expect(t, tree.left.left != nil, "didn't expect tree.left.left to be nil") + tt.expect_value(t, tree.left.value, 2) + tt.expect(t, tree.left.left != nil) if tree.left.left == nil { return } - tt.expectf( - t, - tree.left.left.value == 1, - "expected tree.left.left.value to be 1 but got %d", - tree.value, - ) - tt.expect(t, tree.left.left.left == nil, "expected tree.left.left.left to be nil") - tt.expect(t, tree.left.left.right == nil, "expected tree.left.left.right to be nil") - tt.expect(t, tree.left.right != nil, "didn't expect tree.left.right to be nil") + tt.expect_value(t, tree.left.left.value, 1) + tt.expect(t, tree.left.left.left == nil) + tt.expect(t, tree.left.left.right == nil) + tt.expect(t, tree.left.right != nil) if tree.left.right == nil { return } - tt.expectf( - t, - tree.left.right.value == 3, - "expected tree.left.right.value to be 3 but got %d", - tree.value, - ) - tt.expect(t, tree.left.right.left == nil, "expected tree.left.right.left to be nil") - tt.expect(t, tree.left.right.right == nil, "expected tree.left.right.right to be nil") - tt.expectf(t, tree.right != nil, "didn't expect tree.right to be nil") + tt.expect_value(t, tree.left.right.value, 3) + tt.expect(t, tree.left.right.left == nil) + tt.expect(t, tree.left.right.right == nil) + tt.expect(t, tree.right != nil) if tree.right == nil { return } - tt.expectf( - t, - tree.right.value == 6, - "expected tree.right.value to be 6 but got %d", - tree.value, - ) - tt.expect(t, tree.right.left != nil, "didn't expect tree.right.left to be nil") + tt.expect_value(t, tree.right.value, 6) + tt.expect(t, tree.right.left != nil) if tree.right.left == nil { return } - tt.expectf( - t, - tree.right.left.value == 5, - "expected tree.right.left.value to be 5 but got %d", - tree.value, - ) - tt.expect(t, tree.right.left.left == nil, "expected tree.right.left.left to be nil") - tt.expect(t, tree.right.left.right == nil, "expected tree.right.left.right to be nil") - tt.expect(t, tree.right.right != nil, "didn't expect tree.right.right to be nil") + tt.expect_value(t, tree.right.left.value, 5) + tt.expect(t, tree.right.left.left == nil) + tt.expect(t, tree.right.left.right == nil) + tt.expect(t, tree.right.right != nil) if tree.right.right == nil { return } - tt.expectf( - t, - tree.right.right.value == 7, - "expected tree.right.right.value to be 7 but got %d", - tree.value, - ) - tt.expect(t, tree.right.right.left == nil, "expected tree.right.right.left to be nil") - tt.expect(t, tree.right.right.right == nil, "expected tree.right.right.right to be nil") + tt.expect_value(t, tree.right.right.value, 7) + tt.expect(t, tree.right.right.left == nil) + tt.expect(t, tree.right.right.right == nil) } @(test)