Решение на Логически изрази от Пламен Дарджиков

Обратно към всички решения

Към профила на Пламен Дарджиков

Резултати

  • 19 точки от тестове
  • 0 бонус точки
  • 19 точки общо
  • 19 успешни тест(а)
  • 1 неуспешни тест(а)

Код

use std::collections::VecDeque;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr {
Atom(char),
Not(Box<Expr>),
And(Vec<Expr>),
Or(Vec<Expr>),
}
#[derive(Debug, PartialEq, Eq)]
pub enum ParseError {
UnexpectedExpr,
UnexpectedUnaryOp,
UnexpectedBinOp,
UnexpectedParen,
UnexpectedEnd,
}
pub struct SimpleExprParser {
expressionVector: VecDeque<Expr>,
operatorVector: VecDeque<char>,
lastCharIsAtom: bool,
lastWasNegative: bool,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {expressionVector: VecDeque::new(), operatorVector: VecDeque::new(), lastCharIsAtom: false, lastWasNegative: false}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedExpr);
}
self.expressionVector.push_back(if self.lastWasNegative {
Expr::Not(Box::new(Expr::Atom(c)))
} else {
Expr::Atom(c)
});
self.lastCharIsAtom = true;
self.lastWasNegative = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'&' | '|' => {
if !self.lastCharIsAtom {
return Err(ParseError::UnexpectedBinOp);
}
self.lastWasNegative = false;
}
'!' | _ => {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedUnaryOp);
}
self.lastWasNegative = true;
}
}
self.operatorVector.push_back(op);
self.lastCharIsAtom = false;
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
let mut parser = self;
if !parser.lastCharIsAtom {
return Err(ParseError::UnexpectedEnd);
}
while let Some(op) = parser.operatorVector.pop_front() {
match op {
'&' | '|' => {
let mut groupedExpression: Vec::<Expr> = vec![parser.expressionVector.pop_front().unwrap()];
while let Some(expression) = parser.expressionVector.pop_front() {
groupedExpression.push(expression);
if parser.operatorVector.front().cloned() != Some(op) {
break;
}
parser.operatorVector.pop_front();
}
parser.expressionVector.push_front(match op {
'&' => Expr::And(groupedExpression),
_ => Expr::Or(groupedExpression),
});
}
_ => {}
}
}
if let Some(expr) = parser.expressionVector.pop_front() {
if !parser.expressionVector.is_empty() {
return Err(ParseError::UnexpectedExpr);
}
Ok(expr)
} else {
return Err(ParseError::UnexpectedExpr);
}
}
}
pub struct ExprParser {
expressionVector: VecDeque<Expr>,
operatorVector: VecDeque<char>,
lastCharIsAtom: bool,
beforeParenExpr: Vec<VecDeque<Expr>>,
beforeParenOp: Vec<VecDeque<char>>,
lastWasNegative: bool,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {expressionVector: VecDeque::new(), operatorVector: VecDeque::new(), lastCharIsAtom: false, beforeParenExpr: Vec::new(), beforeParenOp: Vec::new(), lastWasNegative: false}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedExpr);
}
self.expressionVector.push_back(if self.lastWasNegative {
self.operatorVector.pop_back();
Expr::Not(Box::new(Expr::Atom(c)))
} else {
Expr::Atom(c)
});
self.lastCharIsAtom = true;
self.lastWasNegative = false;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'&' | '|' => {
if !self.lastCharIsAtom {
return Err(ParseError::UnexpectedBinOp);
}
self.lastWasNegative = false;
}
'!' | _ => {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedUnaryOp);
}
self.lastWasNegative = true;
}
}
self.operatorVector.push_back(op);
self.lastCharIsAtom = false;
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
if self.lastCharIsAtom {
return Err(ParseError::UnexpectedParen);
}
self.beforeParenExpr.push(self.expressionVector.clone());
self.beforeParenOp.push(self.operatorVector.clone());
self.lastWasNegative = false;
self.operatorVector.push_back('(');
self.expressionVector.clear();
self.operatorVector.clear();
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
if !self.lastCharIsAtom || self.beforeParenExpr.is_empty() {
return Err(ParseError::UnexpectedParen);
}
while let Some(op) = self.operatorVector.pop_front() {
if op == '(' {
break;
}
let res = self.use_operator(op);
if res.is_err() {
return Err(res.unwrap_err());
}
}
if let Some(prev_expr) = self.beforeParenExpr.pop() {
for expr in prev_expr.into_iter().rev() {
self.expressionVector.push_front(expr);
}
}
self.operatorVector = self.beforeParenOp.pop().unwrap();
if let Some(op) = self.operatorVector.back() {
if op.clone() == '!' {
let exprToNegate = self.expressionVector.pop_back().unwrap();
self.expressionVector.push_back(Expr::Not(Box::new(exprToNegate)));
self.operatorVector.pop_back();
}
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
let mut parser = self;
if !parser.lastCharIsAtom {
return Err(ParseError::UnexpectedEnd);
}
if !parser.beforeParenExpr.is_empty() {
return Err(ParseError::UnexpectedParen);
}
while let Some(op) = parser.operatorVector.pop_front() {
let res = parser.use_operator(op);
if res.is_err() {
return Err(res.unwrap_err());
}
}
if let Some(expr) = parser.expressionVector.pop_front() {
if !parser.expressionVector.is_empty() {
return Err(ParseError::UnexpectedBinOp);
}
Ok(expr)
} else {
return Err(ParseError::UnexpectedExpr);
}
}
fn use_operator(&mut self, op: char) -> Result<(), ParseError> {
match op {
'&' | '|' => {
let mut groupedExpression: Vec<Expr> = vec![self.expressionVector.pop_front().unwrap()];
while let Some(expression) = self.expressionVector.pop_front() {
groupedExpression.push(expression);
if self.operatorVector.front().cloned() != Some(op) {
break;
}
self.operatorVector.pop_front();
}
self.expressionVector.push_front(match op {
'&' => Expr::And(groupedExpression),
_ => Expr::Or(groupedExpression),
});
}
_ => {}
}
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
True,
False,
Expr(Expr),
}
pub fn eval(expr: &Expr, truthy: &[char], falsy: &[char]) -> Value {
match expr {
Expr::Atom(c) => {
if truthy.contains(&c) {
Value::True
} else if falsy.contains(&c) {
Value::False
} else {
Value::Expr(expr.clone()) // If the value is unknown, return the expression itself
}
}
Expr::Not(innerExpr) => {
match eval(innerExpr, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(e) => {
match e {
Expr::Not(otherE) => {
Value::Expr(*otherE)
}
_ => {
Value::Expr(Expr::Not(Box::new(e)))
}
}
},
}
}
Expr::And(expressions) => {
let mut simplifiedExprs: Vec<Expr> = Vec::new();
let mut hasFalse = false;
for expr in expressions {
match eval(expr, truthy, falsy) {
Value::False => hasFalse = true,
Value::Expr(e) => simplifiedExprs.push(e),
_ => {}
}
}
if hasFalse {
Value::False
} else if simplifiedExprs.is_empty() {
Value::True
} else if simplifiedExprs.len() == 1{
Value::Expr(simplifiedExprs.first().unwrap().clone())
} else {
Value::Expr(Expr::And(simplifiedExprs))
}
}
Expr::Or(expressions) => {
let mut simplifiedExprs: Vec<Expr> = Vec::new();
let mut hasTrue = false;
for expr in expressions {
match eval(expr, truthy, falsy) {
Value::True => hasTrue = true,
Value::Expr(e) => simplifiedExprs.push(e),
_ => {}
}
}
if hasTrue {
Value::True
} else if simplifiedExprs.is_empty() {
Value::False
} else if simplifiedExprs.len() == 1 {
Value::Expr(simplifiedExprs.first().unwrap().clone())
} else {
Value::Expr(Expr::Or(simplifiedExprs))
}
}
}
}

