1use serde::{Deserialize, Serialize};
2use std::io::{self, Read};
3use std::sync::OnceLock;
4
5const MAX_DECIMAL_PLACES: usize = 100;
7type Dec = dec::Decimal<MAX_DECIMAL_PLACES>;
10
11static DECIMAL_PLACES: OnceLock<usize> = OnceLock::new();
12static NAN: OnceLock<String> = OnceLock::new();
13
14#[derive(Debug, Deserialize, Serialize, Clone)]
15pub enum TreeNode {
16 Op(char, Box<TreeNode>, Box<TreeNode>),
17 Num(i32),
18 Var(String),
19 Fun(String, Box<TreeNode>), Paren(Box<TreeNode>),
21 Empty,
22}
23
24#[derive(Debug, Deserialize, Serialize, Clone)]
26pub struct BinaryAlgebraicExpressionTree {
27 pub name: String,
28 pub root_node: TreeNode,
29}
30
31#[derive(Clone, Debug, Serialize, Deserialize)]
33pub struct TestCase {
34 pub description: Option<String>,
36 pub examples: Vec<[String; 2]>,
38 pub solution: Vec<BinaryAlgebraicExpressionTree>,
39}
40
41impl Default for BinaryAlgebraicExpressionTree {
42 fn default() -> Self {
43 BinaryAlgebraicExpressionTree {
44 name: "NEW".to_string(),
45 root_node: parse_expression("1"),
46 }
47 }
48}
49
50fn get_decimal_places() -> usize {
51 *DECIMAL_PLACES.get_or_init(|| MAX_DECIMAL_PLACES)
52}
53
54fn get_nan() -> &'static String {
55 NAN.get_or_init(|| format!("-0.{}1", "0".repeat(get_decimal_places())))
56}
57
58pub fn read_terminal_input() {
60 let mut use_math_tricks = false;
61 let args: Vec<String> = std::env::args().skip(1).collect();
62 if args.len() == 1
63 && let Some(first_line) = args[0].trim().lines().next()
64 && first_line.trim().starts_with("DECIMAL_PLACES(x)=")
65 {
66 use_math_tricks = true;
67 if let Some(k_str) = first_line.trim().strip_prefix("DECIMAL_PLACES(x)=") {
68 let k_clean = k_str.split_whitespace().next().unwrap_or(k_str);
69 if let Ok(k) = k_clean.parse::<usize>() {
70 let _ = DECIMAL_PLACES.set(k);
71 let _ = NAN.set(format!("-0.{}1", "0".repeat(k)));
72 }
73 }
74 }
75 let input = if args.len() == 1 && args[0].contains('\n') {
76 args[0]
77 .split('\n')
78 .map(|s| s.trim())
79 .filter(|s| !s.is_empty())
80 .map(|s| s.to_string())
81 .collect()
82 } else if args.is_empty() {
83 let mut buffer = String::new();
84 io::stdin().read_to_string(&mut buffer).unwrap();
85 buffer
86 .split('\n')
87 .map(|s| s.trim())
88 .filter(|s| !s.is_empty())
89 .map(|s| s.to_string())
90 .collect()
91 } else {
92 args
93 };
94 if input.is_empty() {
95 println!(
96 "Usage:\n single-variable-algebra-compiler FUNC1(x)=expr1 FUNC2(x)=expr2 ... FUNCN(INPUT)\nOR\n echo 'F(x)=4+4\nG(x)=F(x)*2\nG(1)' | single-variable-algebra-compiler"
97 );
98 return;
99 }
100 let mut trees = Vec::new();
101 for arg in input.iter().take(input.len() - 1) {
102 if let Some((name, expr)) = parse_function(arg) {
103 let tree = BinaryAlgebraicExpressionTree {
104 name: name.to_string(),
105 root_node: parse_expression(expr),
106 };
107 trees.push(tree);
108 } else {
109 println!("Invalid function definition: {arg}");
110 return;
111 }
112 }
113 if let Some((func_name, input_val)) = parse_function_call(input.last().unwrap()) {
114 if let Some(tree) = trees.iter().find(|t| t.name == func_name) {
115 let x: Dec = input_val.parse().unwrap_or_else(|_| {
116 println!("Invalid input value: {input_val}");
117 std::process::exit(1);
118 });
119 let result = apply_algebra_to_tree_node(&tree.root_node, &x, &trees, use_math_tricks);
120 println!("{}", trim2(result));
121 } else {
122 println!("Function {func_name} not defined");
123 }
124 } else {
125 println!("Invalid function call: {}", input.last().unwrap());
126 }
127}
128
129pub fn apply_algebra_to_tree_node(
131 node: &TreeNode,
132 x: &Dec,
133 tablets: &Vec<BinaryAlgebraicExpressionTree>,
134 use_math_tricks: bool,
135) -> Dec {
136 match node {
137 TreeNode::Num(n) => Dec::from(*n),
138 TreeNode::Var(s) => {
139 if s == "x" {
140 *x
141 } else {
142 s.parse::<Dec>()
143 .unwrap_or_else(|_| panic!("Unexpected variable: {s}"))
144 }
145 }
146 TreeNode::Fun(name, arg) => {
147 let arg_value = apply_algebra_to_tree_node(arg, x, tablets, use_math_tricks);
148 if name.as_str() == "ABS" && use_math_tricks {
149 math_trick::abs(arg_value).parse().unwrap()
150 } else if name.as_str() == "GE0" && use_math_tricks {
151 math_trick::ge0(arg_value).parse().unwrap()
152 } else if name.as_str() == "IS0" && use_math_tricks {
153 math_trick::is0(arg_value).parse().unwrap()
154 } else if name.as_str() == "FLOOR1" && use_math_tricks {
155 math_trick::floor1(arg_value).parse().unwrap()
156 } else if name.as_str() == "LEFT" && use_math_tricks {
157 math_trick::left(arg_value.to_standard_notation_string())
158 .parse()
159 .unwrap()
160 } else {
161 let tablet = tablets
162 .iter()
163 .find(|tablet| name == &tablet.name)
164 .unwrap_or_else(|| panic!("There is no tree called {name}"));
165 apply_algebra_to_tree_node(&tablet.root_node, &arg_value, tablets, use_math_tricks)
166 }
167 }
168 TreeNode::Op(op, left, right) => {
169 let mut left_val = apply_algebra_to_tree_node(left, x, tablets, use_math_tricks);
170 let right_val = apply_algebra_to_tree_node(right, x, tablets, use_math_tricks);
171 match op {
172 '+' => left_val + right_val,
173 '-' => left_val - right_val,
174 '*' => left_val * right_val,
175 '/' => left_val / right_val,
176 '^' => {
177 let mut ctx = dec::Context::<Dec>::default();
178 ctx.set_min_exponent(-1000).unwrap();
179 ctx.set_max_exponent(1000).unwrap();
180 ctx.pow(&mut left_val, &right_val);
181 left_val
182 }
183 _ => panic!("Unknown operator: {op}"),
184 }
185 }
186 TreeNode::Paren(expr) => apply_algebra_to_tree_node(expr, x, tablets, use_math_tricks),
187 TreeNode::Empty => Dec::zero(),
188 }
189}
190
191pub fn parse_expression(s: &str) -> TreeNode {
193 let tokens: Vec<char> = s.chars().filter(|c| !c.is_whitespace()).collect();
194 let mut index = 0;
195 parse_additive(&tokens, &mut index)
196}
197
198pub fn create_expression(node: TreeNode) -> String {
200 fn build_expr(node: TreeNode, parent_prec: u8, is_root: bool) -> String {
201 match node {
202 TreeNode::Op(op, left, right) => {
203 let (prec, is_left_assoc) = match op {
204 '^' => (4, false),
205 '*' | '/' => (3, true),
206 '+' | '-' => (2, true),
207 _ => (0, true),
208 };
209 let left_str = build_expr(*left, prec, false);
210 let right_str = build_expr(*right, prec + !is_left_assoc as u8, false);
211 let expr = format!("{left_str}{op}{right_str}");
212 if prec < parent_prec && !is_root {
213 format!("({expr})")
214 } else {
215 expr
216 }
217 }
218 TreeNode::Num(n) => n.to_string(),
219 TreeNode::Var(v) => v,
220 TreeNode::Fun(name, arg) => format!("{}({})", name, build_expr(*arg, 0, false)),
221 TreeNode::Paren(expr) => {
222 let inner = build_expr(*expr, 0, true);
223 if parent_prec > 0 {
224 format!("({inner})")
225 } else {
226 inner
227 }
228 }
229 TreeNode::Empty => String::new(),
230 }
231 }
232 build_expr(node, 0, true)
233}
234
235pub fn level_order_to_array(root: TreeNode) -> [String; 15] {
236 let mut result = std::array::from_fn(|_| String::new());
237 let mut queue = std::collections::VecDeque::with_capacity(15);
238 queue.push_back((0, root));
239 while let Some((i, node)) = queue.pop_front() {
240 if i >= 15 {
241 continue;
242 }
243 match node {
244 TreeNode::Op(op, left, right) => {
245 result[i] = op.to_string();
246 queue.push_back((2 * i + 1, *left));
247 queue.push_back((2 * i + 2, *right));
248 }
249 TreeNode::Num(n) => result[i] = n.to_string(),
250 TreeNode::Var(v) => result[i] = v,
251 TreeNode::Fun(name, arg) => {
252 result[i] = name;
253 queue.push_back((2 * i + 2, *arg));
254 }
255 TreeNode::Paren(expr) => {
256 result[i] = "()".to_string();
257 queue.push_back((2 * i + 1, *expr));
258 }
259 TreeNode::Empty => {}
260 }
261 }
262 result
263}
264
265fn trim2(mut dec: Dec) -> String {
266 dec.trim();
267 let result = dec.to_standard_notation_string();
268 if result == "-0" {
269 "0".to_string()
270 } else {
271 result
272 }
273}
274
275fn parse_function(s: &str) -> Option<(&str, &str)> {
276 let s = s.trim();
277 if let Some((func_part, expr)) = s.split_once('=') {
278 let func_part = func_part.trim();
279 if let Some((name, _)) = func_part.split_once('(') {
280 return Some((name, expr.trim()));
281 }
282 }
283 None
284}
285
286fn parse_function_call(s: &str) -> Option<(&str, &str)> {
287 if !s.ends_with(')') || !s.contains('(') {
288 return None;
289 }
290 let open_paren = s.find('(')?;
291 let name = &s[..open_paren];
292 let input = &s[open_paren + 1..s.len() - 1];
293 Some((name, input))
294}
295
296fn trim_zeros(s: &str) -> String {
297 if s.contains('.') {
298 let trimmed = s.trim_end_matches('0');
299 trimmed.trim_end_matches('.').to_string()
300 } else {
301 s.to_string()
302 }
303}
304
305fn parse_additive(tokens: &[char], index: &mut usize) -> TreeNode {
306 let mut left = parse_multiplicative(tokens, index);
307 while *index < tokens.len() {
308 match tokens[*index] {
309 '+' | '-' => {
310 let op = tokens[*index];
311 *index += 1;
312 let right = parse_multiplicative(tokens, index);
313 left = TreeNode::Op(op, Box::new(left), Box::new(right));
314 }
315 _ => break,
316 }
317 }
318 left
319}
320
321fn parse_multiplicative(tokens: &[char], index: &mut usize) -> TreeNode {
322 let mut left = parse_power(tokens, index);
323 while *index < tokens.len() {
324 match tokens[*index] {
325 '*' | '/' => {
326 let op = tokens[*index];
327 *index += 1;
328 let right = parse_power(tokens, index);
329 left = TreeNode::Op(op, Box::new(left), Box::new(right));
330 }
331 _ => break,
332 }
333 }
334 left
335}
336
337fn parse_power(tokens: &[char], index: &mut usize) -> TreeNode {
338 let mut left = parse_atomic(tokens, index);
339 while *index < tokens.len() && tokens[*index] == '^' {
340 let op = tokens[*index];
341 *index += 1;
342 let right = parse_atomic(tokens, index);
343 left = TreeNode::Op(op, Box::new(left), Box::new(right));
344 }
345 left
346}
347
348fn parse_atomic(tokens: &[char], index: &mut usize) -> TreeNode {
349 if *index >= tokens.len() {
350 return TreeNode::Empty;
351 }
352 let c = tokens[*index];
353 match c {
354 '(' => {
355 *index += 1;
356 let node = parse_additive(tokens, index);
357 if *index < tokens.len() && tokens[*index] == ')' {
358 *index += 1;
359 }
360 TreeNode::Paren(Box::new(node))
361 }
362 '0'..='9' => {
363 let mut num = 0;
364 while *index < tokens.len() && tokens[*index].is_ascii_digit() {
365 num = num * 10 + tokens[*index].to_digit(10).unwrap() as i32;
366 *index += 1;
367 }
368 TreeNode::Num(num)
369 }
370 'x' => {
371 *index += 1;
372 TreeNode::Var("x".to_string())
373 }
374 'A'..='Z' => {
375 let mut name = String::new();
376 while *index < tokens.len()
377 && (tokens[*index].is_alphanumeric() || tokens[*index] == '_')
378 {
379 name.push(tokens[*index]);
380 *index += 1;
381 }
382 if *index < tokens.len() && tokens[*index] == '(' {
383 *index += 1;
384 let arg = parse_additive(tokens, index);
385 if *index < tokens.len() && tokens[*index] == ')' {
386 *index += 1;
387 }
388 TreeNode::Fun(name, Box::new(arg))
389 } else {
390 TreeNode::Var(name)
391 }
392 }
393 _ => TreeNode::Empty,
394 }
395}
396
397pub mod math_trick {
398 use super::*;
399
400 pub fn abs(mut x: Dec) -> String {
401 let mut ctx = dec::Context::<Dec>::default();
402 ctx.set_min_exponent(-1000).unwrap();
403 ctx.set_max_exponent(1000).unwrap();
404 ctx.abs(&mut x);
405 x.to_string()
406 }
407
408 pub fn ge0(x: Dec) -> String {
409 let nan: Dec = get_nan().parse().unwrap();
410 match x {
411 _ if x > nan => "1".to_string(),
412 _ if x < nan => "0".to_string(),
413 _ => "NaN".to_string(),
414 }
415 }
416
417 pub fn is0(x: Dec) -> String {
418 let nan: Dec = get_nan().parse().unwrap();
419 match x {
420 _ if x < nan => "0".to_string(),
421 _ if x > nan && x < "1".parse::<Dec>().unwrap() + nan => "1".to_string(),
422 _ if x > "1".parse::<Dec>().unwrap() + nan => "0".to_string(),
423 _ => "NaN".to_string(),
424 }
425 }
426
427 pub fn floor1(x: Dec) -> String {
428 let nan: Dec = get_nan().parse().unwrap();
429 match x {
430 _ if x < nan => "0".to_string(),
431 _ if x > nan && x < "1".parse::<Dec>().unwrap() + nan => "0".to_string(),
432 _ if x > "1".parse::<Dec>().unwrap() + nan && x < "2".parse::<Dec>().unwrap() + nan => {
433 "1".to_string()
434 }
435 _ if x > "2".parse::<Dec>().unwrap() + nan && x < "3".parse::<Dec>().unwrap() + nan => {
436 "2".to_string()
437 }
438 _ if x > "3".parse::<Dec>().unwrap() + nan && x < "4".parse::<Dec>().unwrap() + nan => {
439 "3".to_string()
440 }
441 _ if x > "4".parse::<Dec>().unwrap() + nan && x < "5".parse::<Dec>().unwrap() + nan => {
442 "4".to_string()
443 }
444 _ if x > "5".parse::<Dec>().unwrap() + nan && x < "6".parse::<Dec>().unwrap() + nan => {
445 "5".to_string()
446 }
447 _ if x > "6".parse::<Dec>().unwrap() + nan && x < "7".parse::<Dec>().unwrap() + nan => {
448 "6".to_string()
449 }
450 _ if x > "7".parse::<Dec>().unwrap() + nan && x < "8".parse::<Dec>().unwrap() + nan => {
451 "7".to_string()
452 }
453 _ if x > "8".parse::<Dec>().unwrap() + nan && x < "9".parse::<Dec>().unwrap() + nan => {
454 "8".to_string()
455 }
456 _ if x > "9".parse::<Dec>().unwrap() + nan
457 && x < "10".parse::<Dec>().unwrap() + nan =>
458 {
459 "9".to_string()
460 }
461 _ if x > "10".parse::<Dec>().unwrap() + nan => "0".to_string(),
462 _ => "NaN".to_string(),
463 }
464 }
465
466 pub fn left(mut num: String) -> String {
468 if floor1(num.parse::<Dec>().unwrap() * "10".parse::<Dec>().unwrap()) == "NaN" {
470 return "NaN".to_string();
471 }
472 if !num.contains('.') {
473 num += ".0";
474 }
475 if num.ends_with('0') {
476 num = num.trim_end_matches('0').to_string()
477 }
478 if num.ends_with('.') {
479 num += "0";
480 }
481 let decimal_pos = num.find('.').unwrap();
482 let (integer_part, fractional_part) = num.split_at(decimal_pos + 1);
483 let mut chars: Vec<_> = fractional_part.chars().collect();
484 let len = get_decimal_places() - chars.len();
485 if len > 0 {
486 chars.extend(vec!['0'; len]);
487 }
488 chars.rotate_right(1);
489 let rotated_fractional_part: String = chars.into_iter().collect();
490 let result = format!("{integer_part}{rotated_fractional_part}");
491 trim_zeros(&result)
492 }
493}
494
495#[cfg(test)]
496mod tests {
497 use super::*;
498
499 fn get_test_cases() -> &'static Vec<TestCase> {
500 static INSTANCE: std::sync::OnceLock<Vec<TestCase>> = std::sync::OnceLock::new();
501 INSTANCE.get_or_init(|| {
502 vec![
503 TestCase {
504 description: None,
505 examples: vec![
506 ["2".to_string(), get_decimal_places().to_string()],
507 ["-0.2424".to_string(), get_decimal_places().to_string()],
508 ["100".to_string(), get_decimal_places().to_string()],
509 ],
510 solution: vec![BinaryAlgebraicExpressionTree {
511 name: "DECIMAL_PLACES".to_string(),
512 root_node: parse_expression(&get_decimal_places().to_string())
513 }],
514 },
515 TestCase {
516 description: None,
517 examples: vec![
518 ["-1".to_string(), "1".to_string()],
519 ["0".to_string(), "0".to_string()],
521 ["1".to_string(), "1".to_string()],
523 ],
524 solution: vec![BinaryAlgebraicExpressionTree {
525 name: "ABS".to_string(),
526 root_node: parse_expression("(x^2)^(1/2)")
527 }],
528 },
529 TestCase {
530 description: None,
531 examples: vec![
532 ["0".to_string(), "NaN".to_string()],
533 ["0.3".to_string(), "1".to_string()],
534 ["-0.3".to_string(), "0".to_string()],
535 ["1.0".to_string(), "1".to_string()],
536 ["400.0".to_string(), "1".to_string()],
537 ],
538 solution: vec![BinaryAlgebraicExpressionTree {
539 name: "H".to_string(),
540 root_node: parse_expression("(x+ABS(x))/(2*x)")
541 }],
542 },
543 TestCase {
544 description: None,
545 examples: vec![
546 [
547 "55".to_string(),
548 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
549 ],
550 [
551 "-11.9".to_string(),
552 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
553 ],
554 [
555 "0.0".to_string(),
556 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
557 ],
558 [
559 "-0.95".to_string(),
560 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "1",
561 ],
562 ],
563 solution: vec![BinaryAlgebraicExpressionTree {
564 name: "TINY".to_string(),
565 root_node: parse_expression("10^(-DECIMAL_PLACES(x)))")
566 }],
567 },
568 TestCase {
569 description: None,
570 examples: vec![
571 [
572 "0.".to_string() + &"9".repeat(get_decimal_places()),
573 "1".to_string(),
574 ],
575 [
576 "-0.".to_string() + &"0".repeat(get_decimal_places()) + "1",
577 "NaN".to_string(),
578 ],
579 ["0.3".to_string(), "1".to_string()],
580 ["-0.3".to_string(), "0".to_string()],
581 ["1.0".to_string(), "1".to_string()],
582 ["400.0".to_string(), "1".to_string()],
583 ],
584 solution: vec![BinaryAlgebraicExpressionTree {
585 name: "GE0".to_string(),
586 root_node: parse_expression("H(x+TINY(x)/10)")
587 }],
588 },
589 TestCase {
590 description: None,
591 examples: vec![
592 ["0".to_string(), "1".to_string()],
593 ["-6.4".to_string(), "1".to_string()],
594 ["1.0".to_string(), "0".to_string()],
595 ["0.999".to_string(), "1".to_string()],
596 ["50".to_string(), "0".to_string()],
597 ],
598 solution: vec![BinaryAlgebraicExpressionTree {
599 name: "LT1".to_string(),
600 root_node: parse_expression("1-GE0(x-1)")
601 }],
602 },
603 TestCase {
604 description: None,
605 examples: vec![
606 ["0".to_string(), "1".to_string()],
607 ["0.5".to_string(), "1".to_string()],
608 ["1".to_string(), "0".to_string()],
609 ],
610 solution: vec![BinaryAlgebraicExpressionTree {
611 name: "IS0".to_string(),
612 root_node: parse_expression("GE0(x)*LT1(x)")
613 }],
614 },
615 TestCase {
616 description: None,
617 examples: vec![
618 ["1".to_string(), "1".to_string()],
619 ["1.5".to_string(), "1".to_string()],
620 ["2".to_string(), "0".to_string()],
621 ],
622 solution: vec![BinaryAlgebraicExpressionTree {
623 name: "IS1".to_string(),
624 root_node: parse_expression("IS0(x-1)")
625 }],
626 },
627 TestCase {
628 description: None,
629 examples: vec![
630 ["2".to_string(), "1".to_string()],
631 ["2.5".to_string(), "1".to_string()],
632 ["3".to_string(), "0".to_string()],
633 ],
634 solution: vec![BinaryAlgebraicExpressionTree {
635 name: "IS2".to_string(),
636 root_node: parse_expression("IS0(x-2)")
637 }],
638 },
639 TestCase {
640 description: None,
641 examples: vec![
642 ["3".to_string(), "1".to_string()],
643 ["3.5".to_string(), "1".to_string()],
644 ["4".to_string(), "0".to_string()],
645 ],
646 solution: vec![BinaryAlgebraicExpressionTree {
647 name: "IS3".to_string(),
648 root_node: parse_expression("IS0(x-3)")
649 }],
650 },
651 TestCase {
652 description: None,
653 examples: vec![
654 ["4".to_string(), "1".to_string()],
655 ["4.5".to_string(), "1".to_string()],
656 ["5".to_string(), "0".to_string()],
657 ],
658 solution: vec![BinaryAlgebraicExpressionTree {
659 name: "IS4".to_string(),
660 root_node: parse_expression("IS0(x-4)")
661 }],
662 },
663 TestCase {
664 description: None,
665 examples: vec![
666 ["5".to_string(), "1".to_string()],
667 ["5.5".to_string(), "1".to_string()],
668 ["6".to_string(), "0".to_string()],
669 ],
670 solution: vec![BinaryAlgebraicExpressionTree {
671 name: "IS5".to_string(),
672 root_node: parse_expression("IS0(x-5)")
673 }],
674 },
675 TestCase {
676 description: None,
677 examples: vec![
678 ["6".to_string(), "1".to_string()],
679 ["6.5".to_string(), "1".to_string()],
680 ["7".to_string(), "0".to_string()],
681 ],
682 solution: vec![BinaryAlgebraicExpressionTree {
683 name: "IS6".to_string(),
684 root_node: parse_expression("IS0(x-6)"),
685 }],
686 },
687 TestCase {
688 description: None,
689 examples: vec![
690 ["7".to_string(), "1".to_string()],
691 ["7.5".to_string(), "1".to_string()],
692 ["8".to_string(), "0".to_string()],
693 ],
694 solution: vec![BinaryAlgebraicExpressionTree {
695 name: "IS7".to_string(),
696 root_node: parse_expression("IS0(x-7)"),
697 }],
698 },
699 TestCase {
700 description: None,
701 examples: vec![
702 ["8".to_string(), "1".to_string()],
703 ["8.5".to_string(), "1".to_string()],
704 ["9".to_string(), "0".to_string()],
705 ],
706 solution: vec![BinaryAlgebraicExpressionTree {
707 name: "IS8".to_string(),
708 root_node: parse_expression("IS0(x-8)"),
709 }],
710 },
711 TestCase {
712 description: None,
713 examples: vec![
714 ["9".to_string(), "1".to_string()],
715 ["9.5".to_string(), "1".to_string()],
716 ["10".to_string(), "0".to_string()],
717 ],
718 solution: vec![BinaryAlgebraicExpressionTree {
719 name: "IS9".to_string(),
720 root_node: parse_expression("IS0(x-9)"),
721 }],
722 },
723 TestCase {
724 description: None,
725 examples: vec![
726 ["0".to_string(), "0".to_string()],
727 ["0.2".to_string(), "0".to_string()],
728 ["1".to_string(), "1".to_string()],
729 ["1.2".to_string(), "1".to_string()],
730 ["2".to_string(), "2".to_string()],
731 ["2.2".to_string(), "2".to_string()],
732 ["3".to_string(), "3".to_string()],
733 ["3.2".to_string(), "3".to_string()],
734 ["4".to_string(), "4".to_string()],
735 ["4.2".to_string(), "4".to_string()],
736 ["5".to_string(), "5".to_string()],
737 ["5.2".to_string(), "5".to_string()],
738 ["6".to_string(), "6".to_string()],
739 ["6.2".to_string(), "6".to_string()],
740 ["7".to_string(), "7".to_string()],
741 ["7.2".to_string(), "7".to_string()],
742 ["8".to_string(), "8".to_string()],
743 ["8.2".to_string(), "8".to_string()],
744 ["9".to_string(), "9".to_string()],
745 ["9.2".to_string(), "9".to_string()],
746 ],
747 solution: vec![BinaryAlgebraicExpressionTree {
748 name: "FLOOR1".to_string(),
749 root_node: parse_expression(
750 "IS1(x)+2*IS2(x)+3*IS3(x)+4*IS4(x)+5*IS5(x)+6*IS6(x)+7*IS7(x)+8*IS8(x)+9*IS9(x)",
751 ),
752 }],
753 },
754 TestCase {
755 description: None,
756 examples: vec![
757 ["0.06".to_string(), "0.6".to_string()],
758 [
759 "0.12345678".to_string(),
760 "0.2345678".to_string() + &"0".repeat(get_decimal_places() - 8) + "1",
761 ],
762 [
763 "0.7".to_string(),
764 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "7",
765 ],
766 ],
767 solution: vec![
768 BinaryAlgebraicExpressionTree {
769 name: "RIGHT".to_string(),
770 root_node: parse_expression("x*10-FLOOR1(x*10)+FLOOR1(x*10)*TINY(x)")
771 },
772 ],
773 },
774 TestCase {
775 description: None,
776 examples: vec![
777 [
778 "0.2345678".to_string() + &"0".repeat(get_decimal_places() - 8) + "1",
779 "0.12345678".to_string(),
780 ],
781 [
782 "0.".to_string() + &"0".repeat(get_decimal_places() - 1) + "7",
783 "0.7".to_string(),
784 ],
785 ],
786 solution: vec![
787 BinaryAlgebraicExpressionTree {
788 name: "LEFT".to_string(),
789 root_node: parse_expression(
790 &("RIGHT(".repeat(get_decimal_places() - 1) + "(x)" + &")".repeat(get_decimal_places() - 1))
791 )
792 },
793 ],
794 },
795 ]
796 })
797 }
798
799 #[test]
800 fn test_solutions() {
801 let tasks = get_test_cases();
802 let mut trees: Vec<BinaryAlgebraicExpressionTree> = vec![];
803 for task in tasks {
804 for tree in &task.solution {
805 trees.push(tree.clone());
806 }
807 }
808 for i in 0..tasks.len() {
809 for [input, output] in &tasks[i].examples {
810 let name_function = &tasks[i].solution.last().unwrap().name;
811 let name = format!("{}({}) = ", name_function, input);
812 let result = trim2(apply_algebra_to_tree_node(
813 &tasks[i].solution.last().unwrap().root_node,
814 &input.parse::<Dec>().unwrap(),
815 &trees,
816 true,
817 ));
818 assert_eq!(name.clone() + output.as_str(), name + &result);
819 }
820 }
821 }
822
823 #[test]
824 fn test_math_tricks() {
825 let tasks = get_test_cases();
826 let mut trees: Vec<BinaryAlgebraicExpressionTree> = vec![];
827 for task in tasks {
828 for tree in &task.solution {
829 trees.push(tree.clone());
830 }
831 }
832 for i in 0..tasks.len() {
833 for [input, output] in &tasks[i].examples {
834 let name_function = &tasks[i].solution.last().unwrap().name;
835 let name = format!("{}({}) = ", name_function, input);
836 let input_dec = input.parse().unwrap();
837 if name_function == "ABS" {
838 assert_eq!(
839 name.clone() + output.as_str(),
840 name + &math_trick::abs(input_dec)
841 );
842 } else if name_function == "GE0" {
843 assert_eq!(
844 name.clone() + output.as_str(),
845 name + &math_trick::ge0(input_dec)
846 );
847 } else if name_function == "IS0" {
848 assert_eq!(
849 name.clone() + output.as_str(),
850 name + &math_trick::is0(input_dec)
851 );
852 } else if name_function == "FLOOR1" {
853 assert_eq!(
854 name.clone() + output.as_str(),
855 name + &math_trick::floor1(input_dec)
856 );
857 } else if name_function == "LEFT" {
858 assert_eq!(
859 name.clone() + output.as_str(),
860 name + &math_trick::left(input_dec.to_standard_notation_string())
861 );
862 }
863 }
864 }
865 }
866}