Skip to content

Commit c428adc

Browse files
committed
adding source files to repo
1 parent b290452 commit c428adc

File tree

4 files changed

+261
-0
lines changed

4 files changed

+261
-0
lines changed

drawer/drawer.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package drawer
2+
3+
import "fmt"
4+
5+
// Drawer is a canvas on which you can draw ascii bytes.
6+
type Drawer struct {
7+
canvas [][]byte
8+
}
9+
10+
// NewDrawer returns a new Drawer with width w and height h.
11+
func NewDrawer(w, h int) *Drawer {
12+
d := new(Drawer)
13+
d.canvas = make([][]byte, h)
14+
for i := range d.canvas {
15+
d.canvas[i] = make([]byte, w)
16+
}
17+
return d
18+
}
19+
20+
// NewDrawerFromString return a new Drawer which contains the string s.
21+
func NewDrawerFromString(s string) *Drawer {
22+
d := new(Drawer)
23+
d.canvas = make([][]byte, 1)
24+
d.canvas[0] = []byte(s)
25+
return d
26+
}
27+
28+
// DrawByte draws a byte in position x, y in the drawer canvas.
29+
// Returns an error if the x, y position in input is outside the canvas.
30+
func (d *Drawer) DrawByte(b byte, x, y int) error {
31+
w, h := d.Dimens()
32+
if x >= w || y >= h {
33+
return fmt.Errorf("position (%d, %d) is outside the canvas of dimension (%d, %d)", x, y, w, h)
34+
}
35+
d.canvas[y][x] = b
36+
return nil
37+
}
38+
39+
// DrawDrawer draws the canvas inside e onto d with the up left corner in position x, y.
40+
// Returns an error if the canvas inside e, drawn in position x, y, overflows the canvas in d.
41+
func (d *Drawer) DrawDrawer(e *Drawer, x, y int) error {
42+
w, h := d.Dimens()
43+
eW, eH := e.Dimens()
44+
if x+eW-1 >= w || y+eH-1 >= h {
45+
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)
46+
}
47+
for i, row := range e.canvas {
48+
for j, b := range row {
49+
d.canvas[i+y][j+x] = b
50+
}
51+
}
52+
return nil
53+
}
54+
55+
// Dimens returns width and height of the canvas.
56+
func (d *Drawer) Dimens() (w, h int) {
57+
h, w = len(d.canvas), len(d.canvas[0])
58+
return
59+
}
60+
61+
// String returns the string representation of the canvas.
62+
func (d *Drawer) String() string {
63+
var s string
64+
for _, row := range d.canvas {
65+
for _, b := range row {
66+
if b == 0 {
67+
s += " "
68+
} else {
69+
s += string(b)
70+
}
71+
}
72+
s += "\n"
73+
}
74+
return s
75+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/SmashXric/treedrawer
2+
3+
go 1.14

tree/tree.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package tree
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"math"
7+
random "math/rand"
8+
"strconv"
9+
"time"
10+
11+
"github.com/SmashXric/treedrawer/drawer"
12+
)
13+
14+
func init() {
15+
random.Seed(time.Now().Unix())
16+
}
17+
18+
// Tree describes the node of a tree with atmost two children.
19+
type Tree struct {
20+
val int64
21+
left, right, parent *Tree
22+
}
23+
24+
// Val returns the value held by the current node of the tree.
25+
func (t *Tree) Val() int64 {
26+
return t.val
27+
}
28+
29+
// Left moves the current node to its left child.
30+
// returns false if there is no left child, otherwise it returns true.
31+
func (t *Tree) Left() (ok bool) {
32+
if t.left == nil {
33+
return false
34+
}
35+
t = t.left
36+
return true
37+
}
38+
39+
// Right moves the current node to its right child.
40+
// returns false if there is no right child, otherwise it returns true.
41+
func (t *Tree) Right() (ok bool) {
42+
if t.right == nil {
43+
return false
44+
}
45+
t = t.right
46+
return true
47+
}
48+
49+
// Parent moves the current node to its parent child.
50+
// returns false if this node is the root of the whole tree, otherwise it returns true.
51+
func (t *Tree) Parent() (ok bool) {
52+
if t.parent == nil {
53+
return false
54+
}
55+
t = t.parent
56+
return true
57+
}
58+
59+
// AddLeft adds a left child to the current node which will held val.
60+
func (t *Tree) AddLeft(val int64) {
61+
t.left = &Tree{val: val, parent: t}
62+
}
63+
64+
// AddRight adds a right child to the current node which will held val.
65+
func (t *Tree) AddRight(val int64) {
66+
t.right = &Tree{val: val, parent: t}
67+
}
68+
69+
// Rand returns the root of a random three with at most n layers.
70+
func Rand(n int) *Tree {
71+
t := new(Tree)
72+
rand(t, 0, n-1)
73+
return t
74+
}
75+
76+
func rand(t *Tree, curr, maxRecursion int) {
77+
t.val = random.Int63n(100)
78+
if curr == maxRecursion {
79+
return
80+
}
81+
if random.Int()%2 == 1 {
82+
t.AddLeft(0)
83+
rand(t.left, curr+1, maxRecursion)
84+
}
85+
if random.Int()%2 == 1 {
86+
t.AddRight(0)
87+
rand(t.right, curr+1, maxRecursion)
88+
}
89+
}
90+
91+
// String returns the string representation of the tree.
92+
func (t *Tree) String() string {
93+
return stringify(t).String()
94+
}
95+
96+
func stringify(t *Tree) *drawer.Drawer {
97+
dVal := drawer.NewDrawerFromString(strconv.Itoa(int(t.val)))
98+
dValW, _ := dVal.Dimens()
99+
if t.left == nil && t.right == nil {
100+
d := drawer.NewDrawer(dValW+2, 1)
101+
err := d.DrawDrawer(dVal, 1, 0)
102+
if err != nil {
103+
log.Fatal(fmt.Errorf("error while drawing val with no child: %v", err))
104+
}
105+
return d
106+
}
107+
108+
if (t.left != nil && t.right == nil) || (t.left == nil && t.right != nil) {
109+
var dChild *drawer.Drawer
110+
if t.left != nil {
111+
dChild = stringify(t.left)
112+
} else {
113+
dChild = stringify(t.right)
114+
}
115+
dChildW, dChildH := dChild.Dimens()
116+
w := int(math.Max(float64(dValW+2), float64(dChildW)))
117+
h := dChildH + 2
118+
d := drawer.NewDrawer(w, h)
119+
err := d.DrawDrawer(dVal, (w-dValW)/2, 0)
120+
if err != nil {
121+
log.Fatal(fmt.Errorf("error while drawing val with one child: %v", err))
122+
}
123+
err = d.DrawByte('|', w/2, 1)
124+
if err != nil {
125+
log.Fatal(fmt.Errorf("error while drawing | with one child: %v", err))
126+
}
127+
err = d.DrawDrawer(dChild, (w-dChildW)/2, 2)
128+
if err != nil {
129+
log.Fatal(fmt.Errorf("error while drawing child drawer with one child: %v", err))
130+
}
131+
return d
132+
}
133+
134+
dLeft, dRight := stringify(t.left), stringify(t.right)
135+
dLeftW, dLeftH := dLeft.Dimens()
136+
dRightW, dRightH := dRight.Dimens()
137+
maxChildW := int(math.Max(float64(dLeftW), float64(dRightW)))
138+
w := maxChildW*2 + 1
139+
maxChildH := int(math.Max(float64(dLeftH), float64(dRightH)))
140+
slashEndI := maxChildW/2 + 1
141+
edgeH := maxChildW - slashEndI + 1
142+
h := maxChildH + edgeH + 1
143+
d := drawer.NewDrawer(w, h)
144+
err := d.DrawDrawer(dVal, (w-dValW)/2, 0)
145+
if err != nil {
146+
log.Fatal(fmt.Errorf("error while drawing val with two children: %v", err))
147+
}
148+
for i := 0; i < edgeH; i++ {
149+
err = d.DrawByte('/', w/2-1-i, i+1)
150+
if err != nil {
151+
log.Fatal(fmt.Errorf("error while drawing / with two children: %v", err))
152+
}
153+
err = d.DrawByte('\\', w/2+1+i, i+1)
154+
if err != nil {
155+
log.Fatal(fmt.Errorf("error while drawing \\ with two children: %v", err))
156+
}
157+
}
158+
d.DrawDrawer(dLeft, (maxChildW-dLeftW)/2, edgeH)
159+
if err != nil {
160+
log.Fatal(fmt.Errorf("error while drawing left child: %v", err))
161+
}
162+
d.DrawDrawer(dRight, maxChildW+1+(maxChildW-dRightW)/2, edgeH)
163+
if err != nil {
164+
log.Fatal(fmt.Errorf("error while drawing right child: %v", err))
165+
}
166+
return d
167+
}

treedrawer.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
7+
"github.com/SmashXric/treedrawer/tree"
8+
)
9+
10+
var lFlag = flag.Int("l", 4, "Max number of layers in the random tree")
11+
12+
func main() {
13+
flag.Parse()
14+
t := tree.Rand(*lFlag)
15+
fmt.Println(t)
16+
}

0 commit comments

Comments
 (0)