Решение на Логически изрази от Пресияна Борисова

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

Към профила на Пресияна Борисова

Резултати

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

Код

use std::{collections::HashSet, vec};
#[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 {
expr_stack: Vec<Expr>,
op_stack: Vec<char>,
expecting_bin_op: bool,
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {
expr_stack: Vec::new(),
op_stack: Vec::new(),
expecting_bin_op: false,
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.expecting_bin_op {
return Err(ParseError::UnexpectedExpr);
}
self.expr_stack.push(Expr::Atom(c));
self.expecting_bin_op = true;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if op == '!' {
if self.expecting_bin_op {
return Err(ParseError::UnexpectedUnaryOp);
}
self.op_stack.push(op);
} else {
if !self.expecting_bin_op {
return Err(ParseError::UnexpectedBinOp);
}
self.op_stack.push(op);
self.expecting_bin_op = false;
}
Ok(())
}
pub fn finish(mut self) -> Result<Expr, ParseError> {
while let Some(op) = self.op_stack.pop() {
if op == '!' {
let expr = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
self.expr_stack.push(Expr::Not(Box::new(expr)));
} else {
let right = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
let left = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
let combined = match op {
'&' => Expr::And(vec![left, right]),
'|' => Expr::Or(vec![left, right]),
_ => return Err(ParseError::UnexpectedBinOp),
};
self.expr_stack.push(combined);
}
}
if self.expr_stack.len() == 1 {
Ok(self.expr_stack.pop().unwrap())
} else {
Err(ParseError::UnexpectedEnd)
}
}
}
pub struct ExprParser {
expr_stack: Vec<Expr>,
op_stack: Vec<char>,
paren_stack: Vec<usize>,
expecting_bin_op: bool,
whole_expr: String,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {
expr_stack: Vec::new(),
op_stack: Vec::new(),
paren_stack: Vec::new(),
expecting_bin_op: false,
whole_expr: String::new(),
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.expecting_bin_op {
return Err(ParseError::UnexpectedExpr);
}
self.expr_stack.push(Expr::Atom(c));
self.whole_expr.push(c);
self.expecting_bin_op = true;
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if op == '!' {
if self.expecting_bin_op {
return Err(ParseError::UnexpectedUnaryOp);
}
self.op_stack.push(op);
} else {
if !self.expecting_bin_op {
return Err(ParseError::UnexpectedBinOp);
}
self.op_stack.push(op);
self.expecting_bin_op = false;
}
self.whole_expr.push(op);
Ok(())
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
self.paren_stack.push(self.expr_stack.len());
self.op_stack.push('(');
self.expecting_bin_op = false;
self.whole_expr.push('(');
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
let mut sub_exprs = Vec::new();
self.whole_expr.push(')');
while let Some(op) = self.op_stack.pop() {
if op == '(' {
self.paren_stack.pop().ok_or(ParseError::UnexpectedParen)?;
if sub_exprs.len() > 1 {
return Err(ParseError::UnexpectedExpr);
}
if let Some(expr) = sub_exprs.pop() {
self.expr_stack.push(expr);
}
self.expecting_bin_op = true;
return Ok(());
}
if op == '!' {
if sub_exprs.len() > 0 {
let expr = sub_exprs.pop().ok_or(ParseError::UnexpectedEnd)?;
sub_exprs.push(Expr::Not(Box::new(expr)));
} else {
let expr = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
sub_exprs.push(Expr::Not(Box::new(expr)));
}
} else {
let right = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
let left: Expr;
if sub_exprs.len() > 0 {
left = sub_exprs.pop().ok_or(ParseError::UnexpectedEnd)?;
} else {
left = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
}
let combined = match op {
'&' => Expr::And(vec![left, right]),
'|' => Expr::Or(vec![left, right]),
_ => return Err(ParseError::UnexpectedBinOp),
};
sub_exprs.push(combined);
}
}
Err(ParseError::UnexpectedParen)
}
pub fn finish(mut self) -> Result<Expr, ParseError> {
while let Some(op) = self.op_stack.pop() {
if op == '!' {
let expr = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
self.expr_stack.push(Expr::Not(Box::new(expr)));
} else {
let right = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
let left = self.expr_stack.pop().ok_or(ParseError::UnexpectedEnd)?;
let combined = match op {
'&' => Expr::And(vec![left, right]),
'|' => Expr::Or(vec![left, right]),
_ => return Err(ParseError::UnexpectedBinOp),
};
self.expr_stack.push(combined);
}
}
if self.expr_stack.len() == 1 {
Ok(self.expr_stack.pop().unwrap())
} else {
Err(ParseError::UnexpectedEnd)
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
True,
False,
Expr(Expr),
}
pub fn eval(expr: &Expr, truthy: &[char], falsy: &[char]) -> Value {
let truthy_set: HashSet<char> = truthy.iter().cloned().collect();
let falsy_set: HashSet<char> = falsy.iter().cloned().collect();
match expr {
Expr::Atom(c) => {
if truthy_set.contains(c) {
Value::True
} else if falsy_set.contains(c) {
Value::False
} else {
Value::Expr(expr.clone())
}
}
Expr::Not(inner) => match eval(inner, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(_) => Value::Expr(Expr::Not(inner.clone())),
},
Expr::And(exprs) => {
let mut simplified = Vec::new();
for e in exprs {
match eval(e, truthy, falsy) {
Value::True => continue,
Value::False => return Value::False,
Value::Expr(inner) => simplified.push(inner),
}
}
if simplified.is_empty() {
Value::True
} else if simplified.len() == 1 {
Value::Expr(simplified.pop().unwrap())
} else {
Value::Expr(Expr::And(simplified))
}
}
Expr::Or(exprs) => {
let mut simplified = Vec::new();
for e in exprs {
match eval(e, truthy, falsy) {
Value::True => return Value::True,
Value::False => continue,
Value::Expr(inner) => simplified.push(inner),
}
}
if simplified.is_empty() {
Value::False
} else if simplified.len() == 1 {
Value::Expr(simplified.pop().unwrap())
} else {
Value::Expr(Expr::Or(simplified))
}
}
}
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-1j986el/solution)
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.90s
     Running tests/solution_test.rs (target/debug/deps/solution_test-1428e1090729d165)

running 20 tests
test solution_test::test_error_paren_mismatched ... FAILED
test solution_test::test_eval_full ... ok
test solution_test::test_eval_not_and_or ... ok
test solution_test::test_eval_partial ... ok
test solution_test::test_eval_unwrap_and_or ... ok
test solution_test::test_eval_unwrap_nested ... FAILED
test solution_test::test_paren_expr_priority ... ok
test solution_test::test_paren_around_expr ... ok
test solution_test::test_paren_not ... FAILED
test solution_test::test_paren_nested ... FAILED
test solution_test::test_paren_surrounded ... FAILED
test solution_test::test_parser_alternating_ops ... FAILED
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 ... FAILED
test solution_test::test_parser_multiple_atoms_same_op ... FAILED
test solution_test::test_parser_not ... ok
test solution_test::test_parser_multiple_not ... FAILED

failures:

---- solution_test::test_error_paren_mismatched stdout ----
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.close_paren(), Err(_))', tests/solution_test.rs:331:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_error_paren_mismatched' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:325:5

---- solution_test::test_eval_unwrap_nested stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Expr(Or([Atom('X'), Atom('B'), Not(And([Atom('C'), Atom('D')])), Atom('Y')]))`,
 right: `Expr(Or([Atom('X'), Atom('B'), Not(Atom('D')), Atom('Y')]))`', tests/solution_test.rs:480:9
thread 'solution_test::test_eval_unwrap_nested' panicked at 'assertion failed: `(left == right)`
  left: `Expr(Or([Atom('X'), Atom('B'), Not(And([Atom('C'), Atom('D')])), Atom('Y')]))`,
 right: `Expr(Or([Atom('X'), Atom('B'), Not(Atom('D')), Atom('Y')]))`', tests/solution_test.rs:479:5

---- solution_test::test_paren_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Not(Or([Or([Atom('A'), Atom('B')]), Atom('X')]))`,
 right: `Or([Not(Or([Atom('A'), Atom('B')])), Atom('X')])`', tests/solution_test.rs:226:9
thread 'solution_test::test_paren_not' panicked at 'assertion failed: `(left == right)`
  left: `Not(Or([Or([Atom('A'), Atom('B')]), Atom('X')]))`,
 right: `Or([Not(Or([Atom('A'), Atom('B')])), Atom('X')])`', tests/solution_test.rs:216:5

---- solution_test::test_paren_nested stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Not(And([Not(And([Not(And([Atom('C'), Atom('D')])), Atom('B')])), Atom('A')]))`,
 right: `Not(And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))]))`', tests/solution_test.rs:255:9
thread 'solution_test::test_paren_nested' panicked at 'assertion failed: `(left == right)`
  left: `Not(And([Not(And([Not(And([Atom('C'), Atom('D')])), Atom('B')])), Atom('A')]))`,
 right: `Not(And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))]))`', tests/solution_test.rs:252:5

---- solution_test::test_paren_surrounded stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Or([Atom('X'), Or([And([Atom('A'), Atom('B')]), Or([And([Atom('C'), Atom('D')]), Atom('Y')])])])`,
 right: `Or([Atom('X'), And([Atom('A'), Atom('B')]), And([Atom('C'), Atom('D')]), Atom('Y')])`', tests/solution_test.rs:238:9
