-
Notifications
You must be signed in to change notification settings - Fork 9
/
asciicanvas.py
162 lines (150 loc) · 5.98 KB
/
asciicanvas.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#-*- coding: utf-8 -*-
#-----------------------------------------------------------------------
# Author: delimitry
#-----------------------------------------------------------------------
class AsciiCanvas(object):
"""
ASCII canvas for drawing in console using ASCII chars
"""
def __init__(self, cols, lines, fill_char=' '):
"""
Initialize ASCII canvas
"""
if cols < 1 or cols > 1000 or lines < 1 or lines > 1000:
raise Exception('Canvas cols/lines must be in range [1..1000]')
self.cols = cols
self.lines = lines
if not fill_char:
fill_char = ' '
elif len(fill_char) > 1:
fill_char = fill_char[0]
self.fill_char = fill_char
self.canvas = [[fill_char] * (cols) for _ in range(lines)]
def clear(self):
"""
Fill canvas with empty chars
"""
self.canvas = [[self.fill_char] * (self.cols) for _ in range(self.lines)]
def print_out(self):
"""
Print out canvas to console
"""
print(self.get_canvas_as_str())
def add_line(self, x0, y0, x1, y1, fill_char='o'):
"""
Add ASCII line (x0, y0 -> x1, y1) to the canvas, fill line with `fill_char`
"""
if not fill_char:
fill_char = 'o'
elif len(fill_char) > 1:
fill_char = fill_char[0]
if x0 > x1:
# swap A and B
x1, x0 = x0, x1
y1, y0 = y0, y1
# get delta x, y
dx = x1 - x0
dy = y1 - y0
# if a length of line is zero just add point
if dx == 0 and dy == 0:
if self.check_coord_in_range(x0, y0):
self.canvas[y0][x0] = fill_char
return
# when dx >= dy use fill by x-axis, and use fill by y-axis otherwise
if abs(dx) >= abs(dy):
for x in range(x0, x1 + 1):
y = y0 if dx == 0 else y0 + int(round((x - x0) * dy / float((dx))))
if self.check_coord_in_range(x, y):
self.canvas[y][x] = fill_char
else:
if y0 < y1:
for y in range(y0, y1 + 1):
x = x0 if dy == 0 else x0 + int(round((y - y0) * dx / float((dy))))
if self.check_coord_in_range(x, y):
self.canvas[y][x] = fill_char
else:
for y in range(y1, y0 + 1):
x = x0 if dy == 0 else x1 + int(round((y - y1) * dx / float((dy))))
if self.check_coord_in_range(x, y):
self.canvas[y][x] = fill_char
def add_text(self, x, y, text):
"""
Add text to canvas at position (x, y)
"""
for i, c in enumerate(text):
if self.check_coord_in_range(x + i, y):
self.canvas[y][x + i] = c
def add_rect(self, x, y, w, h, fill_char=' ', outline_char='o'):
"""
Add rectangle filled with `fill_char` and outline with `outline_char`
"""
if not fill_char:
fill_char = ' '
elif len(fill_char) > 1:
fill_char = fill_char[0]
if not outline_char:
outline_char = 'o'
elif len(outline_char) > 1:
outline_char = outline_char[0]
for px in range(x, x + w):
for py in range(y, y + h):
if self.check_coord_in_range(px, py):
if px == x or px == x + w - 1 or py == y or py == y + h - 1:
self.canvas[py][px] = outline_char
else:
self.canvas[py][px] = fill_char
def add_nine_patch_rect(self, x, y, w, h, outline_3x3_chars=None):
"""
Add nine-patch rectangle
"""
default_outline_3x3_chars = (
'.', '-', '.',
'|', ' ', '|',
'`', '-', "'"
)
if not outline_3x3_chars:
outline_3x3_chars = default_outline_3x3_chars
# filter chars
filtered_outline_3x3_chars = []
for index, char in enumerate(outline_3x3_chars[0:9]):
if not char:
char = default_outline_3x3_chars[index]
elif len(char) > 1:
char = char[0]
filtered_outline_3x3_chars.append(char)
for px in range(x, x + w):
for py in range(y, y + h):
if self.check_coord_in_range(px, py):
if px == x and py == y:
self.canvas[py][px] = filtered_outline_3x3_chars[0]
elif px == x and y < py < y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[3]
elif px == x and py == y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[6]
elif x < px < x + w - 1 and py == y:
self.canvas[py][px] = filtered_outline_3x3_chars[1]
elif x < px < x + w - 1 and py == y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[7]
elif px == x + w - 1 and py == y:
self.canvas[py][px] = filtered_outline_3x3_chars[2]
elif px == x + w - 1 and y < py < y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[5]
elif px == x + w - 1 and py == y + h - 1:
self.canvas[py][px] = filtered_outline_3x3_chars[8]
else:
self.canvas[py][px] = filtered_outline_3x3_chars[4]
def check_coord_in_range(self, x, y):
"""
Check that coordinate (x, y) is in range, to prevent out of range error
"""
return 0 <= x < self.cols and 0 <= y < self.lines
def get_canvas_as_str(self):
"""
Return canvas as a string
"""
return '\n'.join([''.join(col) for col in self.canvas])
def __str__(self):
"""
Return canvas as a string
"""
return self.get_canvas_as_str()