Решение на Логически изрази от Станислав Иванов

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

Към профила на Станислав Иванов

Резултати

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

Код

#[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 {
operands: Vec<Expr>,
operators: Vec<char>,
}
impl SimpleExprParser {
pub fn new() -> Self {
Self {
operands: Vec::new(),
operators: Vec::new(),
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.operators.iter().filter(|&&op| op != '!').count() != self.operands.len() {
return Err(ParseError::UnexpectedExpr);
}
let mut expr = Expr::Atom(c);
while self.operators.last() == Some(&'!') {
expr = Expr::Not(Box::new(expr));
self.operators.pop();
}
self.operands.push(expr);
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'!' => {
if self.operators.iter().filter(|&&op| op != '!').count() != self.operands.len() {
return Err(ParseError::UnexpectedUnaryOp);
}
self.operators.push(op);
}
'&' | '|' => {
if self.operators.iter().filter(|&&op| op != '!').count() == self.operands.len() {
return Err(ParseError::UnexpectedBinOp);
}
self.operators.push(op)
}
_ => panic!("Invalid operator!"),
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
let mut operands = self.operands.iter();
let mut expr = operands.next().ok_or(ParseError::UnexpectedEnd)?.clone();
for op in self.operators {
match op {
'&' => {
let operand = operands.next().ok_or(ParseError::UnexpectedEnd)?.clone();
match expr {
Expr::And(ref mut vec) => vec.push(operand),
_ => expr = Expr::And(vec![expr, operand]),
}
}
'|' => {
let operand = operands.next().ok_or(ParseError::UnexpectedEnd)?.clone();
match expr {
Expr::Or(ref mut vec) => vec.push(operand),
_ => expr = Expr::Or(vec![expr, operand]),
}
}
_ => return Err(ParseError::UnexpectedBinOp),
}
}
Ok(expr)
}
}
/// Парсър за пълния израз
pub struct ExprParser {
parsers: Vec<SimpleExprParser>,
}
impl ExprParser {
pub fn new() -> Self {
Self {
parsers: vec![SimpleExprParser::new()],
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
self.parsers
.last_mut()
.ok_or(ParseError::UnexpectedEnd)?
.push_atom(c)
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
self.parsers
.last_mut()
.ok_or(ParseError::UnexpectedEnd)?
.push_op(op)
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
let parser = self.parsers.last().ok_or(ParseError::UnexpectedEnd)?;
if parser.operators.iter().filter(|&&op| op != '!').count() != parser.operands.len() {
return Err(ParseError::UnexpectedParen);
}
self.parsers.push(SimpleExprParser::new());
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
impl SimpleExprParser {
fn push_expr(&mut self, expr: Expr) -> Result<(), ParseError> {
let mut expr = expr;
while self.operators.last() == Some(&'!') {
expr = Expr::Not(Box::new(expr));
self.operators.pop();
}
self.operands.push(expr);
Ok(())
}
fn clone(&self) -> Self {
Self {
operands: self.operands.clone(),
operators: self.operators.clone(),
}
}
}
let parser = self.parsers.last().ok_or(ParseError::UnexpectedParen)?;
let expr = parser
.clone()
.finish()
.map_err(|_| ParseError::UnexpectedParen)?;
let result = self
.parsers
.last_mut()
.ok_or(ParseError::UnexpectedParen)?
.push_expr(expr);
self.parsers.pop();
result
}
pub fn finish(self) -> Result<Expr, ParseError> {
if self.parsers.len() != 1 {
return Err(ParseError::UnexpectedEnd);
}
self.parsers.into_iter().next().unwrap().finish()
}
}
#[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(char) if truthy.contains(char) => Value::True,
Expr::Atom(char) if falsy.contains(char) => Value::False,
Expr::Not(expr) => match eval(expr, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(Expr::Not(expr)) => Value::Expr(*expr),
Value::Expr(expr) => Value::Expr(Expr::Not(Box::new(expr))),
},
Expr::And(exprs) => {
let mut new_exprs = Vec::new();
for expr in exprs {
match eval(expr, truthy, falsy) {
Value::False => return Value::False,
Value::Expr(Expr::And(vec)) => new_exprs.extend(vec),
Value::Expr(expr) => new_exprs.push(expr),
_ => {}
}
}
match new_exprs.len() {
0 => Value::True,
1 => Value::Expr(new_exprs.pop().unwrap()),
_ => Value::Expr(Expr::And(new_exprs)),
}
}
Expr::Or(exprs) => {
let mut new_exprs = Vec::new();
for expr in exprs {
match eval(expr, truthy, falsy) {
Value::True => return Value::True,
Value::Expr(Expr::Or(vec)) => new_exprs.extend(vec),
Value::Expr(expr) => new_exprs.push(expr),
_ => {}
}
}
match new_exprs.len() {
0 => Value::False,
1 => Value::Expr(new_exprs.pop().unwrap()),
_ => Value::Expr(Expr::Or(new_exprs)),
}
}
_ => Value::Expr(expr.clone()),
}
}

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

