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

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

Към профила на Петър Христов

Резултати

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

Код

#[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 {
pub vec: Vec<Expr>,
last_element: char,
binary_op: Vec<char>,
unary_op: Vec<char>,
}
impl Clone for SimpleExprParser {
fn clone(&self) -> Self {
SimpleExprParser {
vec: self.vec.clone(),
last_element: self.last_element,
binary_op: self.binary_op.clone(),
unary_op: self.unary_op.clone(),
}
}
}
impl SimpleExprParser {
pub fn new() -> SimpleExprParser {
SimpleExprParser {
vec: Vec::new(),
last_element: '&',
binary_op: vec!['|', '&'],
unary_op: vec!['!'],
}
}
pub fn is_unary_operator(&mut self, c: &char) -> bool {
self.unary_op.contains(c)
}
pub fn is_binary_operator(&mut self, c: &char) -> bool {
self.binary_op.contains(c)
}
pub fn is_operator(&mut self, c: &char) -> bool {
self.is_unary_operator(c) | self.is_binary_operator(c)
}
/// Приема атом.
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.is_operator(&c) {
panic!("Operator inputted in push_atom");
}
let last_element = self.last_element;
if !self.is_operator(&last_element) {
println!("Consecutive atoms detected");
return Err(ParseError::UnexpectedExpr);
}
self.vec.push(Expr::Atom(c));
self.last_element = c;
Ok(())
}
/// Приема символ за операция.
///
/// `op` ще бъде едно от '&', '|', '!'.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if !self.is_operator(&op) {
panic!("Atom inputted in push_op");
}
let last_element = self.last_element;
if self.is_binary_operator(&last_element) && self.is_binary_operator(&op) {
println!("Consecutive binary operators detected");
return Err(ParseError::UnexpectedBinOp);
} else if self.is_unary_operator(&last_element) {
println!("Consecutive unary operators detected");
return Err(ParseError::UnexpectedUnaryOp);
}
if op == '&' {
self.vec.push(Expr::And(Vec::new()));
}
if op == '|' {
self.vec.push(Expr::Or(Vec::new()));
}
if op == '!' {
self.vec.push(Expr::Not(Box::new(Expr::Atom('\0'))));
}
self.last_element = op;
Ok(())
}
pub fn push_expr(&mut self, expr: &Expr) {
self.last_element = 'e';
self.vec.push((*expr).clone());
}
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
if self.last_element == '!' || self.last_element == '|' || self.last_element == '&' {
println!("Last element is an operator!");
return Err(ParseError::UnexpectedEnd);
}
let first_element: Expr;
let start_index;
let length = self.vec.len();
if let Expr::Not(_) = self.vec[0] {
first_element = Expr::Not(Box::new(self.vec[1].clone()));
start_index = 2;
} else {
first_element = self.vec[0].clone();
start_index = 1;
}
let mut curr = vec![first_element];
let curr_type = Expr::And(Vec::new());
fn finish_rec(
start_index: usize,
length: usize,
vec: &Vec<Expr>,
curr: &mut Vec<Expr>,
curr_type: Expr,
) {
let mut i = start_index;
while i < length {
let to_add: Expr;
let current_el = vec[i].clone();
if let Expr::Not(_) = vec[i + 1] {
to_add = Expr::Not(Box::new(vec[i + 2].clone()));
i += 1;
} else {
to_add = vec[i + 1].clone();
}
match (curr_type.clone(), current_el) {
(Expr::And(_), Expr::And(_)) => curr.push(to_add),
(Expr::Or(_), Expr::Or(_)) => curr.push(to_add),
(Expr::And(_), Expr::Or(_)) => {
let mut v = vec![to_add];
finish_rec(i + 2, length, vec, &mut v, Expr::Or(Vec::new()));
curr.push(Expr::Or(v));
break;
}
(Expr::Or(_), Expr::And(_)) => {
let mut v = vec![to_add];
finish_rec(i + 2, length, vec, &mut v, Expr::And(Vec::new()));
curr.push(Expr::And(v));
break;
}
_ => println!("Unexpected Output!"),
}
i += 2;
}
}
finish_rec(start_index, length, &self.vec, &mut curr, curr_type);
Ok(Expr::And(curr))
}
}
pub struct ExprParser {
arr_parsers: Vec<SimpleExprParser>,
stack_paren: Vec<SimpleExprParser>,
last_char: char,
}
impl ExprParser {
pub fn new() -> ExprParser {
ExprParser {
arr_parsers: Vec::new(),
stack_paren: vec![SimpleExprParser::new()],
last_char: '&',
}
}
/// Приема атом.
///
/// `c` ще бъде валиден символ за атом.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if let Some(last_expr) = self.stack_paren.last_mut() {
self.last_char = c;
last_expr.push_atom(c)
} else {
panic!("Expr not present in stack!");
}
}
/// Приема символ за операция.
///
/// `op` ще бъде едно от '&', '|', '!'.
/// В противен случай можете да panic-нете (няма да се тества)
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
if let Some(last_expr) = self.stack_paren.last_mut() {
self.last_char = op;
last_expr.push_op(op)
} else {
panic!("Expr not present in stack!");
}
}
/// Приема отваряща скоба.
pub fn open_paren(&mut self) -> Result<(), ParseError> {
if !(self.last_char == '&' || self.last_char == '!' || self.last_char == '|') {
return Err(ParseError::UnexpectedParen);
}
self.stack_paren.push(SimpleExprParser::new());
Ok(())
}
/// Приема затваряща скоба.
pub fn close_paren(&mut self) -> Result<(), ParseError> {
if self.stack_paren.len() == 1 {
println!("Nothing to close!");
return Err(ParseError::UnexpectedParen);
}
if self.last_char == '&' || self.last_char == '!' || self.last_char == '|' {
return Err(ParseError::UnexpectedParen);
}
if let Some(curr) = self.stack_paren.pop() {
let expr = curr.finish().unwrap();
if let Some(last) = self.stack_paren.last_mut() {
last.push_expr(&expr);
}
} else {
panic!("Stack is empty!");
}
Ok(())
}
/// Завършва парсването и връща построения израз.
pub fn finish(self) -> Result<Expr, ParseError> {
if self.stack_paren.len() > 1 {
println!("Parentheses not closed!");
return Err(ParseError::UnexpectedEnd);
}
let arr = self.stack_paren.last().unwrap().clone();
arr.finish()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Value {
True,
False,
Expr(Expr),
}
fn eval_rec_or(arr: &Vec<Expr>, truthy: &[char], falsy: &[char], mut current_eval: Value) -> Value {
for item in arr {
match item {
Expr::Atom(ch) => {
if truthy.contains(ch) {
current_eval = Value::True;
} else if falsy.contains(ch) && current_eval == Value::False {
current_eval = Value::Expr((*item).clone());
}
}
Expr::Not(ptr) => match (**ptr).clone() {
Expr::And(arr_next) => {
current_eval = eval_rec_and(&arr_next, truthy, falsy, current_eval)
}
Expr::Or(arr_next) => {
current_eval = eval_rec_or(&arr_next, truthy, falsy, current_eval)
}
Expr::Atom(ch) => {
if falsy.contains(&ch) {
current_eval = Value::True;
} else if !truthy.contains(&ch) && current_eval == Value::False {
current_eval = Value::Expr((*item).clone());
}
}
_ => panic!("Unexpected Input detected!"),
},
Expr::And(arr_next) => {
current_eval = eval_rec_and(arr_next, truthy, falsy, current_eval);
}
Expr::Or(arr_next) => {
current_eval = eval_rec_or(arr_next, truthy, falsy, current_eval);
}
}
}
current_eval
}
fn eval_rec_and(
arr: &Vec<Expr>,
truthy: &[char],
falsy: &[char],
mut current_eval: Value,
) -> Value {
for item in arr {
match item {
Expr::Atom(ch) => {
if falsy.contains(ch) {
current_eval = Value::False;
} else if !truthy.contains(ch) && current_eval == Value::True {
current_eval = Value::Expr((*item).clone());
}
}
Expr::Not(ptr) => match (**ptr).clone() {
Expr::And(arr_next) => {
current_eval = eval_rec_and(&arr_next, truthy, falsy, current_eval)
}
Expr::Or(arr_next) => {
current_eval = eval_rec_or(&arr_next, truthy, falsy, current_eval)
}
Expr::Atom(ch) => {
if truthy.contains(&ch) {
current_eval = Value::False;
} else if !falsy.contains(&ch) && current_eval == Value::True {
current_eval = Value::Expr((*item).clone());
}
}
_ => panic!("Unexpected Input detected!"),
},
Expr::And(arr_next) => {
current_eval = eval_rec_and(arr_next, truthy, falsy, current_eval);
}
Expr::Or(arr_next) => {
current_eval = eval_rec_or(arr_next, truthy, falsy, current_eval);
}
}
}
current_eval
}
pub fn eval(expr: &Expr, truthy: &[char], falsy: &[char]) -> Value {
if let Expr::And(arr) = expr {
eval_rec_and(arr, truthy, falsy, Value::True)
} else {
panic!("Expression not starting with And!");
}
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-1kmz8zr/solution)
warning: field `arr_parsers` is never read
   --> src/lib.rs:165:5
    |
164 | pub struct ExprParser {
    |            ---------- field in this struct
165 |     arr_parsers: Vec<SimpleExprParser>,
    |     ^^^^^^^^^^^
    |
    = note: `#[warn(dead_code)]` on by default

warning: `solution` (lib) generated 1 warning
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.75s
     Running tests/solution_test.rs (target/debug/deps/solution_test-1428e1090729d165)

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

failures:

---- solution_test::test_eval_full stdout ----
thread '<unnamed>' panicked at 'Expression not starting with And!', src/lib.rs:333:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
thread 'solution_test::test_eval_full' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:371:5

---- solution_test::test_eval_not_and_or stdout ----
thread '<unnamed>' panicked at 'Expression not starting with And!', src/lib.rs:333:9
thread 'solution_test::test_eval_not_and_or' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:387:5

---- solution_test::test_eval_partial stdout ----
thread '<unnamed>' panicked at 'Expression not starting with And!', src/lib.rs:333:9
thread 'solution_test::test_eval_partial' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:409:5

---- solution_test::test_eval_unwrap_and_or stdout ----
thread '<unnamed>' panicked at 'Expression not starting with And!', src/lib.rs:333:9
thread 'solution_test::test_eval_unwrap_and_or' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:456:5

---- solution_test::test_eval_unwrap_nested stdout ----
thread '<unnamed>' panicked at 'Expression not starting with And!', src/lib.rs:333:9
thread 'solution_test::test_eval_unwrap_nested' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:479:5

---- solution_test::test_paren_around_expr stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([And([Atom('A')])])`,
 right: `Atom('A')`', tests/solution_test.rs:179:9
thread 'solution_test::test_paren_around_expr' panicked at 'assertion failed: `(left == right)`
  left: `And([And([Atom('A')])])`,
 right: `Atom('A')`', tests/solution_test.rs:176:5

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

---- solution_test::test_paren_nested stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Not(And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))]))])`,
 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: `And([Not(And([Atom('A'), Not(And([Atom('B'), Not(And([Atom('C'), Atom('D')]))]))]))])`,
 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_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('X'), Not(And([Atom('A'), Or([Atom('B')])]))])`,
 right: `And([Atom('X'), Not(Or([Atom('A'), Atom('B')]))])`', tests/solution_test.rs:219:9
thread 'solution_test::test_paren_not' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('X'), Not(And([Atom('A'), Or([Atom('B')])]))])`,
 right: `And([Atom('X'), Not(Or([Atom('A'), Atom('B')]))])`', tests/solution_test.rs:216:5

---- solution_test::test_paren_surrounded stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('X'), Or([And([Atom('A'), Atom('B')]), 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: `And([Atom('X'), Or([And([Atom('A'), Atom('B')]), 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_and_or stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A'), Or([Atom('B')])])`,
 right: `Or([Atom('A'), Atom('B')])`', tests/solution_test.rs:92:9
thread 'solution_test::test_parser_and_or' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A'), Or([Atom('B')])])`,
 right: `Or([Atom('A'), Atom('B')])`', tests/solution_test.rs:84:5

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

---- solution_test::test_parser_atom stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A')])`,
 right: `Atom('A')`', tests/solution_test.rs:78:9
thread 'solution_test::test_parser_atom' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('A')])`,
 right: `Atom('A')`', tests/solution_test.rs:74:5

---- solution_test::test_parser_errors_basic stdout ----
Consecutive binary operators detected
Consecutive binary operators detected
Consecutive atoms detected
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.push_op(\'!\'), Err(_))', tests/solution_test.rs:278:9
thread 'solution_test::test_parser_errors_basic' panicked at 'called `Option::unwrap()` on a `None` value', tests/solution_test.rs:265:5

---- solution_test::test_parser_expr_and_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Not(Atom('A')), Or([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: `And([Not(Atom('A')), Or([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('X'), Or([Atom('Y'), Atom('Z'), Atom('W')])])`,
 right: `Or([Atom('X'), Atom('Y'), Atom('Z'), Atom('W')])`', tests/solution_test.rs:131:9
thread 'solution_test::test_parser_multiple_atoms_same_op' panicked at 'assertion failed: `(left == right)`
  left: `And([Atom('X'), Or([Atom('Y'), Atom('Z'), Atom('W')])])`,
 right: `Or([Atom('X'), Atom('Y'), Atom('Z'), Atom('W')])`', tests/solution_test.rs:124:5

---- solution_test::test_parser_multiple_not stdout ----
Consecutive unary operators detected
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:142:42
thread 'solution_test::test_parser_multiple_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedUnaryOp', tests/solution_test.rs:140:5

---- solution_test::test_parser_not stdout ----
thread '<unnamed>' panicked at 'assertion failed: `(left == right)`
  left: `And([Not(Atom('B'))])`,
 right: `Not(Atom('B'))`', tests/solution_test.rs:101:9
thread 'solution_test::test_parser_not' panicked at 'assertion failed: `(left == right)`
  left: `And([Not(Atom('B'))])`,
 right: `Not(Atom('B'))`', tests/solution_test.rs:98:5


failures:
    solution_test::test_eval_full
    solution_test::test_eval_not_and_or
    solution_test::test_eval_partial
    solution_test::test_eval_unwrap_and_or
    solution_test::test_eval_unwrap_nested
    solution_test::test_paren_around_expr
    solution_test::test_paren_expr_priority
    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_and_or
    solution_test::test_parser_atom
    solution_test::test_parser_errors_basic
    solution_test::test_parser_expr_and_not
    solution_test::test_parser_multiple_atoms_same_op
    solution_test::test_parser_multiple_not
    solution_test::test_parser_not

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

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

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

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

Имаш някакъв фундаментален пропуск в решението и не изкарваш почти никакви точки. Препоръчвам да си напишеш тестове, защото тази задача е много трудно да се реши без тях. Погледни си решението отново и тествай стъпка по стъпка.