Skip to content

Commit eae48cc

Browse files
committed
Allow changing connectors
1 parent d820ff5 commit eae48cc

File tree

1 file changed

+20
-32
lines changed

1 file changed

+20
-32
lines changed

vicutils/printBin.py

Lines changed: 20 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# Default configuration constants
44
DEFAULT_UNIT_SIZE = 3
5-
DEFAULT_VALUE_FILL_CHAR = " " # Character used to pad node values (e.g., "_5_")
5+
DEFAULT_VALUE_FILL_CHAR = "_" # Character used to pad node values (e.g., "_5_")
66
DEFAULT_CONNECTOR_FILL_CHAR = "_" # Character used to fill horizontal gaps between node pairs
77

88

@@ -31,7 +31,6 @@ class BinaryNode:
3131
>>> # 4 5 7
3232
"""
3333
def __init__(self, val=0, left=None, right=None):
34-
# If val is a list, build tree from it
3534
if isinstance(val, list):
3635
if not val or val[0] is None:
3736
raise ValueError("Cannot create tree from empty list or list starting with None")
@@ -46,13 +45,11 @@ def __init__(self, val=0, left=None, right=None):
4645
while queue and i < len(val):
4746
node = queue.pop(0)
4847

49-
# Add left child
5048
if i < len(val) and val[i] is not None:
5149
node.left = BinaryNode(val[i])
5250
queue.append(node.left)
5351
i += 1
5452

55-
# Add right child
5653
if i < len(val) and val[i] is not None:
5754
node.right = BinaryNode(val[i])
5855
queue.append(node.right)
@@ -106,13 +103,13 @@ def mapNodesToCodes(node, valueFillChar, unitSize, code="", memo=None):
106103
return memo
107104

108105

109-
def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=None, unitSize=None, removeEmpty=True):
106+
def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=None, unitSize=None, removeEmpty=True, connectors="/\\"):
110107
"""
111108
Converts a binary tree into a 2D matrix representation for visualization.
112109
113110
The matrix includes:
114111
- Even rows (0, 2, 4...): Node values
115-
- Odd rows (1, 3, 5...): Connection lines (/ and \\)
112+
- Odd rows (1, 3, 5...): Connection lines (using connectors)
116113
117114
Args:
118115
node: The root node of the tree to visualize
@@ -121,6 +118,7 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=
121118
connectorFillChar: Character for filling horizontal gaps between node pairs
122119
unitSize: Size for centering values
123120
removeEmpty: Whether to remove empty leading columns
121+
connectors: Two-character string for connectors (e.g., "/\\" or "||"), None to skip connector rows
124122
"""
125123
if unitSize is None:
126124
unitSize = DEFAULT_UNIT_SIZE
@@ -129,66 +127,56 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=
129127
if connectorFillChar is None:
130128
connectorFillChar = DEFAULT_CONNECTOR_FILL_CHAR
131129

130+
if connectors is not None and len(connectors) != 2:
131+
connectors = "/\\"
132+
132133
if depth == -1:
133134
depth = getDepth(node)
134135

135-
# Map all nodes to their binary path codes
136136
tree = mapNodesToCodes(node, valueFillChar, unitSize)
137137

138-
# Cache frequently used values
139-
numCols = 2 ** depth - 1 # Number of leaf positions (columns)
140-
numRows = 2 * depth - 1 # Total rows (values + connectors)
138+
numCols = 2 ** depth - 1
139+
numRows = 2 * depth - 1
141140

142-
# Initialize matrix with space-centered empty cells
143141
mat = [[center("", unitSize=unitSize, fillChar=" ") for _ in range(numCols)] for _ in range(numRows)]
144142

145-
# Start with all even column indices (where values can be placed)
146143
valueIndexes = [i for i in range(numCols) if i % 2 == 0]
147144
prevValueIndexes = None
148145

149-
# Build matrix from bottom to top
150146
for level in range(numRows - 1, -1, -1):
151-
# Odd levels: place connection characters (/ and \)
152147
if level % 2 != 0:
153-
for i, index in enumerate(valueIndexes):
154-
mat[level][index] = [center("/", unitSize=unitSize, fillChar=" "),
155-
center("\\", unitSize=unitSize, fillChar=" ")][i % 2]
148+
if connectors is not None:
149+
for i, index in enumerate(valueIndexes):
150+
mat[level][index] = [center(connectors[0], unitSize=unitSize, fillChar=" "),
151+
center(connectors[1], unitSize=unitSize, fillChar=" ")][i % 2]
156152

157-
# Calculate parent positions (midpoints between child pairs)
158153
nextValueIndexes = []
159154
for i in range(0, len(valueIndexes) - 1, 2):
160155
nextValueIndexes.append((valueIndexes[i] + valueIndexes[i + 1]) // 2)
161156
valueIndexes = nextValueIndexes
162157
continue
163158

164-
# Even levels: place node values
165-
# Generate all binary codes for current level
166159
codes = list(product(*["01" for _ in range(level // 2)]))
167160
codes = ["".join(code) for code in codes]
168161

169162
for i, index in enumerate(valueIndexes):
170163
if codes[i] in tree:
171164
mat[level][index] = tree[codes[i]]
172165

173-
# Fill horizontal gaps between node pairs using connectorFillChar
174166
if prevValueIndexes is not None:
175167
for i in range(0, len(prevValueIndexes), 2):
176168
if i + 1 < len(prevValueIndexes):
177-
# Calculate parent position (should not be overwritten)
178169
parentCol = (prevValueIndexes[i] + prevValueIndexes[i + 1]) // 2
179-
# Fill columns between children, except parent position
180170
for col in range(prevValueIndexes[i] + 1, prevValueIndexes[i + 1]):
181171
if col != parentCol:
182172
mat[level][col] = center("", unitSize=unitSize, fillChar=connectorFillChar)
183173

184-
# Save current valueIndexes for next even level
185174
prevValueIndexes = valueIndexes
186175

187-
# Remove empty leading columns if requested
188176
if removeEmpty:
189177
centeredSpace = center("", unitSize=unitSize, fillChar=" ")
190-
centeredSlash = center("/", unitSize=unitSize, fillChar=" ")
191-
centeredBackslash = center("\\", unitSize=unitSize, fillChar=" ")
178+
centeredSlash = center(connectors[0] if connectors else "/", unitSize=unitSize, fillChar=" ")
179+
centeredBackslash = center(connectors[1] if connectors else "\\", unitSize=unitSize, fillChar=" ")
192180

193181
for i in range(numCols):
194182
remove = all(
@@ -203,7 +191,7 @@ def nodeToMat(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=
203191
return mat
204192

205193

206-
def nodeToString(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=None, unitSize=None, removeEmpty=True, showConnectors=True):
194+
def nodeToString(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillChar=None, unitSize=None, removeEmpty=True, connectors="/\\"):
207195
"""
208196
Converts a binary tree into a string representation for visualization.
209197
@@ -214,13 +202,13 @@ def nodeToString(node: BinaryNode, depth=-1, valueFillChar=None, connectorFillCh
214202
connectorFillChar: Character for filling horizontal gaps between node pairs
215203
unitSize: Size for centering values
216204
removeEmpty: Whether to remove empty leading columns
217-
showConnectors: Whether to show connector lines (/ and \) between nodes
205+
connectors: Two-character string for connectors (e.g., "/\\" or "||"), None to skip connector rows
218206
"""
219207
mat = nodeToMat(node, depth=depth, valueFillChar=valueFillChar,
220-
connectorFillChar=connectorFillChar, unitSize=unitSize, removeEmpty=removeEmpty)
208+
connectorFillChar=connectorFillChar, unitSize=unitSize,
209+
removeEmpty=removeEmpty, connectors=connectors)
221210

222-
if showConnectors:
211+
if connectors is not None:
223212
return "\n".join("".join(row) for row in mat)
224213
else:
225-
# Only include even rows (node values, skip odd rows with connectors)
226214
return "\n".join("".join(mat[i]) for i in range(0, len(mat), 2))

0 commit comments

Comments
 (0)