Reworked parsing

master
Mark 2024-03-04 15:49:24 -08:00
parent a0ffc73333
commit a2a264163a
Signed by: Mark
GPG Key ID: C6D63995FE72FD80
1 changed files with 275 additions and 54 deletions

View File

@ -1,26 +1,167 @@
use std::fmt::Display;
use std::fmt::{Debug, Display};
use termion::color;
use crate::{Player, Symb};
#[derive(Debug, PartialEq)]
enum Token {
Number(f32),
#[derive(Debug, PartialEq, Clone)]
pub enum Token {
Value(String),
OpAdd,
OpSub,
OpMult,
OpDiv,
}
impl Token {
fn val(&self) -> f32 {
#[derive(PartialEq, Clone)]
pub enum TreeElement {
Partial(String),
Number(f32),
Add {
l: Box<TreeElement>,
r: Box<TreeElement>,
},
Sub {
l: Box<TreeElement>,
r: Box<TreeElement>,
},
Mul {
l: Box<TreeElement>,
r: Box<TreeElement>,
},
Div {
l: Box<TreeElement>,
r: Box<TreeElement>,
},
Neg {
r: Box<TreeElement>,
},
}
impl Display for TreeElement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Number(x) => *x,
_ => unreachable!(),
Self::Partial(s) => write!(f, "{s}")?,
Self::Number(n) => write!(f, "{n}")?,
Self::Add { l, r } => write!(f, "({l}+{r})")?,
Self::Div { l, r } => write!(f, "({l}÷{r})")?,
Self::Mul { l, r } => write!(f, "({l}×{r})")?,
Self::Sub { l, r } => write!(f, "({l}-{r})")?,
Self::Neg { r } => write!(f, "(-{r})")?,
}
Ok(())
}
}
impl Debug for TreeElement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self, f)
}
}
enum InterTreeElement {
Unprocessed(Token),
Processed(TreeElement),
}
#[allow(dead_code)]
impl TreeElement {
pub fn left(&self) -> Option<&TreeElement> {
match self {
Self::Add { l, .. }
| Self::Sub { l, .. }
| Self::Mul { l, .. }
| Self::Div { l, .. } => Some(&**l),
_ => None,
}
}
pub fn right(&self) -> Option<&TreeElement> {
match self {
Self::Add { r, .. }
| Self::Neg { r, .. }
| Self::Sub { r, .. }
| Self::Mul { r, .. }
| Self::Div { r, .. } => Some(&**r),
_ => None,
}
}
pub fn left_mut(&mut self) -> Option<&mut TreeElement> {
match self {
Self::Add { l, .. }
| Self::Sub { l, .. }
| Self::Mul { l, .. }
| Self::Div { l, .. } => Some(&mut **l),
_ => None,
}
}
pub fn right_mut(&mut self) -> Option<&mut TreeElement> {
match self {
Self::Add { r, .. }
| Self::Neg { r, .. }
| Self::Sub { r, .. }
| Self::Mul { r, .. }
| Self::Div { r, .. } => Some(&mut **r),
_ => None,
}
}
}
impl TreeElement {
pub fn evaluate(&self) -> Option<f32> {
match self {
Self::Number(x) => Some(*x),
Self::Partial(_) => None,
Self::Add { l, r } => {
let l = l.evaluate();
let r = r.evaluate();
if let (Some(l), Some(r)) = (l, r) {
Some(l + r)
} else {
None
}
}
Self::Mul { l, r } => {
let l = l.evaluate();
let r = r.evaluate();
if let (Some(l), Some(r)) = (l, r) {
Some(l * r)
} else {
None
}
}
Self::Div { l, r } => {
let l = l.evaluate();
let r = r.evaluate();
if let (Some(l), Some(r)) = (l, r) {
Some(l / r)
} else {
None
}
}
Self::Sub { l, r } => {
let l = l.evaluate();
let r = r.evaluate();
if let (Some(l), Some(r)) = (l, r) {
Some(l - r)
} else {
None
}
}
Self::Neg { r } => {
let r = r.evaluate();
if let Some(r) = r {
Some(-r)
} else {
None
}
}
}
}
}
#[derive(Clone)]
pub struct Board {
board: [Option<(Symb, Player)>; 11],
free_spots: usize,
@ -152,88 +293,159 @@ impl Board {
true
}
pub fn evaluate(&self) -> Option<f32> {
if !self.is_done() {
return None;
}
pub fn tokenize(&self) -> Vec<Token> {
let mut tokens = Vec::new();
let mut is_neg = true; // if true, - is negative. if false, subtract.
let mut current_num = 0f32;
let mut current_sgn = 1f32;
let mut current_num = String::new();
for (s, _) in self.board.iter().map(|x| x.unwrap()) {
for s in self.board.iter().map(|x| x.map(|(s, _)| s)) {
match s {
Symb::Div => {
tokens.push(Token::Number(current_num * current_sgn));
current_num = 0.0;
current_sgn = 1.0;
Some(Symb::Div) => {
tokens.push(Token::Value(current_num.clone()));
current_num.clear();
tokens.push(Token::OpDiv);
is_neg = true;
}
Symb::Minus => {
Some(Symb::Minus) => {
if is_neg {
current_sgn = -1.0;
current_num = format!("-{}", current_num);
} else {
tokens.push(Token::Number(current_num * current_sgn));
current_num = 0.0;
current_sgn = 1.0;
tokens.push(Token::Value(current_num.clone()));
current_num.clear();
tokens.push(Token::OpSub);
is_neg = true;
}
}
Symb::Plus => {
tokens.push(Token::Number(current_num * current_sgn));
current_num = 0.0;
current_sgn = 1.0;
Some(Symb::Plus) => {
tokens.push(Token::Value(current_num.clone()));
current_num.clear();
tokens.push(Token::OpAdd);
is_neg = true;
}
Symb::Times => {
tokens.push(Token::Number(current_num * current_sgn));
current_num = 0.0;
current_sgn = 1.0;
Some(Symb::Times) => {
tokens.push(Token::Value(current_num.clone()));
current_num.clear();
tokens.push(Token::OpMult);
is_neg = true;
}
Symb::Zero => {
current_num = current_num * 10.0;
Some(Symb::Zero) => {
current_num.push('0');
is_neg = false;
}
Symb::Number(x) => {
current_num = current_num * 10.0 + (x.get() as f32);
Some(Symb::Number(x)) => {
current_num.push_str(&x.to_string());
is_neg = false;
}
None => {
current_num.push('_');
is_neg = false;
}
}
}
tokens.push(Token::Number(current_num * current_sgn));
tokens.push(Token::Value(current_num));
tokens
}
pub fn treeify(tokens: &Vec<Token>) -> TreeElement {
let mut tree: Vec<_> = tokens
.iter()
.map(|x| InterTreeElement::Unprocessed(x.clone()))
.collect();
let mut priority_level = 0;
let mut did_something;
while tokens.len() > 1 {
while tree.len() > 1 {
did_something = false;
for i in 0..tokens.len() {
for i in 0..tree.len() {
if match priority_level {
0 => matches!(tokens[i], Token::OpMult | Token::OpDiv),
1 => matches!(tokens[i], Token::OpAdd | Token::OpSub),
0 => matches!(
tree[i],
InterTreeElement::Unprocessed(Token::OpMult)
| InterTreeElement::Unprocessed(Token::OpDiv)
),
1 => matches!(
tree[i],
InterTreeElement::Unprocessed(Token::OpAdd)
| InterTreeElement::Unprocessed(Token::OpSub)
),
_ => false,
} {
did_something = true;
let l = &tokens[i - 1];
let r = &tokens[i + 1];
let l = &tree[i - 1];
let r = &tree[i + 1];
let v = match tokens[i] {
Token::OpAdd => l.val() + r.val(),
Token::OpDiv => l.val() / r.val(),
Token::OpSub => l.val() - r.val(),
Token::OpMult => l.val() * r.val(),
let l = match l {
InterTreeElement::Processed(x) => x.clone(),
InterTreeElement::Unprocessed(Token::Value(s)) => {
if s.starts_with('-') {
TreeElement::Neg {
r: {
if s.contains('_') {
Box::new(TreeElement::Partial(s[1..].to_string()))
} else {
Box::new(TreeElement::Number(s[1..].parse().unwrap()))
}
},
}
} else {
if s.contains('_') {
TreeElement::Partial(s.to_string())
} else {
TreeElement::Number(s.parse().unwrap())
}
}
}
_ => unreachable!(),
};
tokens.remove(i - 1);
tokens.remove(i - 1);
tokens[i - 1] = Token::Number(v);
let r = match r {
InterTreeElement::Processed(x) => x.clone(),
InterTreeElement::Unprocessed(Token::Value(s)) => {
if s.starts_with('-') {
TreeElement::Neg {
r: {
if s.contains('_') {
Box::new(TreeElement::Partial(s[1..].to_string()))
} else {
Box::new(TreeElement::Number(s[1..].parse().unwrap()))
}
},
}
} else {
if s.contains('_') {
TreeElement::Partial(s.to_string())
} else {
TreeElement::Number(s.parse().unwrap())
}
}
}
_ => unreachable!(),
};
let v = match tree[i] {
InterTreeElement::Unprocessed(Token::OpAdd) => TreeElement::Add {
l: Box::new(l),
r: Box::new(r),
},
InterTreeElement::Unprocessed(Token::OpDiv) => TreeElement::Div {
l: Box::new(l),
r: Box::new(r),
},
InterTreeElement::Unprocessed(Token::OpMult) => TreeElement::Mul {
l: Box::new(l),
r: Box::new(r),
},
InterTreeElement::Unprocessed(Token::OpSub) => TreeElement::Sub {
l: Box::new(l),
r: Box::new(r),
},
_ => unreachable!(),
};
tree.remove(i - 1);
tree.remove(i - 1);
tree[i - 1] = InterTreeElement::Processed(v);
break;
}
}
@ -243,7 +455,14 @@ impl Board {
}
}
Some(tokens[0].val())
match tree.into_iter().next().unwrap() {
InterTreeElement::Processed(x) => x,
_ => unreachable!(),
}
}
pub fn evaluate(&self) -> Option<f32> {
Self::treeify(&self.tokenize()).evaluate()
}
/// Hacky method to parse a board from a string
@ -255,7 +474,9 @@ impl Board {
let x = s
.chars()
.filter_map(|c| {
if let Some(symb) = Symb::from_char(&c) {
if c == '_' {
Some(None)
} else if let Some(symb) = Symb::from_char(&c) {
Some(Some((symb, current_player)))
} else {
None