thread 'solution_test::test_paren_surrounded' panicked at 'assertion failed: `(left == right)`
  left: `Or([Atom('X'), Or([And([Atom('A'), Atom('B')]), Or([And([Atom('C'), Atom('D')]), Atom('Y')])])])`,
 right: `Or([Atom('X'), And([Atom('A'), Atom('B')]), And([Atom('C'), Atom('D')]), Atom('Y')])`', tests/solution_test.rs:235:5

---- solution_test::test_parser_alternating_ops stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A'), Or([Atom('B'), And([Atom('C'), Atom('D')])])])`,
 right: `And([Or([And([Atom('A'), Atom('B')]), Atom('C')]), Atom('D')])`', tests/solution_test.rs:160:9
thread 'solution_test::test_parser_alternating_ops' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A'), Or([Atom('B'), And([Atom('C'), Atom('D')])])])`,
 right: `And([Or([And([Atom('A'), Atom('B')]), Atom('C')]), Atom('D')])`', tests/solution_test.rs:157:5

---- solution_test::test_parser_expr_and_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Not(Or([Atom('A'), Atom('B')]))`,
 right: `Or([Not(Atom('A')), Atom('B')])`', tests/solution_test.rs:114:9
thread 'solution_test::test_parser_expr_and_not' panicked at 'assertion failed: `(left == right)`
  left: `Not(Or([Atom('A'), Atom('B')]))`,
 right: `Or([Not(Atom('A')), Atom('B')])`', tests/solution_test.rs:107:5

---- solution_test::test_parser_multiple_atoms_same_op stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A'), And([Atom('B'), Atom('C')])])`,
 right: `And([Atom('A'), Atom('B'), Atom('C')])`', tests/solution_test.rs:127:9
thread 'solution_test::test_parser_multiple_atoms_same_op' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A'), And([Atom('B'), Atom('C')])])`,
 right: `And([Atom('A'), Atom('B'), Atom('C')])`', tests/solution_test.rs:124:5

---- solution_test::test_parser_multiple_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `Not(Not(Or([Atom('A'), Atom('B')])))`,
 right: `Or([Not(Not(Atom('A'))), Atom('B')])`', tests/solution_test.rs:151:9
thread 'solution_test::test_parser_multiple_not' panicked at 'assertion failed: `(left == right)`
  left: `Not(Not(Or([Atom('A'), Atom('B')])))`,
 right: `Or([Not(Not(Atom('A'))), Atom('B')])`', tests/solution_test.rs:140:5


failures:
    solution_test::test_error_paren_mismatched
    solution_test::test_eval_unwrap_nested
    solution_test::test_paren_nested
    solution_test::test_paren_not
    solution_test::test_paren_surrounded
    solution_test::test_parser_alternating_ops
    solution_test::test_parser_expr_and_not
    solution_test::test_parser_multiple_atoms_same_op
    solution_test::test_parser_multiple_not

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

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

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

Пресияна качи първо решение на 22.12.2024 22:22 (преди 9 месеца)