Compiling solution v0.1.0 (/tmp/d20241224-258381-10c7sn6/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.88s
     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 ... FAILED
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 ... ok
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_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_multiple_not ... ok
test solution_test::test_parser_not ... ok

failures:

---- solution_test::test_error_paren_mismatched stdout ----
thread '<unnamed>' panicked at 'assertion failed: matches!(parser.open_paren(), Err(_))', tests/solution_test.rs:362: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_paren_around_expr stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:179:36
thread 'solution_test::test_paren_around_expr' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:176:5

---- solution_test::test_paren_expr_priority stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:201:29
thread 'solution_test::test_paren_expr_priority' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:197:5

---- solution_test::test_paren_nested stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedParen', tests/solution_test.rs:254:58
thread 'solution_test::test_paren_nested' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedParen', tests/solution_test.rs:252:5

---- solution_test::test_paren_not stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:220:29
thread 'solution_test::test_paren_not' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedEnd', tests/solution_test.rs:216:5

---- solution_test::test_paren_surrounded stdout ----
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedBinOp', tests/solution_test.rs:237:61
thread 'solution_test::test_paren_surrounded' panicked at 'called `Result::unwrap()` on an `Err` value: UnexpectedBinOp', tests/solution_test.rs:235:5


failures:
    solution_test::test_error_paren_mismatched
    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

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

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

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

Станислав качи първо решение на 20.12.2024 18:33 (преди 9 месеца)

Станислав качи решение на 22.12.2024 00:15 (преди 9 месеца)

#[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 {
operands: Vec<Expr>,
operators: Vec<char>,
}
impl SimpleExprParser {
pub fn new() -> Self {
Self {
operands: Vec::new(),
operators: Vec::new(),
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
if self.operators.iter().filter(|&&op| op != '!').count() != self.operands.len() {
return Err(ParseError::UnexpectedExpr);
}
let mut expr = Expr::Atom(c);
while self.operators.last() == Some(&'!') {
expr = Expr::Not(Box::new(expr));
self.operators.pop();
}
self.operands.push(expr);
Ok(())
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
match op {
'!' => {
if self.operators.iter().filter(|&&op| op != '!').count() != self.operands.len() {
return Err(ParseError::UnexpectedUnaryOp);
}
self.operators.push(op);
}
'&' | '|' => {
if self.operators.iter().filter(|&&op| op != '!').count() == self.operands.len() {
return Err(ParseError::UnexpectedBinOp);
}
self.operators.push(op)
}
_ => panic!("Invalid operator!"),
}
Ok(())
}
pub fn finish(self) -> Result<Expr, ParseError> {
let mut operands = self.operands.iter();
let mut expr = operands.next().ok_or(ParseError::UnexpectedEnd)?.clone();
for op in self.operators {
match op {
'&' => {
let operand = operands.next().ok_or(ParseError::UnexpectedEnd)?.clone();
match expr {
Expr::And(ref mut vec) => vec.push(operand),
_ => expr = Expr::And(vec![expr, operand]),
}
}
'|' => {
let operand = operands.next().ok_or(ParseError::UnexpectedEnd)?.clone();
match expr {
Expr::Or(ref mut vec) => vec.push(operand),
_ => expr = Expr::Or(vec![expr, operand]),
}
}
_ => return Err(ParseError::UnexpectedBinOp),
}
}
Ok(expr)
}
}
/// Парсър за пълния израз
pub struct ExprParser {
parsers: Vec<SimpleExprParser>,
}
impl ExprParser {
pub fn new() -> Self {
Self {
parsers: vec![SimpleExprParser::new()],
}
}
pub fn push_atom(&mut self, c: char) -> Result<(), ParseError> {
self.parsers
.last_mut()
.ok_or(ParseError::UnexpectedEnd)?
.push_atom(c)
}
pub fn push_op(&mut self, op: char) -> Result<(), ParseError> {
self.parsers
.last_mut()
.ok_or(ParseError::UnexpectedEnd)?
.push_op(op)
}
pub fn open_paren(&mut self) -> Result<(), ParseError> {
let parser = self.parsers.last().ok_or(ParseError::UnexpectedEnd)?;
if parser.operators.iter().filter(|&&op| op != '!').count() != parser.operands.len() {
return Err(ParseError::UnexpectedParen);
}
self.parsers.push(SimpleExprParser::new());
Ok(())
}
pub fn close_paren(&mut self) -> Result<(), ParseError> {
impl SimpleExprParser {
fn push_expr(&mut self, expr: Expr) -> Result<(), ParseError> {
let mut expr = expr;
while self.operators.last() == Some(&'!') {
expr = Expr::Not(Box::new(expr));
self.operators.pop();
}
self.operands.push(expr);
Ok(())
}
+
+ fn clone(&self) -> Self {
+ Self {
+ operands: self.operands.clone(),
+ operators: self.operators.clone(),
+ }
+ }
}
- let expr = self
- .parsers
- .pop()
- .ok_or(ParseError::UnexpectedParen)?
+
+ let parser = self.parsers.last().ok_or(ParseError::UnexpectedParen)?;
+ let expr = parser
+ .clone()
.finish()
.map_err(|_| ParseError::UnexpectedParen)?;
- self.parsers
+ let result = self
+ .parsers
.last_mut()
- .ok_or(ParseError::UnexpectedEnd)?
- .push_expr(expr)
+ .ok_or(ParseError::UnexpectedParen)?
+ .push_expr(expr);
+
+ self.parsers.pop();
+ result
}
pub fn finish(self) -> Result<Expr, ParseError> {
if self.parsers.len() != 1 {
return Err(ParseError::UnexpectedEnd);
}
self.parsers.into_iter().next().unwrap().finish()
}
}
#[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(char) if truthy.contains(char) => Value::True,
Expr::Atom(char) if falsy.contains(char) => Value::False,
Expr::Not(expr) => match eval(expr, truthy, falsy) {
Value::True => Value::False,
Value::False => Value::True,
Value::Expr(Expr::Not(expr)) => Value::Expr(*expr),
Value::Expr(expr) => Value::Expr(Expr::Not(Box::new(expr))),
},
Expr::And(exprs) => {
let mut new_exprs = Vec::new();
for expr in exprs {
match eval(expr, truthy, falsy) {
Value::False => return Value::False,
Value::Expr(Expr::And(vec)) => new_exprs.extend(vec),
Value::Expr(expr) => new_exprs.push(expr),
_ => {}
}
}
match new_exprs.len() {
0 => Value::True,
1 => Value::Expr(new_exprs.pop().unwrap()),
_ => Value::Expr(Expr::And(new_exprs)),
}
}
Expr::Or(exprs) => {
let mut new_exprs = Vec::new();
for expr in exprs {
match eval(expr, truthy, falsy) {
Value::True => return Value::True,
Value::Expr(Expr::Or(vec)) => new_exprs.extend(vec),
Value::Expr(expr) => new_exprs.push(expr),
_ => {}
}
}
match new_exprs.len() {
0 => Value::False,
1 => Value::Expr(new_exprs.pop().unwrap()),
_ => Value::Expr(Expr::Or(new_exprs)),
}
}
_ => Value::Expr(expr.clone()),
}
}