Лог от изпълнението

Compiling solution v0.1.0 (/tmp/d20241224-258381-rbi409/solution)
warning: structure field `expressionVector` should have a snake case name
  --> src/lib.rs:21:5
   |
21 |     expressionVector: VecDeque<Expr>,
   |     ^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `expression_vector`
   |
   = note: `#[warn(non_snake_case)]` on by default

warning: structure field `operatorVector` should have a snake case name
  --> src/lib.rs:22:5
   |
22 |     operatorVector: VecDeque<char>,
   |     ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `operator_vector`

warning: structure field `lastCharIsAtom` should have a snake case name
  --> src/lib.rs:23:5
   |
23 |     lastCharIsAtom: bool,
   |     ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_char_is_atom`

warning: structure field `lastWasNegative` should have a snake case name
  --> src/lib.rs:24:5
   |
24 |     lastWasNegative: bool,
   |     ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_was_negative`

warning: variable `groupedExpression` should have a snake case name
  --> src/lib.rs:78:29
   |
78 |                     let mut groupedExpression: Vec::<Expr> = vec![parser.expressionVector.pop_front().unwrap()];
   |                             ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `grouped_expression`

warning: structure field `expressionVector` should have a snake case name
   --> src/lib.rs:110:5
    |
110 |     expressionVector: VecDeque<Expr>,
    |     ^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `expression_vector`

warning: structure field `operatorVector` should have a snake case name
   --> src/lib.rs:111:5
    |
111 |     operatorVector: VecDeque<char>,
    |     ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `operator_vector`

warning: structure field `lastCharIsAtom` should have a snake case name
   --> src/lib.rs:112:5
    |
