Skip to content

Commit

Permalink
refactor: rewrite logic with Binary Tree
Browse files Browse the repository at this point in the history
  • Loading branch information
leogaudin committed Aug 28, 2024
1 parent deb649f commit b5bb47a
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 40 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -585,3 +585,5 @@ fn generate_sets(variables: Vec<char>, set: Vec<bool>, index: usize) {
- [💬 Grade School Multiplication Algorithm for Binary Numbers explanation](https://math.stackexchange.com/a/1118159)

- [📺 How To Convert Gray Code to Binary and Binary to Gray Code](https://www.youtube.com/watch?v=cbmh1DPPQyI)

- [📖 Implementing a Binary Tree in Rust for fun](https://rusty-ferris.pages.dev/blog/binary-tree-sum-of-values/)
41 changes: 4 additions & 37 deletions src/ex03.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,6 @@
pub fn eval_formula(formula: &str) -> bool {
let chars: Vec<char> = formula.chars().collect();
let mut stack: Vec<bool> = Vec::new();

for c in chars {
if c == '0' || c == '1' {
stack.push(c != '0');
}
else {
if c == '!' {
let last: bool = stack.pop().unwrap();
stack.push(!last);
continue;
}

if stack.len() < 2 {
println!("Invalid expression: not enough operands");
return false;
}
use crate::tree::{create_tree, eval_tree, TreeNodeRef};

let b: bool = stack.pop().unwrap();
let a: bool = stack.pop().unwrap();

match c {
'&' => stack.push(a && b),
'|' => stack.push(a || b),
'^' => stack.push(a ^ b),
'>' => stack.push(!a || b),
'=' => stack.push(a == b),
_ => {
println!("Invalid operator");
return false;
}
}
}
}

return stack.pop().unwrap();
pub fn eval_formula(formula: &str) -> bool {
let tree: TreeNodeRef = create_tree(formula);
return eval_tree(tree);
}
7 changes: 4 additions & 3 deletions src/ex04.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ex03::eval_formula;
use crate::tree::{create_tree, eval_tree, replace_variables, TreeNodeRef};

fn is_valid_formula(formula: &str) -> bool {
let valids: &str = "01!&|^>=";
Expand Down Expand Up @@ -41,8 +41,9 @@ fn print_sets(variables: Vec<char>, set: &mut Vec<bool>, index: usize, formula:
for value in set.iter() {
print!("{}\t", *value as u8);
}
let replaced: String = replace_values(formula, set, &variables);
println!("{}", eval_formula(replaced.as_str()));
let tree: TreeNodeRef = replace_variables(create_tree(formula), set, &variables);
let eval: bool = eval_tree(tree.clone());
println!("{}", eval.to_string().as_str());
return;
}

Expand Down
20 changes: 20 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ use ex03::eval_formula;
mod ex04;
use ex04::print_truth_table;

mod tree;
use tree::{create_tree, print_tree, TreeNodeRef};

fn main() {
println!("\n{}", "EX00 - ADDER".normal().bold());
for _ in 0..42 {
Expand Down Expand Up @@ -103,4 +106,21 @@ fn main() {
for formula in formulas {
print_truth_table(formula);
}

println!("\n{}", "EX05 - NEGATION NORMAL FORM".normal().bold());
let formulas = [
"AB01&|",
"AB&C|",
"ABZK||=",
"1WAH1|&",
// "ABCDEFGHIJKLMNOPQRSTUVWXYZ&|&|&|&|&|&",
];

for formula in formulas {
// print_truth_table(formula);
let tree: TreeNodeRef = create_tree(formula);
print_tree(tree);
println!();
println!();
}
}
153 changes: 153 additions & 0 deletions src/tree.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
use std::{cell::RefCell, rc::Rc};

#[derive(Debug, Clone)]
pub enum NodeValue {
Value(bool),
Variable(char),
Operator(char),
}

pub struct TreeNode {
value: Option<NodeValue>,
left: Option<TreeNodeRef>,
right: Option<TreeNodeRef>,
}

pub type TreeNodeRef = Rc<RefCell<TreeNode>>;

impl TreeNode {
pub fn new() -> TreeNodeRef {
Rc::new(RefCell::new(TreeNode {
value: None,
left: None,
right: None,
}))
}

pub fn set_val(&mut self, value: NodeValue) {
self.value = Some(value);
}

pub fn set_left(&mut self, left: TreeNodeRef) {
self.left = Some(left);
}

pub fn set_right(&mut self, right: TreeNodeRef) {
self.right = Some(right);
}

pub fn get_val(&self) -> Option<NodeValue> {
self.value.clone()
}

pub fn get_left(&self) -> Option<TreeNodeRef> {
self.left.clone()
}

pub fn get_right(&self) -> Option<TreeNodeRef> {
self.right.clone()
}

pub fn clone(&self) -> TreeNodeRef {
Rc::new(RefCell::new(TreeNode {
value: self.value.clone(),
left: self.left.clone(),
right: self.right.clone(),
}))
}
}

pub fn print_tree(node: TreeNodeRef) {
let node = node.borrow();
match node.get_val() {
Some(NodeValue::Value(value)) => print!("{}", value),
Some(NodeValue::Variable(variable)) => print!("{}", variable),
Some(NodeValue::Operator(operator)) => {
print!("(");
print_tree(node.get_left().unwrap());
print!("{}", operator);
print_tree(node.get_right().unwrap());
print!(")");
}
None => panic!("Node has no value"),
}
}

pub fn create_tree(expression: &str) -> TreeNodeRef {
let mut stack: Vec<TreeNodeRef> = Vec::new();
for c in expression.chars() {
if c == ' ' {
continue;
}
let node: TreeNodeRef = TreeNode::new();
match c {
'0' | '1' => {
node.borrow_mut().set_val(NodeValue::Value(c == '1'));
},
'A'..='Z' => {
node.borrow_mut().set_val(NodeValue::Variable(c));
},
'!' => {
let left: TreeNodeRef = stack.pop().unwrap();
node.borrow_mut().set_val(NodeValue::Operator(c));
node.borrow_mut().set_left(left);
}
'&' | '|' | '^' | '>' | '=' => {
let right: TreeNodeRef = stack.pop().unwrap();
let left: TreeNodeRef = stack.pop().unwrap();
node.borrow_mut().set_val(NodeValue::Operator(c));
node.borrow_mut().set_left(left);
node.borrow_mut().set_right(right);
}
_ => panic!("Invalid character in expression"),
}
stack.push(node);
}
stack.pop().unwrap()
}

pub fn eval_tree(node: TreeNodeRef) -> bool {
let node = node.borrow();
match node.get_val() {
Some(NodeValue::Value(value)) => value,
Some(NodeValue::Operator(operator)) => {
if operator == '!' {
return !eval_tree(node.get_left().unwrap());
}
let left: bool = eval_tree(node.get_left().unwrap());
let right: bool = eval_tree(node.get_right().unwrap());
match operator {
'&' => return left && right,
'|' => return left || right,
'^' => return left ^ right,
'>' => return !left || right,
'=' => return left == right,
_ => panic!("Invalid operator"),
}
}
Some(NodeValue::Variable(_)) => panic!("Variable in expression"),
None => panic!("Node has no value"),
}
}

pub fn replace_variables(node: TreeNodeRef, values: &Vec<bool>, variables: &Vec<char>) -> TreeNodeRef {
let mut node = node.borrow_mut();
match node.get_val() {
Some(NodeValue::Value(_)) => node.clone(),
Some(NodeValue::Operator(_)) => {
let left: TreeNodeRef = replace_variables(node.get_left().unwrap(), values, variables);
let right: TreeNodeRef = replace_variables(node.get_right().unwrap(), values, variables);
node.set_left(left);
node.set_right(right);
return node.clone();
}
Some(NodeValue::Variable(variable)) => {
let index: usize = variables.iter().position(|&v| v == variable).unwrap();
let value: bool = values[index];
let new_node: TreeNodeRef = TreeNode::new();
new_node.borrow_mut().set_val(NodeValue::Value(value));
return new_node;
}
None => panic!("Node has no value"),
}
}

0 comments on commit b5bb47a

Please sign in to comment.