-
-
Save RandyMcMillan/b8f4213048f57cdcf33a186774a856a4 to your computer and use it in GitHub Desktop.
morse_binary_tree.rs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::rc::Rc; | |
| use std::cell::RefCell; | |
| use std::collections::HashMap; | |
| use anyhow::{anyhow, Result}; | |
| /// A node in our Morse Virtual Circuit binary tree. | |
| #[derive(Debug, Default)] | |
| struct Node { | |
| value: Option<char>, | |
| dot: Option<Rc<RefCell<Node>>>, | |
| dash: Option<Rc<RefCell<Node>>>, | |
| } | |
| struct MorseCircuit { | |
| root: Rc<RefCell<Node>>, | |
| encoder_map: HashMap<char, String>, | |
| } | |
| impl MorseCircuit { | |
| pub fn new() -> Self { | |
| let mut circuit = MorseCircuit { | |
| root: Rc::new(RefCell::new(Node::default())), | |
| encoder_map: HashMap::new(), | |
| }; | |
| let dataset = [ | |
| ('A', ".-"), ('B', "-..."), ('C', "-.-."), ('D', "-.."), | |
| ('E', "."), ('F', "..-."), ('G', "--."), ('H', "...."), | |
| ('I', ".."), ('J', ".---"), ('K', "-.-"), ('L', ".-.."), | |
| ('M', "--"), ('N', "-."), ('O', "---"), ('P', ".--."), | |
| ('Q', "--.-"), ('R', ".-."), ('S', "..."), ('T', "-"), | |
| ('U', "..-"), ('V', "...-"), ('W', ".--"), ('X', "-..-"), | |
| ('Y', "-.--"), ('Z', "--.."), | |
| ('1', ".----"), ('2', "..---"), ('3', "...--"), ('4', "....-"), | |
| ('5', "....."), ('6', "-...."), ('7', "--..."), ('8', "---.."), | |
| ('9', "----."), ('0', "-----"), | |
| ('.', ".-.-.-"), (',', "--..--"), ('?', "..--.."), ('/', "-..-."), | |
| ('-', "-....-"), ('(', "-.--."), (')', "-.--.-"), (' ', "/"), | |
| ]; | |
| for (ch, code) in dataset { | |
| circuit.insert(ch, code); | |
| } | |
| circuit | |
| } | |
| fn insert(&mut self, ch: char, code: &str) { | |
| self.encoder_map.insert(ch, code.to_string()); | |
| let mut current = Rc::clone(&self.root); | |
| for signal in code.chars() { | |
| let next = match signal { | |
| '.' => { | |
| let mut node = current.borrow_mut(); | |
| node.dot.get_or_insert_with(|| Rc::new(RefCell::new(Node::default()))).clone() | |
| } | |
| '-' => { | |
| let mut node = current.borrow_mut(); | |
| node.dash.get_or_insert_with(|| Rc::new(RefCell::new(Node::default()))).clone() | |
| } | |
| _ => continue, | |
| }; | |
| current = next; | |
| } | |
| current.borrow_mut().value = Some(ch); | |
| } | |
| /// Encodes text, returning an error if a character is not supported. | |
| pub fn encode(&self, text: &str) -> Result<String> { | |
| let mut results = Vec::new(); | |
| for ch in text.to_uppercase().chars() { | |
| let code = self.encoder_map.get(&ch) | |
| .ok_or_else(|| anyhow!("Character '{}' is not supported by the circuit", ch))?; | |
| results.push(code.clone()); | |
| } | |
| Ok(results.join(" ")) | |
| } | |
| /// Decodes signals, returning an error if a sequence leads to a dead end. | |
| pub fn decode(&self, morse: &str) -> Result<String> { | |
| let mut decoded_text = String::new(); | |
| for code in morse.split_whitespace() { | |
| if code == "/" { | |
| decoded_text.push(' '); | |
| continue; | |
| } | |
| let mut current = Rc::clone(&self.root); | |
| for signal in code.chars() { | |
| let next = match signal { | |
| '.' => current.borrow().dot.as_ref().map(Rc::clone), | |
| '-' => current.borrow().dash.as_ref().map(Rc::clone), | |
| _ => return Err(anyhow!("Invalid signal '{}' in sequence '{}'", signal, code)), | |
| }; | |
| current = next.ok_or_else(|| anyhow!("Signal path '{}' does not exist", code))?; | |
| } | |
| let val = current.borrow().value | |
| .ok_or_else(|| anyhow!("Sequence '{}' is incomplete or has no value", code))?; | |
| decoded_text.push(val); | |
| } | |
| Ok(decoded_text) | |
| } | |
| } | |
| fn main() -> Result<()> { | |
| let circuit = MorseCircuit::new(); | |
| // Successful Run | |
| let encoded = circuit.encode("Rust 2026")?; | |
| println!("Encoded: {}", encoded); | |
| println!("Decoded: {}", circuit.decode(&encoded)?); | |
| // Demonstration of Error Handling | |
| println!("\n--- Error Test ---"); | |
| match circuit.encode("Rust!") { | |
| Ok(_) => println!("Success!"), | |
| Err(e) => println!("Encode Error: {}", e), // Character '!' is not supported | |
| } | |
| match circuit.decode(".......") { | |
| Ok(_) => println!("Success!"), | |
| Err(e) => println!("Decode Error: {}", e), // Signal path '.......' does not exist | |
| } | |
| Ok(()) | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| #[test] | |
| fn test_error_on_invalid_char() { | |
| let circuit = MorseCircuit::new(); | |
| assert!(circuit.encode("#").is_err()); | |
| } | |
| #[test] | |
| fn test_error_on_invalid_sequence() { | |
| let circuit = MorseCircuit::new(); | |
| assert!(circuit.decode("........").is_err()); | |
| } | |
| #[test] | |
| fn test_full_sentence_round_trip() -> Result<()> { | |
| let circuit = MorseCircuit::new(); | |
| let input = "HELLO WORLD 2026"; | |
| let encoded = circuit.encode(input)?; | |
| let decoded = circuit.decode(&encoded)?; | |
| assert_eq!(input, decoded); | |
| Ok(()) | |
| } | |
| } |
Author
RandyMcMillan
commented
Feb 4, 2026

Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment