diff --git a/http/simplify.http b/http/simplify.http index 805a7b0..dea1797 100644 --- a/http/simplify.http +++ b/http/simplify.http @@ -141,3 +141,23 @@ GET {{url}}/table/A client.assert(response.body.truthTable, "Response body does not contain the truth table") }); %} + +### GET table and hide intermediate values + +< {% + import {expression} from "./common"; + + expression("A & B | C") +%} +GET {{url}}/table/{{expression}}?hideIntermediateSteps=true + +> {% + client.test("Response body does not contain intermediate steps", () => { + const header = response.body.truthTable.header; + const matrix = response.body.truthTable.truthMatrix; + client.assert(header.length === 4, "Response body contains intermediate steps") + for (let i = 0; i < matrix.length; i++) { + client.assert(matrix[i].length === 4, "Response body contains intermediate steps") + } + }); +%} diff --git a/src/expressions/truth_table.rs b/src/expressions/truth_table.rs index 646d3ff..6eb1929 100644 --- a/src/expressions/truth_table.rs +++ b/src/expressions/truth_table.rs @@ -37,11 +37,14 @@ pub enum Sort { impl TruthTable { pub fn new(expression: &Expression, options: TruthTableOptions) -> Self { - let header = Self::extract_header(expression); + let mut header = Self::extract_header(expression); let mut truth_matrix = Self::generate_truth_matrix(expression, &header, options.hide, options.hide_intermediate_steps); if !matches!(options.sort, Sort::Default) { Self::sort_matrix(&mut truth_matrix, options.sort); } + if options.hide_intermediate_steps { + header = Self::remove_non_atomic_from_header(&header); + } Self { header, truth_matrix } } @@ -53,6 +56,23 @@ impl TruthTable { }) } + fn remove_non_atomic_from_header(header: &[String]) -> Vec { + header.iter() + .enumerate() + .filter_map(|(index, s)| { + if !Self::contains_operator(s) || index == header.len() - 1 { + Some(s.clone()) + } else { + None + } + }) + .collect() + } + + fn contains_operator(slice: &str) -> bool { + slice.contains('⋀') || slice.contains('⋁') || slice.contains('➔') + } + /// Extracts the header for the truth table from the expression /// Duplicate values are removed. /// - Arguments @@ -116,9 +136,13 @@ impl TruthTable { } fn resolve_expression(expression: &Expression, booleans: &HashMap, header: &[String], hide_intermediate: bool) -> Vec { + let Some(last_expression) = header.last() else { + return vec![]; + }; + let mut expression_map = Self::_resolve_expression(expression, booleans); if hide_intermediate { - expression_map = Self::remove_intermediate_steps(expression_map); + expression_map = Self::remove_intermediate_steps(expression_map, last_expression); } let string_map = expression_map.iter() .map(|(key, value)| (key.to_string(), *value)) @@ -129,11 +153,10 @@ impl TruthTable { .collect() } - fn remove_intermediate_steps(expression_map: HashMap<&Expression, bool>) -> HashMap<&Expression, bool> { + fn remove_intermediate_steps<'a>(expression_map: HashMap<&'a Expression, bool>, top_level_expression: &'a str) -> HashMap<&'a Expression, bool> { expression_map.iter() - .enumerate() - .filter_map(|(index, (key, value))| { - if key.is_atomic() || index == expression_map.len() - 1 { + .filter_map(|(key, value)| { + if key.is_atomic() || key.to_string() == top_level_expression { Some((*key, *value)) } else { None @@ -217,6 +240,19 @@ mod tests { assert_eq!(truth_table.truth_matrix[7], vec![false, false, false, false, false, false]); } + #[test] + fn test_new_truth_table_and_hide_intermediate_steps() { + let expression = and(atomic("A"), or(atomic("B"), atomic("C"))); + let truth_table = TruthTable::new(&expression, TruthTableOptions { + hide_intermediate_steps: true, + ..Default::default() + }); + assert_eq!(truth_table.header, vec!["A", "B", "C", "A ⋀ (B ⋁ C)"]); + for (index, row) in truth_table.truth_matrix.iter().enumerate() { + assert_eq!(row.len(), 4, "Row at {index}: {:?}", row); + } + } + #[test] fn test_sort_matrix_true_first() { let mut matrix = matrix![ diff --git a/src/routing/options.rs b/src/routing/options.rs index d068cdb..064e6eb 100644 --- a/src/routing/options.rs +++ b/src/routing/options.rs @@ -20,8 +20,8 @@ pub struct TruthTableOptions { pub sort: Sort, #[serde(default)] pub hide: Hide, - #[serde(default)] - pub hide_intermediate_steps: bool, // TODO: Implement hide intermediate steps + #[serde(default, deserialize_with = "deserialize_bool")] + pub hide_intermediate_steps: bool, } #[derive(Deserialize)]