<commit_before>extern crate log_domain;
#[macro_use]
extern crate rustomata;

use log_domain::LogDomain;
use std::fs::File;
use std::io::Read;
use std::rc::Rc;

use rustomata::approximation::ApproximationStrategy;
use rustomata::approximation::equivalence_classes::EquivalenceRelation;
use rustomata::approximation::relabel::RlbElement;
use rustomata::approximation::tts::TTSElement;
use rustomata::pmcfg::*;
use rustomata::pmcfg::negra::to_negra;
use rustomata::recognisable::*;
use rustomata::recognisable::coarse_to_fine::CoarseToFineRecogniser;
use rustomata::tree_stack_automaton::*;

fn pmcfg_from_file(grammar_file_path: &str) -> PMCFG<String, String, LogDomain<f64>>
{
    let mut grammar_file = File::open(grammar_file_path).unwrap();
    let mut grammar_string = String::new();
    let _ = grammar_file.read_to_string(&mut grammar_string);
    grammar_string.parse().unwrap()
}

#[test]
fn test_example_pmcfg_to_negra() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.mcfg"));
    let tree_stack = automaton.recognise(
        String::from("aabccd").chars().map(|x| x.to_string()).collect()
    ).next().unwrap().0;

    let syntax_tree = to_abstract_syntax_tree(tree_stack.storage.to_tree());
    let separated_syntax_tree = separate_terminal_rules(&syntax_tree);

    let negra_string = to_negra(&separated_syntax_tree, 0);
    let negra_control_string = String::from(
        "#BOS 0\n\
         a\ta\t--\t--\t1\n\
         a\ta\t--\t--\t2\n\
         b\tb\t--\t--\t3\n\
         c\tc\t--\t--\t1\n\
         c\tc\t--\t--\t2\n\
         d\td\t--\t--\t3\n\
         #1\tA\t--\t--\t4\n\
         #2\tA\t--\t--\t1\n\
         #3\tB\t--\t--\t4\n\
         #4\tS\t--\t--\t0\n\
         #EOS 0"
    );

    assert_eq!(negra_control_string, negra_string);
}

#[test]
fn test_from_str_automaton() {
    let i1: TreeStackInstruction<String> = TreeStackInstruction::Up {
        n: 1,
        current_val: "zwei".to_string(),
        old_val: "drei".to_string(),
        new_val: "vier".to_string(),
    };

    let i2: TreeStackInstruction<String> = TreeStackInstruction::Push {
        n: 1,
        current_val: "zwei".to_string(),
        new_val: "vier".to_string(),
    };

    let i3: TreeStackInstruction<String> = TreeStackInstruction::Down {
        current_val: "zwei".to_string(),
        old_val: "drei".to_string(),
        new_val: "vier".to_string(),
    };

    let i1_string = "Up 1 zwei drei vier";
    let i1_string2 = "   Up 1  zwei  drei   vier  ";
    let i2_string = "Push 1 zwei vier";
    let i3_string = "Down zwei drei vier";

    assert_eq!(Ok(i1.clone()), i1_string.parse());
    assert_eq!(Ok(i1.clone()), i1_string2.parse());
    assert_eq!(Ok(i2.clone()), i2_string.parse());
    assert_eq!(Ok(i3.clone()), i3_string.parse());

    let t1 = Transition {
        word: vec!["hello".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i1,
    };

    let t2 = Transition {
        word: vec!["\"hello\\".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i2,
    };

    let t3 = Transition {
        word: vec!["\"hello\\".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i3,
    };

    let mut t1_string = String::from("Transition [\"hello\",\"world\"] (");
    t1_string.push_str(i1_string);
    t1_string.push_str(") #0.5");

    let mut t2_string = String::from("Transition [\"\\\"hello\\\\\",\"world\"] (");
    t2_string.push_str(i2_string);
    t2_string.push_str(") #0.5");

    let mut t3_string = String::from("Transition [\"\\\"hello\\\\\",\"world\"] (");
    t3_string.push_str(i3_string);
    t3_string.push_str(") #0.5");

    assert_eq!(Ok(t1.clone()), t1_string.parse());
    assert_eq!(Ok(t2.clone()), t2_string.parse());
    assert_eq!(Ok(t3.clone()), t3_string.parse());

    let automaton: TreeStackAutomaton<String, String, LogDomain<f64>> = TreeStackAutomaton::new(
        vec![t1.clone(), t2.clone(), t3.clone()],
        TreeStack::new("eins".to_string())
    );

    let mut automaton_string: String = String::from("initial: eins\n\n");
    automaton_string.push_str(t1_string.as_str());
    automaton_string.push_str("\n");
    automaton_string.push_str(t2_string.as_str());
    automaton_string.push_str("\n");
    automaton_string.push_str(t3_string.as_str());
    automaton_string.push_str("\n");

    let automaton_parse: TreeStackAutomaton<String, String, LogDomain<f64>> = automaton_string.parse().unwrap();

    let ts1: Vec<_> = automaton.list_transitions().collect();
    let ts2: Vec<_> = automaton_parse.list_transitions().collect();

    assert_eq!(ts1, ts2);

    assert_eq!(
        automaton.initial(),
        automaton_parse.initial()
    );
}

#[test]
fn test_coarse_to_fine_recogniser_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.mcfg"));
    let tts = TTSElement::new();
    let rel: EquivalenceRelation<String, String> = "0 [A, B]\n1 *".parse().unwrap();
    let mapping = |ps: &PosState<_>| ps
        .map(|r: &PMCFGRule<_, _, _>| r.map_nonterminals(|nt| rel.project(nt)));
    let rlb = RlbElement::new(&mapping);
    let recogniser = coarse_to_fine_recogniser!(automaton.clone(); tts, rlb);

    let words = vec![
        "aabccd",
        "aaabcccd",
        "abccd",
        "abbcd",
    ];

    for word in words {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next(),
            recogniser.recognise(input).next()
        );
    }
}

#[test]
fn test_tts_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.mcfg"));
    let tts = TTSElement::new();
    let (tts_ed_automaton, _) = tts.approximate_automaton(&automaton);

    let true_positives_and_true_negatives = vec![
        "",
        "abcd",
        "aabccd",
        "aaabcccd",
    ];

    for word in true_positives_and_true_negatives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next().is_some(),
            tts_ed_automaton.recognise(input).next().is_some()
        );
    }

    let false_positives = vec![
        "aabcd",
        "aabbcd",
        "abbcccdddd",
        "abbbccdddd",
    ];

    for word in false_positives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(false, automaton.recognise(input.clone()).next().is_some());
        assert_eq!(true, tts_ed_automaton.recognise(input).next().is_some());
    }
}

