rust implement a crate for encode and decode brainfuck and ook

Pub Date: 2023-07-28

#![allow(unused)]
fn main() {
mod utils;
#[allow(warnings)]
pub mod Ook {
    use std::collections::HashMap;
    pub trait Join {
        fn join(&self, by: &str) -> String;
    }

    impl<T: ToString> Join for [T] {
        fn join(&self, by: &str) -> String {
            self.iter()
                .map(|item| item.to_string())
                .collect::<Vec<String>>()
                .join(by)
        }
    }

    /// # text to brainfuck
    pub fn text_to_brainfuck(text: impl AsRef<str>) -> String {
        let mut value: isize = 0;
        let mut result = String::new();

        for c in text.as_ref().chars() {
            let diff = c as isize - value;
            value = c as isize;

            if diff == 0 {
                result.push_str(">.");
                continue;
            }

            if diff.abs() < 10 {
                if diff > 0 {
                    result.push('>');
                    result.push_str(&"+".repeat(diff as usize));
                } else if diff < 0 {
                    result.push('>');
                    result.push_str(&"-".repeat(diff.abs() as usize));
                }
            } else {
                let loop_count = (diff.abs() as f64).sqrt() as usize;
                result.push_str(&"+".repeat(loop_count));

                if diff > 0 {
                    result.push_str(&"[->".to_owned());
                    result.push_str(&"+".repeat(loop_count));
                    result.push_str("<]");
                    result.push('>');
                    result.push_str(&"+".repeat(diff as usize - loop_count.pow(2)));
                } else if diff < 0 {
                    result.push_str(&"[->".to_owned());
                    result.push_str(&"-".repeat(loop_count));
                    result.push_str("<]");
                    result.push('>');
                    result.push_str(&"-".repeat(diff.abs() as usize - loop_count.pow(2)));
                }
            }

            result.push_str(".<");
        }
        result.replace("<>", "")
    }

    ///# decode brainfuck to text
    pub fn brainfuck_to_text(encoded: impl AsRef<str>) -> String {
        let mut decoded = String::new();
        let mut data = vec![0u8; 30000];
        let mut data_index = 0;
        let mut loop_stack = Vec::new();
        let encoded_chars: Vec<char> = encoded.as_ref().chars().collect();

        let mut index = 0;
        while index < encoded_chars.len() {
            match encoded_chars[index] {
                '+' => {
                    data[data_index] = data[data_index].wrapping_add(1);
                }
                '-' => {
                    data[data_index] = data[data_index].wrapping_sub(1);
                }
                '>' => {
                    data_index += 1;
                }
                '<' => {
                    if data_index > 0 {
                        data_index -= 1;
                    }
                }
                '.' => {
                    decoded.push(data[data_index] as char);
                }
                ',' => {
                    // Input operation is not supported in decoding mode.
                    // You can add your own logic here if needed.
                }
                '[' => {
                    if data[data_index] == 0 {
                        // Skip the loop (jump to corresponding ']')
                        let mut brackets = 1;
                        while brackets > 0 && index < encoded_chars.len() {
                            index += 1;
                            if encoded_chars[index] == '[' {
                                brackets += 1;
                            } else if encoded_chars[index] == ']' {
                                brackets -= 1;
                            }
                        }
                    } else {
                        loop_stack.push(index);
                    }
                }
                ']' => {
                    if data[data_index] != 0 {
                        // Jump back to the loop start ('[')
                        if let Some(&start) = loop_stack.last() {
                            index = start - 1; // Subtract 1 since 'index' will be incremented again
                        }
                    } else {
                        loop_stack.pop();
                    }
                }
                _ => {} // Ignore other characters
            }

            index += 1;
        }

        decoded
    }

    /// # translate brainfuck to ook
    pub fn brainfuck_to_ook(output: impl AsRef<str>) -> String {
        output.as_ref()
            .chars()
            .map(|ch| match ch {
                '>' => "Ook. Ook? ",
                '<' => "Ook? Ook. ",
                '+' => "Ook. Ook. ",
                '-' => "Ook! Ook! ",
                '.' => "Ook! Ook. ",
                ',' => "Ook. Ook! ",
                '[' => "Ook! Ook? ",
                ']' => "Ook? Ook! ",
                _ => "",
            })
            .collect()
    }
     /// # translate ook to brainfuck
     pub fn ook_to_text(input: impl AsRef<str>) -> String {
        let input = input.as_ref().replace("Ook", "").replace(" ", "");
        let mut output = "".to_string();
        let lookup: HashMap<&str, &str> = [
            (".?", ">"),
            ("?.", "<"),
            ("..", "+"),
            ("!!", "-"),
            ("!.", "."),
            (".!", ","),
            ("!?", "["),
            ("?!", "]"),
        ].iter().cloned().collect();
        let len = input.len();
        for i in (0..len).step_by(2) {
            let key = &input[i..i+2];
            output.push_str(lookup.get(key).unwrap_or(&""));
        }
        brainfuck_to_text(&output)
    }
    /// # text to ook
    pub fn text_to_ook(text: impl AsRef<str>) -> String {
        brainfuck_to_ook(&text_to_brainfuck(&text.as_ref())).to_string()
    }
    /// # text to shourt ook
    pub fn text_to_short_ook(text:  impl AsRef<str>) -> String {
        brainfuck_to_ook(&text_to_brainfuck(&text.as_ref()))
            .to_string()
            .replace(" ", "")
            .replace("Ook", "")
    }
}

}