Demo entry 6682742

XCH

   

Submitted by anonymous on Dec 10, 2017 at 09:41
Language: Rust. Code size: 11.2 kB.

/*
Copyright 2017 LEXUGE

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

use std::string::String;
use std::io;
use std::vec::Vec;
use std::i32;

struct ElementStruct {
    name: String,
    num: usize,
}

struct ChemicalFormula {
    left_num: i32,
    right_num: i32,
    sum: i32, //sum of the left_num and the right_num
}

fn main() {
    print_about_info();
    let (equation, searching_range) = input();
    let mut traversal: Vec<i32> = Vec::new();
    let (chemical_formula_struct, elements_table, list) = xch_parser(equation);
    if xch_try(
        1,
        searching_range,
        &mut traversal,
        &list,
        &chemical_formula_struct,
        elements_table.len()
    ) == false {
        println!("NO ANS!");
        println!("Parser Results:");
        for i in 1..elements_table.len()+1 {
            for j in 1..chemical_formula_struct.sum as usize+1 {
                print!("{} ", list[i][j]);
            }
            println!(" ");
        }
    }
}

//other functions
fn xch_try(
    f: i32,
    searching_range: i32,
    traversal: &mut Vec<i32>,
    list: &[[i32; 101]; 101],
    chmcl_f_sut: &ChemicalFormula,
    len: usize
) -> bool {
    if f == chmcl_f_sut.sum + 1 {
        if check(traversal, list, chmcl_f_sut, len) == true {
            print_ans(traversal);
            return true;
        }
    } else {
        for i in 1..searching_range + 1 {
            traversal.push(i);
            if xch_try(f+1, searching_range, traversal, list, chmcl_f_sut, len) == true {
                return true;
            }
            traversal.pop();
        }
    }
    false
}

fn print_ans(traversal: &mut Vec<i32>) {
    println!("[OUTPUT]:");
    for i in traversal {
        print!("{} ", i);
    }
    println!(" ");
}

fn check(
    traversal: &mut Vec<i32>,
    list: &[[i32;101];101],
    chmcl_f_sut: &ChemicalFormula,
    len: usize
) -> bool {
    let mut tmp1: i32;
    let mut tmp2: i32;
    for i in 1..len+1 {
        tmp1 = 0;
        tmp2 = 0;
        for j in 1..chmcl_f_sut.left_num as usize+1 {
            let tmp: i32;
            tmp = list[i][j].checked_mul(traversal[j-1]).expect("[ERROR] i32 overflow");
            tmp1 = tmp1.checked_add(tmp).expect("[ERROR] i32 overflow");
        }
        for j in chmcl_f_sut.left_num as usize+1..chmcl_f_sut.sum as usize+1 {
            let tmp: i32;
            tmp = list[i][j].checked_mul(traversal[j-1]).expect("[ERROR] i32 overflow");
            tmp2 = tmp2.checked_add(tmp).expect("[ERROR] i32 overflow");
        }
        if tmp1 != tmp2 {
            return false;
        }
    }
    true
}

fn print_about_info() {
    println!("XCH - Chemical Equation Balancer");
    println!("<> by LEXUGE <LEXUGEyky@outlook.com>");
    println!("Copyright (C) 2017 LEXUGE");
    println!("License GPL-3.0+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>");
}

fn input() -> (String, i32) {
    println!("[INPUT] Input the equation:");
    let mut equation = String::new();
    io::stdin().read_line(&mut equation)
            .expect("[ERROR] Failed to read line!");
    println!("[INPUT] Input the searching range:");
    let mut searching_range = String::new();
    io::stdin().read_line(&mut searching_range)
            .expect("[ERROR] Failed to read line!");
    let searching_range: i32 = match searching_range.trim().parse::<i32>() {
        Ok(num) => num,
        Err(_) => panic!("[ERROR] Not a number!"),
    };
    equation.pop();
    (equation, searching_range)
}

fn xch_parser(equation: String) -> (ChemicalFormula, Vec<ElementStruct>, [[i32;101];101]){
    legal_check(&equation);
    let mut chemical_formula_struct = ChemicalFormula {
        left_num: 0,
        right_num: 0,
        sum: 0,
    };
    let mut elements_table: Vec<ElementStruct> = Vec::new(); //store the index of elements
    let mut list = [[0 as i32;101];101];
    //Unicode slice safe

    //block to call parsers
    {
        let equation_left = equation[..equation.find('=').unwrap()]
            .to_string();
        let equation_right = equation[equation.find('=').unwrap()+1..]
            .to_string();
        // println!("{} {}", equation_left,equation_right);
        chemical_formula_struct.left_num = part_parser(
            equation_left.clone(),
            &mut elements_table,
            &mut list,
            0
        );
        chemical_formula_struct.right_num = part_parser(
            equation_right.clone(),
            &mut elements_table,
            &mut list,
            chemical_formula_struct.left_num
        );
    }
    chemical_formula_struct.sum = chemical_formula_struct.left_num
        + chemical_formula_struct.right_num;
    //return
    (chemical_formula_struct, elements_table, list)
}

fn part_parser(
    eqn: String,
    elements_table: &mut Vec<ElementStruct>,
    list: &mut [[i32;101];101],
    begin: i32
) -> i32 {
    let mut sum = begin;
    for formula in eqn.split("+") {
        sum = sum+1;
        legal_check_brackets(&formula.to_string());
        parser_formula(&formula.to_string(), elements_table, 1, sum as usize, list);
    }
    sum-begin
}

fn parser_formula(
    formula: &String,
    elements_table: &mut Vec<ElementStruct>,
    times: i32,
    location: usize,
    list: &mut [[i32;101];101]
) {
    let formula_backup = formula;
    let mut formula = formula.chars().into_iter().collect::<Vec<_>>();
    let mut element_name = String::new();
    let mut element_num_string = String::new();
    let mut element_num:i32 = 1;
    let mut i: usize = 0;

    formula.push('!');
    while i<=formula.len()-1 {
        if (check_char(formula[i]) == 2) || (check_char(formula[i]) == 4) || (formula[i] == '!') {
            if !element_name.is_empty() {
                if !element_num_string.is_empty() {
                    element_num = match element_num_string.trim().parse::<i32>() {
                        Ok(num) => num,
                        Err(_) => panic!("[ERROR] Not a number!"),
                    };
                }

                if find_element_in_table(&element_name, elements_table).is_ok() == false {
                    let len = elements_table.len();
                    elements_table.push(
                        ElementStruct {
                            name: element_name.clone(),
                            num: len+1, //WARN: the elements_table[0].num will be 1
                        }
                    );
                }

                {
                    //store data in table
                    let tmp = find_element_in_table(&element_name, elements_table).unwrap();
                    list[tmp][location] = list[tmp][location]
                        + element_num.checked_mul(times).expect("[ERROR] i32 overflow");
                }
            }
            //clean job
            element_num = 1;
            element_num_string.clear();
            element_name.clear();
        }

        if (check_char(formula[i]) == 1) || (check_char(formula[i]) == 2) {
            element_name.push(formula[i]);
        }

        if check_char(formula[i]) == 3 {
            element_num_string.push(formula[i]);
        }

        if formula[i] == '(' {
            let mut j = brackets_matcher(&formula, i, true).unwrap()+1;
            while check_char(formula[j]) == 3 {
                element_num_string.push(formula[j]);
                j = j+1;
            }
            if !element_num_string.is_empty() {
                element_num = match element_num_string.trim().parse::<i32>() {
                    Ok(num) => num,
                    Err(_) => panic!("[ERROR] Not a number!"),
                };
            }
            parser_formula(
                &formula_backup[i+1..brackets_matcher(&formula, i, true).unwrap()+1].to_string(),
                elements_table,
                times.checked_mul(element_num).expect("[ERROR] i32 overflow"),
                location,
                list
            );
            i = j-1;
            //clean job
            element_num = 1;
            element_num_string.clear();
            element_name.clear();
        }
        i = i+1;
    }
}

fn brackets_matcher(eqn: &Vec<char>, pos: usize, mode: bool) -> Result<usize, String> {
    let mut fake_stack = 0;

    if mode == true {
        for i in pos+1..eqn.len() {
            if eqn[i] == '(' {
                fake_stack = fake_stack+1;
            }
            if eqn[i] == ')' {
                if fake_stack == 0 {
                    let x: Result<usize, String> =Ok(i);
                    return x;
                } else {
                    fake_stack = fake_stack-1;
                }
            }
        }
    } else {
        for i in (0..pos).rev() {
            if eqn[i] == ')' {
                fake_stack = fake_stack+1;
            }
            if eqn[i] == '(' {
                if fake_stack == 0 {
                    let x: Result<usize, String> =Ok(i);
                    return x;
                } else {
                    fake_stack = fake_stack-1;
                }
            }
        }
    }
    let x: Result<usize, String> = Err("[ERROR] Can't match!".to_string());
    x
}

fn find_element_in_table(target: &String, e_t: &mut Vec<ElementStruct>) -> Result<usize, String> {
    for i in e_t.into_iter() {
        if i.name == *target {
            let x: Result<usize, String> = Ok(i.num);
            return x;
        }
    }
    let x: Result<usize, String> = Err("[ERROR] Not found!".to_string());
    x
}

fn check_char(test: char) -> i32 {
    if (test>='a')&&(test<='z') {
        return 1; //'a'~'z'
    } else if (test>='A')&&(test<='Z') {
        return 2; //'A'~'Z'
    } else if (test>='0')&&(test<='9') {
        return 3; //'0'~'9'
    } else if (test=='(')||(test<=')') {
        return 4; //( or )
    } else if (test=='+')||(test=='=') {
        return 5; //+ or =
    } else {
        return 0; //nothing!
    }
}

fn legal_check(eqn: &String) {
    let eqn = eqn.chars().into_iter().collect::<Vec<_>>();
    let mut tmp = 0;
    for i in eqn {
        if check_char(i) == 0 {
            panic!("[ERROR] Illegal Equation!");
        }
        if i == '=' {
            tmp = tmp+1;
        }
    }
    if tmp != 1 {
        panic!("[ERROR] Illegal Equation!");
    }
}

fn legal_check_brackets(eqn: &String) {
    let eqn = eqn.chars().into_iter().collect::<Vec<_>>();
    for i in 0..eqn.len() {
        if eqn[i] == '(' {
            brackets_matcher(&eqn, i, true).expect("[ERROR] Illegal Equation!");
        }
        if eqn[i] == ')' {
            brackets_matcher(&eqn, i, false).expect("[ERROR] Illegal Equation!");
        }
    }
}

This snippet took 0.02 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).