#[test]
fn test_from_str_pmcfg() {
    let c0: Composition<String> = Composition {
        composition: vec![vec![VarT::Var(0, 0), VarT::Var(1, 0), VarT::Var(0, 1), VarT::Var(1, 1)]],
    };

    let c1: Composition<String> = Composition { composition: vec![vec![], vec![]] };

    let c2 = Composition {
        composition: vec![vec![VarT::T("a".to_string()),
                               VarT::Var(0, 0)],
                          vec![VarT::T("c".to_string()),
                               VarT::Var(0, 1)]],
    };

    let c3 = Composition {
        composition: vec![vec![VarT::T("b".to_string()),
                               VarT::Var(0, 0)],
                          vec![VarT::T("d".to_string()),
                               VarT::Var(0, 1)]],
    };

    let r0: PMCFGRule<String, String, LogDomain<f64>> = PMCFGRule {
        head: "S".to_string(),
        tail: vec!["A".to_string(), "B".to_string()],
        composition: c0.clone(),
        weight: LogDomain::new(1.0).unwrap(),
    };

    let r1: PMCFGRule<String, String, LogDomain<f64>> = PMCFGRule {
        head: "A".to_string(),
        tail: Vec::new(),
        composition: c1.clone(),
        weight: LogDomain::new(0.6).unwrap(),
    };

    let r2: PMCFGRule<String, String, LogDomain<f64>> = PMCFGRule {
        head: "A".to_string(),
        tail: vec!["A".to_string()],
        composition: c2.clone(),
        weight: LogDomain::new(0.4).unwrap(),
    };

    let r3: PMCFGRule<String, String, LogDomain<f64>> = PMCFGRule {
        head: "B".to_string(),
        tail: Vec::new(),
        composition: c1.clone(),
        weight: LogDomain::new(0.7).unwrap(),
    };

    let r4: PMCFGRule<String, String, LogDomain<f64>> = PMCFGRule {
        head: "B".to_string(),
        tail: vec!["B".to_string()],
        composition: c3.clone(),
        weight: LogDomain::new(0.3).unwrap(),
    };

    let r0_string = "\"S\" → [[Var 0 0, Var 1 0, Var 0 1, Var 1 1]] (\"A\", B)";
    let r1_string = "A → [[],[]] ()  # 0.6 % this is a comment";
    let r2_string = "A → [[T a, Var 0 0],[T c, Var 0 1]] (A)  # 0.4";
    let r3_string = "B → [[],[]] ()  # 0.7";
    let r4_string = "B → [[T b, Var 0 0],[T d, Var 0 1]] (B)  # 0.3";

    assert_eq!(Ok(r0.clone()),
               r0_string.parse::<PMCFGRule<String, String, LogDomain<f64>>>());
    assert_eq!(Ok(r1.clone()),
               r1_string.parse::<PMCFGRule<String, String, LogDomain<f64>>>());
    assert_eq!(Ok(r2.clone()),
               r2_string.parse::<PMCFGRule<String, String, LogDomain<f64>>>());
    assert_eq!(Ok(r3.clone()),
               r3_string.parse::<PMCFGRule<String, String, LogDomain<f64>>>());
    assert_eq!(Ok(r4.clone()),
               r4_string.parse::<PMCFGRule<String, String, LogDomain<f64>>>());

    let g: PMCFG<String, String, LogDomain<f64>> = PMCFG {
        initial: vec!["S".to_string()],
        rules: vec![r0.clone(), r1.clone(), r2.clone(), r3.clone(), r4.clone()],
    };

    let mut g_string = String::from("initial: [S]\n\n");
    g_string.push_str(r0_string.clone());
    g_string.push_str("\n");
    g_string.push_str(r1_string.clone());
    g_string.push_str("\n");
    g_string.push_str(r2_string.clone());
    g_string.push_str("\n");
    g_string.push_str(r3_string.clone());
    g_string.push_str("\n");
    g_string.push_str(r4_string.clone());

    assert_eq!(Ok(g.clone()), g_string.parse());

    let a = TreeStackAutomaton::from(g);

    assert_ne!(None, a.recognise(vec!["a".to_string(), "b".to_string(), "c".to_string(), "d".to_string()]).next());
}
<commit_msg>tests/pmcfg.rs: reworked integration test of PMCFG::from_str()<commit_after>extern crate log_domain;
#[macro_use]
extern crate rustomata;

use log_domain::LogDomain;
use std::fs::File;
use std::io::Read;
use std::rc::Rc;

use rustomata::approximation::ApproximationStrategy;
use rustomata::approximation::equivalence_classes::EquivalenceRelation;
use rustomata::approximation::relabel::RlbElement;
use rustomata::approximation::tts::TTSElement;
use rustomata::pmcfg::*;
use rustomata::pmcfg::negra::to_negra;
use rustomata::recognisable::*;
use rustomata::recognisable::coarse_to_fine::CoarseToFineRecogniser;
use rustomata::tree_stack_automaton::*;

fn pmcfg_from_file(grammar_file_path: &str) -> PMCFG<String, String, LogDomain<f64>>
{
    let mut grammar_file = File::open(grammar_file_path).unwrap();
    let mut grammar_string = String::new();
    let _ = grammar_file.read_to_string(&mut grammar_string);
    grammar_string.parse().unwrap()
}

#[test]
fn test_example_pmcfg_to_negra() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.mcfg"));
    let tree_stack = automaton.recognise(
        String::from("aabccd").chars().map(|x| x.to_string()).collect()
    ).next().unwrap().0;

    let syntax_tree = to_abstract_syntax_tree(tree_stack.storage.to_tree());
    let separated_syntax_tree = separate_terminal_rules(&syntax_tree);

    let negra_string = to_negra(&separated_syntax_tree, 0);
    let negra_control_string = String::from(
        "#BOS 0\n\
         a\ta\t--\t--\t1\n\
         a\ta\t--\t--\t2\n\
         b\tb\t--\t--\t3\n\
         c\tc\t--\t--\t1\n\
         c\tc\t--\t--\t2\n\
         d\td\t--\t--\t3\n\
         #1\tA\t--\t--\t4\n\
         #2\tA\t--\t--\t1\n\
         #3\tB\t--\t--\t4\n\
         #4\tS\t--\t--\t0\n\
         #EOS 0"
    );

    assert_eq!(negra_control_string, negra_string);
}

#[test]
fn test_from_str_automaton() {
    let i1: TreeStackInstruction<String> = TreeStackInstruction::Up {
        n: 1,
        current_val: "zwei".to_string(),
        old_val: "drei".to_string(),
        new_val: "vier".to_string(),
    };

    let i2: TreeStackInstruction<String> = TreeStackInstruction::Push {
        n: 1,
        current_val: "zwei".to_string(),
        new_val: "vier".to_string(),
    };

    let i3: TreeStackInstruction<String> = TreeStackInstruction::Down {
        current_val: "zwei".to_string(),
        old_val: "drei".to_string(),
        new_val: "vier".to_string(),
    };

    let i1_string = "Up 1 zwei drei vier";
    let i1_string2 = "   Up 1  zwei  drei   vier  ";
    let i2_string = "Push 1 zwei vier";
    let i3_string = "Down zwei drei vier";

    assert_eq!(Ok(i1.clone()), i1_string.parse());
    assert_eq!(Ok(i1.clone()), i1_string2.parse());
    assert_eq!(Ok(i2.clone()), i2_string.parse());
    assert_eq!(Ok(i3.clone()), i3_string.parse());

    let t1 = Transition {
        word: vec!["hello".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i1,
    };

    let t2 = Transition {
        word: vec!["\"hello\\".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i2,
    };

    let t3 = Transition {
        word: vec!["\"hello\\".to_string(), "world".to_string()],
        weight: LogDomain::new(0.5).unwrap(),
        instruction: i3,
    };

    let mut t1_string = String::from("Transition [\"hello\",\"world\"] (");
    t1_string.push_str(i1_string);
    t1_string.push_str(") #0.5");

    let mut t2_string = String::from("Transition [\"\\\"hello\\\\\",\"world\"] (");
    t2_string.push_str(i2_string);
    t2_string.push_str(") #0.5");

    let mut t3_string = String::from("Transition [\"\\\"hello\\\\\",\"world\"] (");
    t3_string.push_str(i3_string);
    t3_string.push_str(") #0.5");

    assert_eq!(Ok(t1.clone()), t1_string.parse());
    assert_eq!(Ok(t2.clone()), t2_string.parse());
    assert_eq!(Ok(t3.clone()), t3_string.parse());

    let automaton: TreeStackAutomaton<String, String, LogDomain<f64>> = TreeStackAutomaton::new(
        vec![t1.clone(), t2.clone(), t3.clone()],
        TreeStack::new("eins".to_string())
    );

    let mut automaton_string: String = String::from("initial: eins\n\n");
    automaton_string.push_str(t1_string.as_str());
    automaton_string.push_str("\n");
    automaton_string.push_str(t2_string.as_str());
    automaton_string.push_str("\n");
    automaton_string.push_str(t3_string.as_str());
    automaton_string.push_str("\n");

    let automaton_parse: TreeStackAutomaton<String, String, LogDomain<f64>> = automaton_string.parse().unwrap();

    let ts1: Vec<_> = automaton.list_transitions().collect();
    let ts2: Vec<_> = automaton_parse.list_transitions().collect();

    assert_eq!(ts1, ts2);

    assert_eq!(
        automaton.initial(),
        automaton_parse.initial()
    );
}

#[test]
fn test_coarse_to_fine_recogniser_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.mcfg"));
    let tts = TTSElement::new();
    let rel: EquivalenceRelation<String, String> = "0 [A, B]\n1 *".parse().unwrap();
    let mapping = |ps: &PosState<_>| ps
        .map(|r: &PMCFGRule<_, _, _>| r.map_nonterminals(|nt| rel.project(nt)));
    let rlb = RlbElement::new(&mapping);
    let recogniser = coarse_to_fine_recogniser!(automaton.clone(); tts, rlb);

    let words = vec![
        "aabccd",
        "aaabcccd",
        "abccd",
        "abbcd",
    ];

    for word in words {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next(),
            recogniser.recognise(input).next()
        );
    }
}

#[test]
fn test_tts_correctness() {
    let automaton = TreeStackAutomaton::from(pmcfg_from_file("examples/example.mcfg"));
    let tts = TTSElement::new();
    let (tts_ed_automaton, _) = tts.approximate_automaton(&automaton);

    let true_positives_and_true_negatives = vec![
        "",
        "abcd",
        "aabccd",
        "aaabcccd",
    ];

    for word in true_positives_and_true_negatives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            automaton.recognise(input.clone()).next().is_some(),
            tts_ed_automaton.recognise(input).next().is_some()
        );
    }

    let false_positives = vec![
        "aabcd",
        "aabbcd",
        "abbcccdddd",
        "abbbccdddd",
    ];

    for word in false_positives {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(false, automaton.recognise(input.clone()).next().is_some());
        assert_eq!(true, tts_ed_automaton.recognise(input).next().is_some());
    }
}

#[test]
fn test_pmcfg_from_str_correctness() {
    let rule_s0 = PMCFGRule {
        head: String::from("S"),
        tail: vec![String::from("A"), String::from("B")],
        composition: Composition { composition: vec![
            vec![VarT::Var(0, 0), VarT::Var(1, 0), VarT::Var(0, 1), VarT::Var(1, 1)],
        ] },
        weight: LogDomain::new(1.0).unwrap()
    };
    let rule_a0 = PMCFGRule {
        head: String::from("A"),
        tail: vec![String::from("A")],
        composition: Composition { composition: vec![
            vec![VarT::T(String::from("a")), VarT::Var(0, 0)],
            vec![VarT::T(String::from("c")), VarT::Var(0, 1)],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_a1 = PMCFGRule {
        head: String::from("A"),
        tail: vec![],
        composition: Composition { composition: vec![
            vec![],
            vec![],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_b0 = PMCFGRule {
        head: String::from("B"),
        tail: vec![String::from("B")],
        composition: Composition { composition: vec![
            vec![VarT::T(String::from("b")), VarT::Var(0, 0)],
            vec![VarT::T(String::from("d")), VarT::Var(0, 1)],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let rule_b1 = PMCFGRule {
        head: String::from("B"),
        tail: vec![],
        composition: Composition { composition: vec![
            vec![],
            vec![],
        ] },
        weight: LogDomain::new(0.5).unwrap()
    };
    let control_grammar = PMCFG {
        initial: vec![String::from("S")],
        rules: vec![rule_s0, rule_a0, rule_a1, rule_b0, rule_b1]
    };

    let grammar = pmcfg_from_file("examples/example.mcfg");
    assert_eq!(
        control_grammar.clone(),
        grammar.clone()
    );

    let control_automaton = TreeStackAutomaton::from(control_grammar);
    let automaton = TreeStackAutomaton::from(grammar);
    let words = vec![
        "",
        "aabccd",
        "aabbcd",
        "aabccdd",
    ];

    for word in words {
        let input: Vec<_> = String::from(word).chars().map(|x| x.to_string()).collect();
        assert_eq!(
            control_automaton.recognise(input.clone()).next().is_some(),
            automaton.recognise(input).next().is_some()
        );
    }
}
<|endoftext|>


<commit_before>use rover;
use coords::Position2D;

#[test]
fn should_create_new_rover(){
    let r = rover::new();
    assert_eq!(r.position, Position2D{x: 0, y: 0})
}

#[test]
fn should_move_north(){
    let mut r = rover::new();
    r.move(rover::YDelta(1));
    assert_eq!(r.position, Position2D{x: 0, y: 1})
}

#[test]
fn should_move_north_twice(){
    let mut r = rover::new();
    r.move(rover::YDelta(2));
    assert_eq!(r.position, Position2D{x: 0, y: 2})
}

#[test]
fn should_move_east(){
    let mut r = rover::new();
    r.move(rover::XDelta(1));
    assert_eq!(r.position, Position2D{x: 1, y: 0})
}

#[test]
fn should_move_east_twice(){
    let mut r = rover::new();
    r.move(rover::XDelta(2));
    assert_eq!(r.position, Position2D{x: 2, y: 0})
}

#[test]
fn should_move_south(){
    let mut r = rover::new();
    r.move(rover::YDelta(-1));
    assert_eq!(r.position, Position2D{x: 0, y: -1})
}

#[test]
fn should_move_south_twice(){
    let mut r = rover::new();
    r.move(rover::YDelta(-2));
    assert_eq!(r.position, Position2D{x: 0, y: -2})
}

#[test]
fn should_move_west(){
    let mut r = rover::new();
    r.move(rover::XDelta(-1));
    assert_eq!(r.position, Position2D{x: -1, y: 0})
}

#[test]
fn should_move_west_twice(){
    let mut r = rover::new();
    r.move(rover::XDelta(-2));
    assert_eq!(r.position, Position2D{x: -2, y: 0})
}

#[test]
fn should_move_by_position(){
    let mut r = rover::new();
    r.move(rover::Vector(2, 3));
    assert_eq!(r.position, Position2D{x: 2, y: 3})
}
<commit_msg>fix test name<commit_after>use rover;
use coords::Position2D;

#[test]
fn should_create_new_rover(){
    let r = rover::new();
    assert_eq!(r.position, Position2D{x: 0, y: 0})
}

#[test]
fn should_move_north(){
    let mut r = rover::new();
    r.move(rover::YDelta(1));
    assert_eq!(r.position, Position2D{x: 0, y: 1})
}

#[test]
fn should_move_north_twice(){
    let mut r = rover::new();
    r.move(rover::YDelta(2));
    assert_eq!(r.position, Position2D{x: 0, y: 2})
}

#[test]
fn should_move_east(){
    let mut r = rover::new();
    r.move(rover::XDelta(1));
    assert_eq!(r.position, Position2D{x: 1, y: 0})
}

#[test]
fn should_move_east_twice(){
    let mut r = rover::new();
    r.move(rover::XDelta(2));
    assert_eq!(r.position, Position2D{x: 2, y: 0})
}

#[test]
fn should_move_south(){
    let mut r = rover::new();
    r.move(rover::YDelta(-1));
    assert_eq!(r.position, Position2D{x: 0, y: -1})
}

#[test]
fn should_move_south_twice(){
    let mut r = rover::new();
    r.move(rover::YDelta(-2));
    assert_eq!(r.position, Position2D{x: 0, y: -2})
}

#[test]
fn should_move_west(){
    let mut r = rover::new();
    r.move(rover::XDelta(-1));
    assert_eq!(r.position, Position2D{x: -1, y: 0})
}

#[test]
fn should_move_west_twice(){
    let mut r = rover::new();
    r.move(rover::XDelta(-2));
    assert_eq!(r.position, Position2D{x: -2, y: 0})
}

#[test]
fn should_move_by_vector(){
    let mut r = rover::new();
    r.move(rover::Vector(2, 3));
    assert_eq!(r.position, Position2D{x: 2, y: 3})
}
<|endoftext|>


<commit_before>use crate::attr::Display;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{Ident, LitStr};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self) {
        if !self.args.is_empty() {
            return;
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = TokenStream::new();

        while let Some(brace) = read.find('{') {
            out += &read[..=brace];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let var = match next {
                '0'..='9' => take_int(&mut read),
                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),
                _ => return,
            };
            let ident = Ident::new(&var, span);
            args.extend(quote_spanned!(span=> , #ident));
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.was_shorthand = true;
    }
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    int.push('_');
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> String {
    let mut ident = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    ident
}

#[cfg(test)]
mod tests {
    use super::*;
    use proc_macro2::Span;

    fn assert(input: &str, fmt: &str, args: &str) {
        let mut display = Display {
            fmt: LitStr::new(input, Span::call_site()),
            args: TokenStream::new(),
        };
        display.expand_shorthand();
        assert_eq!(fmt, display.fmt.value());
        assert_eq!(args, display.args.to_string());
    }

    #[test]
    fn test_expand() {
        assert("error {var}", "error {}", ", var");
        assert("fn main() {{ }}", "fn main() {{ }}", "");
        assert(
            "{v} {v:?} {0} {0:?}",
            "{} {:?} {} {:?}",
            ", v , v , _0 , _0",
        );
    }
}
<commit_msg>Allow ident containing number<commit_after>use crate::attr::Display;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{Ident, LitStr};

impl Display<'_> {
    // Transform `"error {var}"` to `"error {}", var`.
    pub fn expand_shorthand(&mut self) {
        if !self.args.is_empty() {
            return;
        }

        let span = self.fmt.span();
        let fmt = self.fmt.value();
        let mut read = fmt.as_str();
        let mut out = String::new();
        let mut args = TokenStream::new();

        while let Some(brace) = read.find('{') {
            out += &read[..=brace];
            read = &read[brace + 1..];
            if read.starts_with('{') {
                out.push('{');
                read = &read[1..];
                continue;
            }
            let next = match read.chars().next() {
                Some(next) => next,
                None => return,
            };
            let var = match next {
                '0'..='9' => take_int(&mut read),
                'a'..='z' | 'A'..='Z' | '_' => take_ident(&mut read),
                _ => return,
            };
            let ident = Ident::new(&var, span);
            args.extend(quote_spanned!(span=> , #ident));
        }

        out += read;
        self.fmt = LitStr::new(&out, self.fmt.span());
        self.args = args;
        self.was_shorthand = true;
    }
}

fn take_int(read: &mut &str) -> String {
    let mut int = String::new();
    int.push('_');
    for (i, ch) in read.char_indices() {
        match ch {
            '0'..='9' => int.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    int
}

fn take_ident(read: &mut &str) -> String {
    let mut ident = String::new();
    for (i, ch) in read.char_indices() {
        match ch {
            'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => ident.push(ch),
            _ => {
                *read = &read[i..];
                break;
            }
        }
    }
    ident
}

#[cfg(test)]
mod tests {
    use super::*;
    use proc_macro2::Span;

    fn assert(input: &str, fmt: &str, args: &str) {
        let mut display = Display {
            fmt: LitStr::new(input, Span::call_site()),
            args: TokenStream::new(),
        };
        display.expand_shorthand();
        assert_eq!(fmt, display.fmt.value());
        assert_eq!(args, display.args.to_string());
    }

    #[test]
    fn test_expand() {
        assert("error {var}", "error {}", ", var");
        assert("fn main() {{ }}", "fn main() {{ }}", "");
        assert(
            "{v} {v:?} {0} {0:?}",
            "{} {:?} {} {:?}",
            ", v , v , _0 , _0",
        );
    }
}
<|endoftext|>


<commit_before>extern crate csv;
extern crate num;
extern crate rustc_serialize;

use super::pokemon_model;
use super::pokemon_token;
use super::enums;
use super::resolve;
use self::num::FromPrimitive;
use std::collections::HashMap;
use player::Player;

///Struct that is a representation of a move a pokemon can learn. Contains everything that is
///needed to calculate it's impact given a user and a target Pokemon.
#[derive(Debug, Clone, RustcDecodable)]
pub struct Technique {
    attack_id: usize,
    name: String,
    attack_type: String,
    power: Option<u16>,
    power_points: Option<u8>,
    accuracy: Option<u16>,
    priority: i8,
    target: String,
    damage_class: String,
    effect_short: String,
    effect_long: String,
    effect_chance: Option<u8>,
    category: String,
    ailment: String,
    min_hits: Option<u8>,
    max_hits: Option<u8>,
    min_turns: Option<u8>,
    max_turns: Option<u8>,
    drain_percentage: i8,
    healing_percentage: i8,
    crit_rate: u8,
    ailment_chance: u8,
    flinch_chance: u8,
    stat_chance: u8,
    description: String,
    stat: Option<i32>,
    effectivity_map: Option<HashMap<enums::types, i8>>,
    move_flags: Option<Vec<enums::MoveFlags>>,
    stat_change_rate: Option<i8>,
}

impl Technique {
    ///Matches over the category of a move and calls a specific method in resolve.rs for this
    ///category. All calculation is done inside the method, therefore no return is needed.
    pub fn resolve<T,U> (&self, user: pokemon_token::PokemonToken,
        target: pokemon_token::PokemonToken, attacker: T, defender: U)
        where T: Player, U: Player {
        if self.hits(target.clone(), user.clone()) {
            match self.get_category() {

                enums::Move_Category::Damage => resolve::deal_damage(self.clone(), user, target),

                enums::Move_Category::Ailment => resolve::ailment(self.get_ailment(), 100, target),

                enums::Move_Category::Net_Good_Stats => {},

                enums::Move_Category::Heal => {
                    resolve::heal(self.clone(), user, target);
                },

                enums::Move_Category::Damage_And_Ailment => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    resolve::ailment(self.get_ailment(), self.get_effect_chance(), target);
                },

                //apart from the Math done
                enums::Move_Category::Swagger => {
                    if resolve::change_stats(self.get_stat_change_rate(), self.get_stat(),
                        target.clone()) {
                        resolve::ailment(self.get_ailment(), 100, target);
                    }
                },

                enums::Move_Category::Damage_And_Lower => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    let _ = resolve::change_stats(self.get_stat_change_rate(), self.get_stat(),
                        target);
                },

                enums::Move_Category::Damage_And_Raise => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    let _ = resolve::change_stats(self.get_stat_change_rate(), self.get_stat(),
                        target);
                },

                enums::Move_Category::Damage_And_Heal => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    resolve::heal(self.clone(), user ,target);
                },

                enums::Move_Category::Ohko => {
                    if ((self.get_name() == "guillotine" || self.get_name() == "sheer-cold") &&
                    user.get_level() >= target.get_level()) || ((self.get_name() == "horn-drill" ||
                    self.get_name() == "fissure") && user.get_current().get_stat(enums::Stats::Speed)
                    >= target.get_current().get_stat(enums::Stats::Speed))  {
                        resolve::ko_attack(target);
                    } else {
                        println!("{} was not affected by {}", target.get_name(), self.get_name());
                    }
                },

                enums::Move_Category::Whole_Field_Effect => {},

                enums::Move_Category::Field_Effect => {},

                enums::Move_Category::Force_Switch => resolve::switch_pokemon(defender),

                enums::Move_Category::Unique => {},

            };
        } else {
            println!("{} missed {}", user.get_name(), target.get_name());
        }
    }

    pub fn hits(&self, user: pokemon_token::PokemonToken, target: pokemon_token::PokemonToken)
        -> bool {
        //TODO: Calculate if a move hits the target
        true
    }

    ///Takes the attacked Pokemon as an input besides the move and calculate from their types
    ///how effective the move is. Returns an appropriate enum for further calculations.
    pub fn get_effectiveness(&self, enemy: pokemon_token::PokemonToken) -> enums::TypeEffectiveness {
        let mut eff_count = 0;
        if self.clone().effectivity_map.unwrap().contains_key(&enemy.get_types().0) {
            eff_count = eff_count + self.clone().effectivity_map.unwrap().get(&enemy.get_types().0)
            .unwrap();
        }
        if enemy.get_types().1 != enums::types::undefined
        && self.clone().effectivity_map.unwrap().contains_key(&enemy.get_types().1) {
            eff_count = eff_count + self.clone().effectivity_map.unwrap().get(&enemy.get_types().1)
            .unwrap();
        }
        match eff_count {
            -2 => enums::TypeEffectiveness::NotEffective,
            -1 => enums::TypeEffectiveness::NotVeryEffective,
            0 => enums::TypeEffectiveness::Normal,
            1 => enums::TypeEffectiveness::VeryEffective,
            2 => enums::TypeEffectiveness::SuperEffective,
            _ => enums::TypeEffectiveness::Ineffective,
        }
    }

    pub fn get_id(&self) -> usize {
        self.attack_id
    }

    pub fn get_name(&self) -> String {
        self.name.clone()
    }

    pub fn get_type(&self) -> enums::types {
        let a_type: &str = &self.attack_type;
        match a_type {
            "normal" => enums::types::normal,
            "fighting" => enums::types::fighting,
            "flying" => enums::types::flying,
            "poison" => enums::types::poison,
            "ground" => enums::types::ground,
            "rock" => enums::types::rock,
            "bug" => enums::types::bug,
            "ghost" => enums::types::ghost,
            "steel" => enums::types::steel,
            "fire" => enums::types::fire,
            "water" => enums::types::water,
            "grass" => enums::types::grass,
            "electric" => enums::types::electric,
            "psychic" => enums::types::psychic,
            "ice" => enums::types::ice,
            "dragon" => enums::types::dragon,
            "dark" => enums::types::dark,
            "fairy" => enums::types::fairy,
            _ => enums::types::undefined,
        }
    }

    pub fn get_power(&self) -> Option<u16> {
        self.power
    }

    pub fn get_power_points(&self) -> Option<u8> {
        self.power_points
    }

    pub fn get_accuracy(&self) -> Option<u16> {
        self.accuracy
    }

    pub fn get_priority(&self) -> i8 {
        self.priority
    }

    pub fn get_target(&self) -> enums::Target {
        let tmp: &str = &self.target;
        match tmp {
            "specific-move" => enums::Target::SpecificMove,
            "selected-pokemon-me-first" => enums::Target::SelectedPokemonMeFirst,
            "ally" => enums::Target::Ally,
            "users-field" => enums::Target::UsersField,
            "user-or-ally" => enums::Target::UserOrAlly,
            "opponents-field" => enums::Target::OpponentsField,
            "user" => enums::Target::User,
            "random-opponent" => enums::Target::RandomOpponent,
            "all-other-pokemon" => enums::Target::AllOtherPokemon,
            "selected-pokemon" => enums::Target::SelectedPokemon,
            "all-opponents" => enums::Target::AllOpponents,
            "entire-field" => enums::Target::EntireField,
            "user-and-allies" => enums::Target::UserAndAllies,
            "all-pokemon" => enums::Target::AllPokemon,
            _ => unreachable!(),
        }
    }

    pub fn get_damage_class(&self) -> enums::DamageClass {
        let tmp: &str = &self.damage_class;
        match tmp {
            "physical" => enums::DamageClass::Physical,
            "special" => enums::DamageClass::Special,
            "status" => enums::DamageClass::Status,
            _ => unreachable!(),
        }
    }

    pub fn get_short_effect(&self) -> String {
        self.effect_short.clone()
    }

    pub fn get_long_effect(&self) -> String {
        self.effect_long.clone()
    }

    pub fn get_effect_chance(&self) -> u8 {
        if self.effect_chance.is_some() {
            return self.effect_chance.unwrap();
        }
        100
    }

    pub fn get_category(&self) -> enums::Move_Category {
        let tmp: &str = &self.category;
        match tmp {
            "damage" => enums::Move_Category::Damage,
            "ailment" => enums::Move_Category::Ailment,
            "net-good-stats" => enums::Move_Category::Net_Good_Stats,
            "heal" => enums::Move_Category::Heal,
            "damage+ailment" => enums::Move_Category::Damage_And_Ailment,
            "swagger" => enums::Move_Category::Swagger,
            "damage+lower" => enums::Move_Category::Damage_And_Lower,
            "damage+raise" => enums::Move_Category::Damage_And_Raise,
            "damage+heal" => enums::Move_Category::Damage_And_Heal,
            "ohko" => enums::Move_Category::Ohko,
            "whole-field-effect" => enums::Move_Category::Whole_Field_Effect,
            "field-effect" => enums::Move_Category::Field_Effect,
            "force-switch" => enums::Move_Category::Force_Switch,
            "unique" => enums::Move_Category::Unique,
            _ => unreachable!(),
        }
    }

    pub fn get_ailment(&self) -> enums::Ailment {
        let tmp: &str = &self.ailment;
        match tmp {
            "unknown" => enums::Ailment::Unknown,
            "none" => enums::Ailment::Undefined,
            "paralysis" => enums::Ailment::Paralysis,
            "sleep" => enums::Ailment::Sleep,
            "freeze" => enums::Ailment::Freeze,
            "burn" => enums::Ailment::Burn,
            "poison" => enums::Ailment::Poison,
            "confusion" => enums::Ailment::Confusion,
            "infatuation" => enums::Ailment::Infatuation,
            "trap" => enums::Ailment::Trap,
            "nightmare" => enums::Ailment::Nightmare,
            "torment" => enums::Ailment::Torment,
            "disable" => enums::Ailment::Disable,
            "yawn" => enums::Ailment::Yawn,
            "heal-block" => enums::Ailment::Heal_Block,
            "no-type-immunity" => enums::Ailment::No_Type_Immunity,
            "leech-seed" => enums::Ailment::Leech_Seed,
            "embargo" => enums::Ailment::Embargo,
            "perish-song" => enums::Ailment::Perish_Song,
            "ingrain" => enums::Ailment::Ingrain,
            _ => unreachable!(),
        }
    }

    pub fn get_min_hits(&self) -> u8 {
        if self.min_hits.is_some() {
            return self.min_hits.unwrap();
        }
        1
    }

    pub fn get_max_hits(&self) -> u8 {
        if self.max_hits.is_some() {
            return self.max_hits.unwrap();
        }
        1
    }

    pub fn get_min_turn(&self) -> u8 {
        if self.min_turns.is_some() {
            return self.min_turns.unwrap();
        }
        1
    }

    pub fn get_max_turns(&self) -> u8 {
        if self.max_turns.is_some() {
            return self.max_turns.unwrap();
        }
        1
    }

    pub fn get_drain_percentage(&self) -> i8 {
        self.drain_percentage
    }

    pub fn get_healing_percentage(&self) -> i8 {
        self.healing_percentage
    }

    pub fn get_crit_rate(&self) -> u8 {
        self.crit_rate
    }

    pub fn get_ailment_chance(&self) -> u8 {
        self.ailment_chance
    }

    pub fn get_flinch_chance(&self) -> u8 {
        self.flinch_chance
    }

    pub fn get_stat_chance(&self) -> u8 {
        self.stat_chance
    }

    pub fn get_description(&self) -> String {
        self.description.clone()
    }

    pub fn get_stat(&self) -> enums::Stats {
        if self.stat.is_some(){
            return enums::Stats::from_i32(self.stat.unwrap()).unwrap();
        }
        enums::Stats::from_i32(0).unwrap()
    }

    pub fn get_stat_change_rate(&self) -> i8 {
        if self.stat_change_rate.is_some() {
            return self.stat_change_rate.unwrap();
        }
        0
    }

    pub fn get_effectivity_map(&self) -> HashMap<enums::types, i8> {
        self.clone().effectivity_map.unwrap()
    }

    pub fn get_flags(&self) -> Vec<enums::MoveFlags> {
        if self.move_flags.is_some() {
            return self.move_flags.clone().unwrap();
        }
        Vec::new()
    }

    pub fn set_effectivity_map(&mut self, map: HashMap<enums::types, i8>) {
        self.effectivity_map = Some(map);
    }

    pub fn set_flags(&mut self, flag: Vec<enums::MoveFlags>) {
        self.move_flags = Some(flag);
    }
}
<commit_msg>added little comment<commit_after>extern crate csv;
extern crate num;
extern crate rustc_serialize;

use super::pokemon_model;
use super::pokemon_token;
use super::enums;
use super::resolve;
use self::num::FromPrimitive;
use std::collections::HashMap;
use player::Player;

///Struct that is a representation of a move a pokemon can learn. Contains everything that is
///needed to calculate it's impact given a user and a target Pokemon.
#[derive(Debug, Clone, RustcDecodable)]
pub struct Technique {
    attack_id: usize,
    name: String,
    attack_type: String,
    power: Option<u16>,
    power_points: Option<u8>,
    accuracy: Option<u16>,
    priority: i8,
    target: String,
    damage_class: String,
    effect_short: String,
    effect_long: String,
    effect_chance: Option<u8>,
    category: String,
    ailment: String,
    min_hits: Option<u8>,
    max_hits: Option<u8>,
    min_turns: Option<u8>,
    max_turns: Option<u8>,
    drain_percentage: i8,
    healing_percentage: i8,
    crit_rate: u8,
    ailment_chance: u8,
    flinch_chance: u8,
    stat_chance: u8,
    description: String,
    stat: Option<i32>,
    effectivity_map: Option<HashMap<enums::types, i8>>,
    move_flags: Option<Vec<enums::MoveFlags>>,
    stat_change_rate: Option<i8>,
}

impl Technique {
    ///Matches over the category of a move and calls a specific method in resolve.rs for this
    ///category. All calculation is done inside the method, therefore no return is needed.
    pub fn resolve<T,U> (&self, user: pokemon_token::PokemonToken,
        target: pokemon_token::PokemonToken, attacker: T, defender: U)
        where T: Player, U: Player {
        if self.hits(target.clone(), user.clone()) {
            match self.get_category() {

                enums::Move_Category::Damage => resolve::deal_damage(self.clone(), user, target),

                enums::Move_Category::Ailment => resolve::ailment(self.get_ailment(), 100, target),

                enums::Move_Category::Net_Good_Stats => {},

                enums::Move_Category::Heal => {
                    resolve::heal(self.clone(), user, target);
                },

                enums::Move_Category::Damage_And_Ailment => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    resolve::ailment(self.get_ailment(), self.get_effect_chance(), target);
                },

                //apart from the Math done
                enums::Move_Category::Swagger => {
                    if resolve::change_stats(self.get_stat_change_rate(), self.get_stat(),
                        target.clone()) {
                        resolve::ailment(self.get_ailment(), 100, target);
                    }
                },

                enums::Move_Category::Damage_And_Lower => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    let _ = resolve::change_stats(self.get_stat_change_rate(), self.get_stat(),
                        target);
                },

                enums::Move_Category::Damage_And_Raise => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    let _ = resolve::change_stats(self.get_stat_change_rate(), self.get_stat(),
                        target);
                },

                enums::Move_Category::Damage_And_Heal => {
                    resolve::deal_damage(self.clone(), user.clone(), target.clone());
                    resolve::heal(self.clone(), user ,target);
                },

                //totally done
                enums::Move_Category::Ohko => {
                    if ((self.get_name() == "guillotine" || self.get_name() == "sheer-cold") &&
                    user.get_level() >= target.get_level()) || ((self.get_name() == "horn-drill" ||
                    self.get_name() == "fissure") && user.get_current().get_stat(enums::Stats::Speed)
                    >= target.get_current().get_stat(enums::Stats::Speed))  {
                        resolve::ko_attack(target);
                    } else {
                        println!("{} was not affected by {}", target.get_name(), self.get_name());
                    }
                },

                enums::Move_Category::Whole_Field_Effect => {},

                enums::Move_Category::Field_Effect => {},

                enums::Move_Category::Force_Switch => resolve::switch_pokemon(defender),

                enums::Move_Category::Unique => {},

            };
        } else {
            println!("{} missed {}", user.get_name(), target.get_name());
        }
    }

    pub fn hits(&self, user: pokemon_token::PokemonToken, target: pokemon_token::PokemonToken)
        -> bool {
        //TODO: Calculate if a move hits the target
        true
    }

    ///Takes the attacked Pokemon as an input besides the move and calculate from their types
    ///how effective the move is. Returns an appropriate enum for further calculations.
    pub fn get_effectiveness(&self, enemy: pokemon_token::PokemonToken) -> enums::TypeEffectiveness {
        let mut eff_count = 0;
        if self.clone().effectivity_map.unwrap().contains_key(&enemy.get_types().0) {
            eff_count = eff_count + self.clone().effectivity_map.unwrap().get(&enemy.get_types().0)
            .unwrap();
        }
        if enemy.get_types().1 != enums::types::undefined
        && self.clone().effectivity_map.unwrap().contains_key(&enemy.get_types().1) {
            eff_count = eff_count + self.clone().effectivity_map.unwrap().get(&enemy.get_types().1)
            .unwrap();
        }
        match eff_count {
            -2 => enums::TypeEffectiveness::NotEffective,
            -1 => enums::TypeEffectiveness::NotVeryEffective,
            0 => enums::TypeEffectiveness::Normal,
            1 => enums::TypeEffectiveness::VeryEffective,
            2 => enums::TypeEffectiveness::SuperEffective,
            _ => enums::TypeEffectiveness::Ineffective,
        }
    }

    pub fn get_id(&self) -> usize {
        self.attack_id
    }

    pub fn get_name(&self) -> String {
        self.name.clone()
    }

    pub fn get_type(&self) -> enums::types {
        let a_type: &str = &self.attack_type;
        match a_type {
            "normal" => enums::types::normal,
            "fighting" => enums::types::fighting,
            "flying" => enums::types::flying,
            "poison" => enums::types::poison,
            "ground" => enums::types::ground,
            "rock" => enums::types::rock,
            "bug" => enums::types::bug,
            "ghost" => enums::types::ghost,
            "steel" => enums::types::steel,
            "fire" => enums::types::fire,
            "water" => enums::types::water,
            "grass" => enums::types::grass,
            "electric" => enums::types::electric,
            "psychic" => enums::types::psychic,
            "ice" => enums::types::ice,
            "dragon" => enums::types::dragon,
            "dark" => enums::types::dark,
            "fairy" => enums::types::fairy,
            _ => enums::types::undefined,
        }
    }

    pub fn get_power(&self) -> Option<u16> {
        self.power
    }

    pub fn get_power_points(&self) -> Option<u8> {
        self.power_points
    }

    pub fn get_accuracy(&self) -> Option<u16> {
        self.accuracy
    }

    pub fn get_priority(&self) -> i8 {
        self.priority
    }

    pub fn get_target(&self) -> enums::Target {
        let tmp: &str = &self.target;
        match tmp {
            "specific-move" => enums::Target::SpecificMove,
            "selected-pokemon-me-first" => enums::Target::SelectedPokemonMeFirst,
            "ally" => enums::Target::Ally,
            "users-field" => enums::Target::UsersField,
            "user-or-ally" => enums::Target::UserOrAlly,
            "opponents-field" => enums::Target::OpponentsField,
            "user" => enums::Target::User,
            "random-opponent" => enums::Target::RandomOpponent,
            "all-other-pokemon" => enums::Target::AllOtherPokemon,
            "selected-pokemon" => enums::Target::SelectedPokemon,
            "all-opponents" => enums::Target::AllOpponents,
            "entire-field" => enums::Target::EntireField,
            "user-and-allies" => enums::Target::UserAndAllies,
            "all-pokemon" => enums::Target::AllPokemon,
            _ => unreachable!(),
        }
    }

    pub fn get_damage_class(&self) -> enums::DamageClass {
        let tmp: &str = &self.damage_class;
        match tmp {
            "physical" => enums::DamageClass::Physical,
            "special" => enums::DamageClass::Special,
            "status" => enums::DamageClass::Status,
            _ => unreachable!(),
        }
    }

    pub fn get_short_effect(&self) -> String {
        self.effect_short.clone()
    }

    pub fn get_long_effect(&self) -> String {
        self.effect_long.clone()
    }

    pub fn get_effect_chance(&self) -> u8 {
        if self.effect_chance.is_some() {
            return self.effect_chance.unwrap();
        }
        100
    }

    pub fn get_category(&self) -> enums::Move_Category {
        let tmp: &str = &self.category;
        match tmp {
            "damage" => enums::Move_Category::Damage,
            "ailment" => enums::Move_Category::Ailment,
            "net-good-stats" => enums::Move_Category::Net_Good_Stats,
            "heal" => enums::Move_Category::Heal,
            "damage+ailment" => enums::Move_Category::Damage_And_Ailment,
            "swagger" => enums::Move_Category::Swagger,
            "damage+lower" => enums::Move_Category::Damage_And_Lower,
            "damage+raise" => enums::Move_Category::Damage_And_Raise,
            "damage+heal" => enums::Move_Category::Damage_And_Heal,
            "ohko" => enums::Move_Category::Ohko,
            "whole-field-effect" => enums::Move_Category::Whole_Field_Effect,
            "field-effect" => enums::Move_Category::Field_Effect,
            "force-switch" => enums::Move_Category::Force_Switch,
            "unique" => enums::Move_Category::Unique,
            _ => unreachable!(),
        }
    }

    pub fn get_ailment(&self) -> enums::Ailment {
        let tmp: &str = &self.ailment;
        match tmp {
            "unknown" => enums::Ailment::Unknown,
            "none" => enums::Ailment::Undefined,
            "paralysis" => enums::Ailment::Paralysis,
            "sleep" => enums::Ailment::Sleep,
            "freeze" => enums::Ailment::Freeze,
            "burn" => enums::Ailment::Burn,
            "poison" => enums::Ailment::Poison,
            "confusion" => enums::Ailment::Confusion,
            "infatuation" => enums::Ailment::Infatuation,
            "trap" => enums::Ailment::Trap,
            "nightmare" => enums::Ailment::Nightmare,
            "torment" => enums::Ailment::Torment,
            "disable" => enums::Ailment::Disable,
            "yawn" => enums::Ailment::Yawn,
            "heal-block" => enums::Ailment::Heal_Block,
            "no-type-immunity" => enums::Ailment::No_Type_Immunity,
            "leech-seed" => enums::Ailment::Leech_Seed,
            "embargo" => enums::Ailment::Embargo,
            "perish-song" => enums::Ailment::Perish_Song,
            "ingrain" => enums::Ailment::Ingrain,
            _ => unreachable!(),
        }
    }

    pub fn get_min_hits(&self) -> u8 {
        if self.min_hits.is_some() {
            return self.min_hits.unwrap();
        }
        1
    }

    pub fn get_max_hits(&self) -> u8 {
        if self.max_hits.is_some() {
            return self.max_hits.unwrap();
        }
        1
    }

    pub fn get_min_turn(&self) -> u8 {
        if self.min_turns.is_some() {
            return self.min_turns.unwrap();
        }
        1
    }

    pub fn get_max_turns(&self) -> u8 {
        if self.max_turns.is_some() {
            return self.max_turns.unwrap();
        }
        1
    }

    pub fn get_drain_percentage(&self) -> i8 {
        self.drain_percentage
    }

    pub fn get_healing_percentage(&self) -> i8 {
        self.healing_percentage
    }

    pub fn get_crit_rate(&self) -> u8 {
        self.crit_rate
    }

    pub fn get_ailment_chance(&self) -> u8 {
        self.ailment_chance
    }

    pub fn get_flinch_chance(&self) -> u8 {
        self.flinch_chance
    }

    pub fn get_stat_chance(&self) -> u8 {
        self.stat_chance
    }

    pub fn get_description(&self) -> String {
        self.description.clone()
    }

    pub fn get_stat(&self) -> enums::Stats {
        if self.stat.is_some(){
            return enums::Stats::from_i32(self.stat.unwrap()).unwrap();
        }
        enums::Stats::from_i32(0).unwrap()
    }

    pub fn get_stat_change_rate(&self) -> i8 {
        if self.stat_change_rate.is_some() {
            return self.stat_change_rate.unwrap();
        }
        0
    }

    pub fn get_effectivity_map(&self) -> HashMap<enums::types, i8> {
        self.clone().effectivity_map.unwrap()
    }

    pub fn get_flags(&self) -> Vec<enums::MoveFlags> {
        if self.move_flags.is_some() {
            return self.move_flags.clone().unwrap();
        }
        Vec::new()
    }

    pub fn set_effectivity_map(&mut self, map: HashMap<enums::types, i8>) {
        self.effectivity_map = Some(map);
    }

    pub fn set_flags(&mut self, flag: Vec<enums::MoveFlags>) {
        self.move_flags = Some(flag);
    }
}
<|endoftext|>