-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolver.v
299 lines (233 loc) · 5.61 KB
/
solver.v
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
import os
import strconv
struct Term {
mut:
tokens []string
is_operator bool
precedence int
}
fn main() {
input_equation := os.input('Enter your equation: ')
terms := get_term_list(input_equation)
postfix_notation := infix_to_postfix(terms)
evaluated_answer := evaluate_postfix(postfix_notation)
if evaluated_answer.stack.len > 0 {
mut answer := evaluate_tokens(evaluated_answer.stack[0].tokens)
// Cast int64 if number is an integer
if i64(answer) == answer {
println(i64(answer))
exit(0)
}
println(answer)
} else {
println('error :P')
exit(1)
}
exit(0)
}
/*** Stack ***/
struct Stack {
mut:
stack []Term
}
fn (mut stack Stack) push (term Term) {
if term.tokens.len == 0 {
return
}
stack.stack << term
}
fn (mut stack Stack) pop () Term {
if stack.stack.len > 0 {
ret := stack.stack[stack.stack.len-1]
stack.stack = stack.stack[0..stack.stack.len-1]
return ret
}
return Term{}
}
fn (mut stack Stack) get_top () Term {
if stack.stack.len > 0 {
return stack.stack[stack.stack.len-1]
}
return Term{}
}
/******/
fn evaluate_postfix(stack Stack) Stack {
mut oop_stack := Stack{}
mut tmp1 := Term{}
mut tmp2 := Term{}
for _, term in stack.stack {
if !term.is_operator {
oop_stack.push(term)
}else{
tmp1 = oop_stack.pop()
tmp2 = oop_stack.pop()
mut result := ""
match term.tokens[0] {
'*' {
result = strconv.f64_to_str_l(evaluate_tokens(tmp1.tokens) * evaluate_tokens(tmp2.tokens))
}
'/' {
result = strconv.f64_to_str_l(evaluate_tokens(tmp2.tokens) / evaluate_tokens(tmp1.tokens))
}
'+' {
result = strconv.f64_to_str_l(evaluate_tokens(tmp1.tokens) + evaluate_tokens(tmp2.tokens))
}
'-' {
result = strconv.f64_to_str_l(evaluate_tokens(tmp2.tokens) - evaluate_tokens(tmp1.tokens))
}
else {}
}
mut output := []string{}
for _, rbyte in result {
output << rbyte.ascii_str()
}
result_term := Term{
tokens: output
}
// Push output of last evaluation to stack
oop_stack.push(result_term)
}
}
return oop_stack
}
fn infix_to_postfix(terms []Term) Stack {
// Convert infix to postfix notation
mut output := Stack{}
mut operator_stack := Stack{}
outer: for _, term in terms {
if !term.is_operator {
output.push(term)
}else{
// term is an operator
if operator_stack.stack.len == 0 {
operator_stack.push(term)
continue outer
}
for {
top_of_stack := operator_stack.get_top()
if term.precedence > top_of_stack.precedence {
operator_stack.push(term)
continue outer
}
if term.precedence == top_of_stack.precedence {
output.push(operator_stack.pop())
operator_stack.push(term)
continue outer
}
if term.precedence < top_of_stack.precedence {
output.push(operator_stack.pop())
continue
}
}
}
}
// Sort remaining terms by precedence
operator_stack.stack.sort(a.precedence > b.precedence)
// Push all remaining terms to the output stack
if operator_stack.stack.len > 0 {
for _, item in operator_stack.stack {
output.push(item)
}
}
return output
}
fn evaluate_tokens(tokens []string) f64 {
// Find possibly existing decimal point
if '.' in tokens {
mut built_string := ""
for _, s_token in tokens {
built_string += s_token
}
return strconv.atof64(built_string)
}
// Working from left to right to create a number
mut return_number := 0.0
for index, token in tokens {
mut number := strconv.atoi(token) or {
return 0.0
}
zeros := tokens.len - index
for i := 0; i < zeros-1; i++ {
number = number * 10
}
return_number += number
}
return return_number
}
fn get_term_list (equation string) []Term {
operators := ["*", "/", "+", "-"]
numbers := ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
tokens := gen_token_list(equation)
mut working_tokens_list := tokens.clone()
mut terms := []Term{}
mut working_term := Term{}
mut used_term_indexes := []int{}
outer: for index, token in working_tokens_list {
if 0 == index && token in operators {
eprintln("First character cannot be an operation.")
exit(1)
}
if !(token in operators) && !(token in numbers) {
eprintln("Equation can only contain numbers or one of: * / + -")
exit(1)
}
if index in used_term_indexes {
continue
}
if 0 != index && token in operators {
working_term = Term{}
working_term.tokens << token
working_term.is_operator = true
working_term.precedence = 1
match token {
'/' { working_term.precedence = 1 }
'+' { working_term.precedence = 0 }
'-' { working_term.precedence = 0 }
else {}
}
// term is complete, append to array
terms << working_term
// reset working term
working_term = Term{}
used_term_indexes << index
continue
}
if token in numbers {
working_term = Term{}
working_term.tokens << token
if equation.len == 1 {
continue
}
if index+1 > tokens.len {
break
}
used_term_indexes << index
// find the rest of the number
for sub_index, sub_token in tokens[index+1..tokens.len] {
if !(sub_token in operators) {
if used_term_indexes.len > 0 {
used_term_indexes << used_term_indexes[used_term_indexes.len-1]+1
}else{
used_term_indexes << sub_index+1
}
working_term.tokens << sub_token
continue
}else{
break
}
}
// term is complete, append to array
terms << working_term
// reset working term
working_term = Term{}
}
}
return terms
}
fn gen_token_list (equation string) []string {
mut tokens := []string{}
for index, _ in equation {
tokens << equation[index..index+1]
}
return tokens
}