lib: move `examples/nitcorn` to `lib/nitcorn/examples`
[nit.git] / examples / draw_operation.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012-2013 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Draws an arithmetic operation to the terminal
18 module draw_operation
19
20 `{
21 #include <math.h>
22 `}
23
24 redef enum Int
25 fun n_chars: Int `{
26 int c;
27 if ( abs(self) >= 10 )
28 c = 1+(int)log10f( (float)abs(self) );
29 else
30 c = 1;
31 if ( self < 0 ) c ++;
32 return c;
33 `}
34 end
35
36 redef enum Char
37 fun as_operator(a, b: Int): Int
38 do
39 if self == '+' then return a + b
40 if self == '-' then return a - b
41 if self == '*' then return a * b
42 if self == '/' then return a / b
43 if self == '%' then return a % b
44 abort
45 end
46
47 fun override_dispc: Bool
48 do
49 return self == '+' or self == '-' or self == '*' or self == '/' or self == '%'
50 end
51
52 fun lines(s: Int): Array[Line]
53 do
54 if self == '+' then
55 return [new Line(new P(0,s/2),1,0,s), new Line(new P(s/2,1),0,1,s-2)]
56 else if self == '-' then
57 return [new Line(new P(0,s/2),1,0,s)]
58 else if self == '*' then
59 var lines = new Array[Line]
60 for y in [1..s-1[ do
61 lines.add( new Line(new P(1,y), 1,0,s-2) )
62 end
63 return lines
64 else if self == '/' then
65 return [new Line(new P(s-1,0), -1,1, s )]
66 else if self == '%' then
67 var q4 = s/4
68 var lines = [new Line(new P(s-1,0),-1,1,s)]
69 for l in [0..q4[ do
70 lines.append([ new Line( new P(0,l), 1,0,q4), new Line( new P(s-1,s-1-l), -1,0,q4) ])
71 end
72 return lines
73 else if self == '1' then
74 return [new Line(new P(s/2,0), 0,1,s),new Line(new P(0,s-1),1,0,s),
75 new Line( new P(s/2,0),-1,1,s/2)]
76 else if self == '2' then
77 return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s/2),
78 new Line( new P(0,s-1),1,0,s), new Line( new P(0,s/2), 0,1,s/2),
79 new Line( new P(0,s/2), 1,0,s)]
80 else if self == '3' then
81 return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s),
82 new Line( new P(0,s-1),1,0,s), new Line( new P(0,s/2), 1,0,s)]
83 else if self == '4' then
84 return [new Line(new P(s-1,0),0,1,s), new Line( new P(0,0), 0,1,s/2),
85 new Line( new P(0,s/2), 1,0,s)]
86 else if self == '5' then
87 return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,s/2),0,1,s/2),
88 new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s/2),
89 new Line( new P(0,s/2), 1,0,s)]
90 else if self == '6' then
91 return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,s/2),0,1,s/2),
92 new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s),
93 new Line( new P(0,s/2), 1,0,s)]
94 else if self == '7' then
95 var tl = new P(0,0)
96 var tr = new P(s-1,0)
97 return [new Line(tl, 1,0,s), new Line(tr,-1,1,s)]
98 else if self == '8' then
99 return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s),
100 new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s),
101 new Line( new P(0,s/2), 1,0,s)]
102 else if self == '9' then
103 return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s),
104 new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s/2),
105 new Line( new P(0,s/2), 1,0,s)]
106 else if self == '0' then
107 return [new Line(new P(0,0), 1,0,s),new Line(new P(s-1,0),0,1,s),
108 new Line( new P(0,s-1),1,0,s), new Line( new P(0,0), 0,1,s)]
109 end
110 return new Array[Line]
111 end
112 end
113
114 class P
115 var x : Int
116 var y : Int
117 end
118
119 redef class String
120 # hack is to support a bug in the evaluation software
121 fun draw(dispc: Char, size, gap: Int, hack: Bool)
122 do
123 var w = size * length +(length-1)*gap
124 var h = size
125 var map = new Array[Array[Char]]
126 for x in [0..w[ do
127 map[x] = new Array[Char].filled_with( ' ', h )
128 end
129
130 var ci = 0
131 for c in self.chars do
132 var local_dispc
133 if c.override_dispc then
134 local_dispc = c
135 else
136 local_dispc = dispc
137 end
138
139 var lines = c.lines( size )
140 for line in lines do
141 var x = line.o.x+ci*size
142 x += ci*gap
143 var y = line.o.y
144 for s in [0..line.len[ do
145 assert map.length > x and map[x].length > y else print "setting {x},{y} as {local_dispc}"
146 map[x][y] = local_dispc
147 x += line.step_x
148 y += line.step_y
149 end
150 end
151
152 ci += 1
153 end
154
155 if hack then
156 for c in [0..size[ do
157 map[c][0] = map[map.length-size+c][0]
158 map[map.length-size+c][0] = ' '
159 end
160 end
161
162 for y in [0..h[ do
163 for x in [0..w[ do
164 printn map[x][y]
165 end
166 print ""
167 end
168 end
169 end
170
171 class Line
172 var o : P
173 var step_x : Int
174 var step_y : Int
175 var len : Int
176 end
177
178 var a
179 var b
180 var op_char
181 var disp_char
182 var disp_size
183 var disp_gap
184
185 if "NIT_TESTING".environ == "true" then
186 a = 567
187 b = 13
188 op_char = '*'
189 disp_char = 'O'
190 disp_size = 8
191 disp_gap = 1
192 else
193 printn "Left operand: "
194 a = gets.to_i
195
196 printn "Right operand: "
197 b = gets.to_i
198
199 printn "Operator (+, -, *, /, %): "
200 op_char = gets.chars[0]
201
202 printn "Char to display: "
203 disp_char = gets.chars[0]
204
205 printn "Size of text: "
206 disp_size = gets.to_i
207
208 printn "Space between digits: "
209 disp_gap = gets.to_i
210 end
211
212 var result = op_char.as_operator( a, b )
213
214 var len_a = a.n_chars
215 var len_b = b.n_chars
216 var len_res = result.n_chars
217 var max_len = len_a.max( len_b.max( len_res ) ) + 1
218
219 # draw first line
220 var d = max_len - len_a
221 var line_a = ""
222 for i in [0..d[ do line_a += " "
223 line_a += a.to_s
224 line_a.draw( disp_char, disp_size, disp_gap, false )
225
226 print ""
227 # draw second line
228 d = max_len - len_b-1
229 var line_b = op_char.to_s
230 for i in [0..d[ do line_b += " "
231 line_b += b.to_s
232 line_b.draw( disp_char, disp_size, disp_gap, false )
233
234 # draw -----
235 print ""
236 for i in [0..disp_size*max_len+(max_len-1)*disp_gap] do
237 printn "_"
238 end
239 print ""
240 print ""
241
242 # draw result
243 d = max_len - len_res
244 var line_res = ""
245 for i in [0..d[ do line_res += " "
246 line_res += result.to_s
247 line_res.draw( disp_char, disp_size, disp_gap, false )