-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
removed a bug regarding width calc of the NewDrawer in NodeString.Draw()
- Loading branch information
Showing
4 changed files
with
207 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,174 @@ | ||
# treedrawer | ||
treedrawer is a simple go module that will help you to visualize binary trees in the command line. | ||
# Motivation | ||
I started to build this module by trying to solve an exercise on "The Go Programming Language". The task was to implement the String() function of a binary tree. | ||
# Code structure | ||
This module has two sub-packages: | ||
* treedrawer/**tree** | ||
* treedrawer/**drawer** | ||
|
||
**tree** provides a simple representation of a binary tree: | ||
**treedrawer** is a Go module that will help you drawing trees to console like the one below. | ||
``` | ||
╭─╮ | ||
│9│ | ||
╰┬╯ | ||
╭─────────────────┴─────────────┬─────────────┬───┬───╮ | ||
╭──────────┴─────────╮ ╭┴╮ ╭┴╮ ╭┴╮ ╭┴╮ | ||
│I can handle strings│ │1│ │2│ │3│ │4│ | ||
╰──────────┬─────────╯ ╰┬╯ ╰─╯ ╰─╯ ╰─╯ | ||
│ ╭─────┬──┴─────╮ | ||
╭────────────────┴────────────────╮ ╭─┴─╮ ╭─┴╮ ╭────┴───╮ | ||
│with as many children as you want│ │124│ │13│ │a string│ | ||
╰────────────────┬────────────────╯ ╰───╯ ╰──╯ ╰────────╯ | ||
│ | ||
╭───────────────┴───────────────╮ | ||
│with as many layers as you want│ | ||
╰───────────────┬───────────────╯ | ||
│ | ||
╭─────────────────┴─────────────────╮ | ||
│actually I can handle everything...│ | ||
╰─────────────────┬─────────────────╯ | ||
│ | ||
╭──────────────────┴──────────────────╮ | ||
│...that satisfies NodeValue interface│ | ||
╰─────────────────────────────────────╯ | ||
``` | ||
## Import | ||
```go | ||
import "github.com/m1gwings/treedrawer/tree" | ||
``` | ||
// Tree describes the node of a tree with atmost two children. | ||
type Tree struct { | ||
val int64 | ||
left, right, parent *Tree | ||
} | ||
## Quick start | ||
```sh | ||
# Assume the following code is in example.go file | ||
$ cat example.go | ||
``` | ||
```go | ||
package main | ||
|
||
**drawer** is a very simple "unicode-canvas" on which you can draw runes representing unicode characters or another whole canvas specifying the coordinates of the upper-left corner. | ||
import ( | ||
"fmt" | ||
|
||
--- | ||
If you run the following in the root directory: | ||
``` | ||
go build . | ||
``` | ||
"github.com/m1gwings/treedrawer/tree" | ||
) | ||
|
||
you will get a binary that prints random trees to give you an idea. | ||
``` | ||
./treedrawer | ||
func main() { | ||
// Creating a tree with 5 as the value of the root node | ||
t := tree.NewTree(tree.NodeInt64(5)) | ||
|
||
14 | ||
│ | ||
37 | ||
╭────┴────╮ | ||
97 29 | ||
│ ╭──┴──╮ | ||
12 47 24 | ||
// Adding children | ||
t.AddChild(tree.NodeString("adding a string")) | ||
t.AddChild(tree.NodeInt64(4)) | ||
t.AddChild(tree.NodeInt64(3)) | ||
|
||
// Drawing the tree | ||
fmt.Println(t) | ||
} | ||
``` | ||
```sh | ||
$ go run example.go | ||
``` | ||
```sh | ||
╭─╮ | ||
│5│ | ||
╰┬╯ | ||
╭───┴──────┬───╮ | ||
╭───────┴───────╮ ╭┴╮ ╭┴╮ | ||
│adding a string│ │4│ │3│ | ||
╰───────────────╯ ╰─╯ ╰─╯ | ||
|
||
With the **-l** flag you can specify the maximum number of layers of the random tree | ||
``` | ||
./treedrawer -l 3 | ||
## Usage | ||
### Building the tree | ||
Creating the tree with 1 as the value of the root node | ||
```go | ||
t := tree.NewTree(tree.NodeInt64(1)) | ||
``` | ||
Adding the first child to t with value 2 | ||
```go | ||
t.AddChild(tree.NodeInt64(2)) | ||
``` | ||
Adding more children | ||
```go | ||
t.AddChild(tree.NodeInt64(3)) | ||
t.AddChild(tree.NodeInt64(4)) | ||
t.AddChild(tree.NodeInt64(5)) | ||
``` | ||
We've just built the tree below | ||
``` | ||
╭─╮ | ||
│1│ | ||
╰┬╯ | ||
╭───┬─┴─┬───╮ | ||
╭┴╮ ╭┴╮ ╭┴╮ ╭┴╮ | ||
│2│ │3│ │4│ │5│ | ||
╰─╯ ╰─╯ ╰─╯ ╰─╯ | ||
71 | ||
│ | ||
60 | ||
╭──┴──╮ | ||
45 51 | ||
``` | ||
# Import | ||
In order to use the tree API below import the following: | ||
### Navigating the tree | ||
Navigating to first child of t (we're still working with the tree above) | ||
```go | ||
// This method returns an error if the i-th child does not exist | ||
// in this case i = 0 | ||
tFirstChild, err := t.Child(0) | ||
``` | ||
Adding children to first child | ||
```go | ||
tFirstChild.AddChild(tree.NodeInt64(6)) | ||
tFirstChild.AddChild(tree.NodeInt64(7)) | ||
tFirstChild.AddChild(tree.NodeInt64(8)) | ||
``` | ||
Going back to parent | ||
```go | ||
// ok would be equal to false if tFirstChild were the root of the tree | ||
tFirstChildParent, ok := tFirstChild.Parent() | ||
|
||
_ := tFirstChildParent == t // true, we have gone back to the root of the tree | ||
``` | ||
import "github.com/m1gwings/treedrawer/tree" | ||
Navigating to third child of t | ||
```go | ||
tThirdChild, err := t.Child(2) | ||
``` | ||
# API | ||
## Building the tree | ||
### func NewTree(val int64) *Tree | ||
NewTree is the default constructor for Tree. | ||
Adding a string child to third child | ||
```go | ||
tThirdChild.AddChild(tree.NodeString("I'm a string")) | ||
``` | ||
t := tree.NewTree(2) | ||
Getting a pointer to the root of the tree | ||
```go | ||
tRoot := tThirdChild.Root() | ||
|
||
_ := tRoot == t // true | ||
``` | ||
Now the tree looks like this | ||
``` | ||
╭─╮ | ||
│1│ | ||
╰┬╯ | ||
╭───────┬───┴─────┬─────────╮ | ||
╭┴╮ ╭┴╮ ╭┴╮ ╭┴╮ | ||
│2│ │3│ │4│ │5│ | ||
╰┬╯ ╰─╯ ╰┬╯ ╰─╯ | ||
╭───┼───╮ │ | ||
╭┴╮ ╭┴╮ ╭┴╮ ╭──────┴─────╮ | ||
│6│ │7│ │8│ │I'm a string│ | ||
╰─╯ ╰─╯ ╰─╯ ╰────────────╯ | ||
``` | ||
### func (t *Tree) AddLeft(val int64) | ||
AddLeft adds a left child to the current node which will held val. | ||
### Getting and setting values from the tree | ||
Getting the value of a node | ||
```go | ||
v := t.Val() | ||
``` | ||
t.AddLeft(5) | ||
Setting the value of a node | ||
```go | ||
t.SetVal(tree.NodeInt64(3)) | ||
``` | ||
### func (t *Tree) AddRight(val int64) | ||
AddRight adds a right child to the current node which will held val. | ||
### Drawing the tree | ||
*tree.Tree implements the Stringer interface, just use fmt to draw trees to console | ||
```go | ||
fmt.Println(t) | ||
``` | ||
t.AddRight(3) | ||
### Implementing NodeValue interface | ||
## Examples | ||
## Known issues | ||
- Emojis are larger than normal characters | ||
```go | ||
fmt.Println(tree.NewTree(tree.NodeString("emojis are buggy 🤪"))) | ||
``` | ||
## Printing the tree | ||
Tree type satisfies the Stringer interface, you can easily use fmt package to get results in the console. | ||
``` | ||
fmt.Println(t) | ||
╭──────────────────╮ | ||
│emojis are buggy 🤪│ | ||
╰──────────────────╯ | ||
2 | ||
╭─┴─╮ | ||
5 3 | ||
``` | ||
## Retreiving values from the tree | ||
### func (t *Tree) Val() int64 | ||
Val returns the value held by the current node of the tree. | ||
## Navigating the tree | ||
### func (t *Tree) Left() (ok bool) | ||
Left moves the current node to its left child. | ||
Returns false if there is no left child, otherwise it returns true. | ||
### func (t *Tree) Right() (ok bool) | ||
Right moves the current node to its right child. | ||
Returns false if there is no right child, otherwise it returns true. | ||
### func (t *Tree) Parent() (ok bool) | ||
Parent moves the current node to its parent. | ||
Returns false if this node is the root of the whole tree, otherwise it returns true. | ||
## Extra | ||
### func Rand(n int) *Tree | ||
Rand returns the root of a random three with at most n layers. | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package tree | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"testing" | ||
) | ||
|
||
func TestShowcase(t *testing.T) { | ||
tr := NewTree(NodeInt64(9)) | ||
tr.AddChild(NodeString("I can handle strings")) | ||
tr.AddChild(NodeInt64(1)) | ||
tr.AddChild(NodeInt64(2)) | ||
tr.AddChild(NodeInt64(3)) | ||
tr.AddChild(NodeInt64(4)) | ||
tr, err := tr.Child(1) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
tr.AddChild(NodeInt64(124)) | ||
tr.AddChild(NodeInt64(13)) | ||
tr.AddChild(NodeString("a string")) | ||
tr, ok := tr.Parent() | ||
if !ok { | ||
log.Fatal(fmt.Errorf("this child should have a parent")) | ||
} | ||
tr, err = tr.Child(0) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
tr.AddChild(NodeString("with as many children as you want")) | ||
tr, err = tr.Child(0) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
tr.AddChild(NodeString("with as many layers as you want")) | ||
tr, err = tr.Child(0) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
tr.AddChild(NodeString("actually I can handle everything...")) | ||
tr, err = tr.Child(0) | ||
if err != nil { | ||
log.Fatal(err) | ||
} | ||
tr.AddChild(NodeString("...that satisfies NodeValue interface")) | ||
|
||
fmt.Println(tr) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters