|
| 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 | +} |
0 commit comments