From a040c4337b2d0da19e556bb8c3bb10d5055da810 Mon Sep 17 00:00:00 2001 From: Cristiano Migali Date: Fri, 28 Aug 2020 19:42:10 +0200 Subject: [PATCH] changed the way trees get printed now trees are much nicer, this commit breaks the drawer API which is not anymore a 2d slice of bytes, insted it's a 2d slice of runes --- README.md | 34 ++++++++++++++-------------------- drawer/drawer.go | 22 +++++++++++----------- tree/tree.go | 32 +++++++++++++++++++++----------- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 749b689..63231d5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ type Tree struct { } ``` -**drawer** is a very simple "ascii-canvas" on which you can draw bytes representing ascii characters or another whole canvas specifying the coordinates of the upper-left corner. +**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. --- If you run the following in the root directory: @@ -28,30 +28,24 @@ you will get a binary that prints random trees to give you an idea. ``` ./treedrawer - 76 - | - 15 - / \ - / \ - / \ - / \ - 28 12 - / \ | - 94 63 39 + 14 + │ + 37 + ╭────┴────╮ + 97 29 + │ ╭──┴──╮ + 12 47 24 ``` With the **-l** flag you can specify the maximum number of layers of the random tree ``` ./treedrawer -l 3 - 14 - / \ - / \ - / \ - / \ - 45 84 - / \ / \ - 38 72 77 32 + 71 + │ + 60 + ╭──┴──╮ + 45 51 ``` # API ## Building the tree @@ -76,7 +70,7 @@ Tree type satisfies the Stringer interface, you can easily use fmt package to ge fmt.Println(t) 2 - / \ + ╭─┴─╮ 5 3 ``` ## Retreiving values from the tree diff --git a/drawer/drawer.go b/drawer/drawer.go index e0ade68..1064db1 100644 --- a/drawer/drawer.go +++ b/drawer/drawer.go @@ -2,17 +2,17 @@ package drawer import "fmt" -// Drawer is a canvas on which you can draw ascii bytes. +// Drawer is a canvas on which you can draw unicode runes. type Drawer struct { - canvas [][]byte + canvas [][]rune } // NewDrawer returns a new Drawer with width w and height h. func NewDrawer(w, h int) *Drawer { d := new(Drawer) - d.canvas = make([][]byte, h) + d.canvas = make([][]rune, h) for i := range d.canvas { - d.canvas[i] = make([]byte, w) + d.canvas[i] = make([]rune, w) } return d } @@ -20,19 +20,19 @@ func NewDrawer(w, h int) *Drawer { // NewDrawerFromString return a new Drawer which contains the string s. func NewDrawerFromString(s string) *Drawer { d := new(Drawer) - d.canvas = make([][]byte, 1) - d.canvas[0] = []byte(s) + d.canvas = make([][]rune, 1) + d.canvas[0] = []rune(s) return d } -// DrawByte draws a byte in position x, y in the drawer canvas. +// DrawRune draws a rune in position x, y in the drawer canvas. // Returns an error if the x, y position in input is outside the canvas. -func (d *Drawer) DrawByte(b byte, x, y int) error { +func (d *Drawer) DrawRune(r rune, x, y int) error { w, h := d.Dimens() if x >= w || y >= h { return fmt.Errorf("position (%d, %d) is outside the canvas of dimension (%d, %d)", x, y, w, h) } - d.canvas[y][x] = b + d.canvas[y][x] = r return nil } @@ -45,8 +45,8 @@ func (d *Drawer) DrawDrawer(e *Drawer, x, y int) error { return fmt.Errorf("canvas e of dimension (%d, %d) drawn in position (%d, %d) overflows canvas d of dimension (%d, %d)", eW, eH, x, y, w, h) } for i, row := range e.canvas { - for j, b := range row { - d.canvas[i+y][j+x] = b + for j, r := range row { + d.canvas[i+y][j+x] = r } } return nil diff --git a/tree/tree.go b/tree/tree.go index 60090e4..30d982b 100644 --- a/tree/tree.go +++ b/tree/tree.go @@ -125,7 +125,7 @@ func stringify(t *Tree) *drawer.Drawer { if err != nil { log.Fatal(fmt.Errorf("error while drawing val with one child: %v", err)) } - err = d.DrawByte('|', w/2, 1) + err = d.DrawRune('│', w/2, 1) if err != nil { log.Fatal(fmt.Errorf("error while drawing | with one child: %v", err)) } @@ -142,29 +142,39 @@ func stringify(t *Tree) *drawer.Drawer { maxChildW := int(math.Max(float64(dLeftW), float64(dRightW))) w := maxChildW*2 + 1 maxChildH := int(math.Max(float64(dLeftH), float64(dRightH))) - slashEndI := maxChildW/2 + 1 - edgeH := maxChildW - slashEndI - h := maxChildH + edgeH + 1 + h := maxChildH + 2 d := drawer.NewDrawer(w, h) err := d.DrawDrawer(dVal, (w-dValW)/2, 0) if err != nil { log.Fatal(fmt.Errorf("error while drawing val with two children: %v", err)) } - for i := 0; i < edgeH; i++ { - err = d.DrawByte('/', w/2-1-i, i+1) + err = d.DrawRune('┴', w/2, 1) + if err != nil { + log.Fatal(fmt.Errorf("error while drawing ┴ rune with two childern: %v", err)) + } + for i := 1; i <= maxChildW/2; i++ { + err = d.DrawRune('─', w/2-i, 1) if err != nil { - log.Fatal(fmt.Errorf("error while drawing / with two children: %v", err)) + log.Fatal(fmt.Errorf("error while drawing ─ rune with two childern with negative i: %v", err)) } - err = d.DrawByte('\\', w/2+1+i, i+1) + err = d.DrawRune('─', w/2+i, 1) if err != nil { - log.Fatal(fmt.Errorf("error while drawing \\ with two children: %v", err)) + log.Fatal(fmt.Errorf("error while drawing ─ rune with two childern with positive i: %v", err)) } } - d.DrawDrawer(dLeft, (maxChildW-dLeftW)/2, edgeH+1) + err = d.DrawRune('╭', w/2-maxChildW/2-1, 1) + if err != nil { + log.Fatal(fmt.Errorf("error while drawing ╭ rune with two children: %v", err)) + } + err = d.DrawRune('╮', w/2+maxChildW/2+1, 1) + if err != nil { + log.Fatal(fmt.Errorf("error while drawing ╮ rune with two children: %v", err)) + } + err = d.DrawDrawer(dLeft, (maxChildW-dLeftW)/2, 2) if err != nil { log.Fatal(fmt.Errorf("error while drawing left child: %v", err)) } - d.DrawDrawer(dRight, maxChildW+1+(maxChildW-dRightW)/2, edgeH+1) + err = d.DrawDrawer(dRight, maxChildW+1+(maxChildW-dRightW)/2, 2) if err != nil { log.Fatal(fmt.Errorf("error while drawing right child: %v", err)) }