112 |     lastCharIsAtom: bool,
    |     ^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_char_is_atom`

warning: structure field `beforeParenExpr` should have a snake case name
   --> src/lib.rs:113:5
    |
113 |     beforeParenExpr: Vec<VecDeque<Expr>>,
    |     ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `before_paren_expr`

warning: structure field `beforeParenOp` should have a snake case name
   --> src/lib.rs:114:5
    |
114 |     beforeParenOp: Vec<VecDeque<char>>,
    |     ^^^^^^^^^^^^^ help: convert the identifier to snake case: `before_paren_op`

warning: structure field `lastWasNegative` should have a snake case name
   --> src/lib.rs:115:5
    |
115 |     lastWasNegative: bool,
    |     ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `last_was_negative`

warning: variable `exprToNegate` should have a snake case name
   --> src/lib.rs:201:21
    |
201 |                 let exprToNegate = self.expressionVector.pop_back().unwrap();
    |                     ^^^^^^^^^^^^ help: convert the identifier to snake case: `expr_to_negate`

warning: variable `groupedExpression` should have a snake case name
   --> src/lib.rs:244:25
    |
244 |                 let mut groupedExpression: Vec<Expr> = vec![self.expressionVector.pop_front().unwrap()];
    |                         ^^^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `grouped_expression`

warning: variable `innerExpr` should have a snake case name
   --> src/lib.rs:282:19
    |
282 |         Expr::Not(innerExpr) => {
    |                   ^^^^^^^^^ help: convert the identifier to snake case: `inner_expr`

warning: variable `otherE` should have a snake case name
   --> src/lib.rs:288:35
    |
288 |                         Expr::Not(otherE) => {
    |                                   ^^^^^^ help: convert the identifier to snake case: `other_e`

warning: variable `simplifiedExprs` should have a snake case name
   --> src/lib.rs:299:21
    |
299 |             let mut simplifiedExprs: Vec<Expr> = Vec::new();
    |                     ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `simplified_exprs`

warning: variable `hasFalse` should have a snake case name
   --> src/lib.rs:300:21
    |
300 |             let mut hasFalse = false;
    |                     ^^^^^^^^ help: convert the identifier to snake case: `has_false`

warning: variable `simplifiedExprs` should have a snake case name
   --> src/lib.rs:321:21
    |
321 |             let mut simplifiedExprs: Vec<Expr> = Vec::new();
    |                     ^^^^^^^^^^^^^^^ help: convert the identifier to snake case: `simplified_exprs`

warning: variable `hasTrue` should have a snake case name
   --> src/lib.rs:322:21
    |
322 |             let mut hasTrue = false;
    |                     ^^^^^^^ help: convert the identifier to snake case: `has_true`

warning: `solution` (lib) generated 19 warnings
warning: variable does not need to be mutable
   --> tests/solution_test.rs:306:13
    |
306 |         let mut parser = SimpleExprParser::new();
    |             ----^^^^^^
    |             |
    |             help: remove this `mut`
    |
    = note: `#[warn(unused_mut)]` on by default

warning: `solution` (test "solution_test") generated 1 warning
    Finished test [unoptimized + debuginfo] target(s) in 1.83s
     Running tests/solution_test.rs (target/debug/deps/solution_test-1428e1090729d165)

running 20 tests
test solution_test::test_eval_full ... ok
test solution_test::test_error_paren_mismatched ... ok
test solution_test::test_eval_not_and_or ... ok
test solution_test::test_eval_partial ... ok
test solution_test::test_eval_unwrap_nested ... ok
test solution_test::test_eval_unwrap_and_or ... ok
test solution_test::test_paren_around_expr ... ok
test solution_test::test_paren_expr_priority ... ok
test solution_test::test_paren_nested ... ok
test solution_test::test_paren_not ... ok
test solution_test::test_paren_surrounded ... ok
test solution_test::test_parser_alternating_ops ... ok
test solution_test::test_parser_and_or ... ok
test solution_test::test_parser_atom ... ok
test solution_test::test_parser_error_unexpected_end ... ok
test solution_test::test_parser_errors_basic ... ok
test solution_test::test_parser_expr_and_not ... ok
test solution_test::test_parser_multiple_atoms_same_op ... ok
test solution_test::test_parser_not ... ok
test solution_test::test_parser_multiple_not ... FAILED

failures:

---- solution_test::test_parser_multiple_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Not(Atom('B'))`,
 right: `Not(Not(Not(Atom('B'))))`', tests/solution_test.rs:143:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_parser_multiple_not' panicked at 'assertion failed: `(left == right)`
  left: `Not(Atom('B'))`,
 right: `Not(Not(Not(Atom('B'))))`', tests/solution_test.rs:140:5


failures:
    solution_test::test_parser_multiple_not

test result: FAILED. 19 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--test solution_test`

История (1 версия и 0 коментара)

Пламен качи първо решение на 21.12.2024 17:27 (преди 9 месеца)