<commit_before>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use runner;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io,
    pub name_stack: Vec<String>,
    pub failures: Vec<String>,
}

impl<'a, T: io::Write> Simple<'a, T> {
    pub fn new(buf: &mut T) -> Simple<T> {
        Simple {
            buf: buf,
            name_stack: vec![],
            failures: vec![],
        }
    }

    fn write_summary(&mut self, result: runner::RunnerResult) -> Result<(), io::Error> {
        let (res, report) = match result {
            Ok(report) => ("ok", report),
            Err(report) => ("FAILED", report),
        };

        writeln!(self.buf,
                 "\n\ntest result: {}. {} examples; {} passed; {} failed;",
                 res,
                 report.total_tests,
                 report.success_count,
                 report.error_count)
    }
}

impl<'a, T: io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: &Event) {
        // FIXME: do something with the io::Error ?
        let _ = match *event {
            Event::StartRunner => writeln!(self.buf, "Running tests:\n"),
            Event::StartDescribe(ref name) |
            Event::StartTest(ref name) => {
                self.name_stack.push(name.clone());
                Ok(())
            }
            Event::EndTest(result) => {
                if !self.name_stack.is_empty() {
                    let failure_name = self.name_stack.join(" | ");
                    self.failures.push(failure_name);
                    self.name_stack.pop();
                }
                let chr = if result.is_ok() {
                    "."
                } else {
                    "F"
                };
                write!(self.buf, "{}", chr)
            }
            Event::FinishedRunner(result) => self.write_summary(result),
            Event::EndDescribe => {
                self.name_stack.pop();
                Ok(())
            }
            // _ => Ok(()),
        };
    }
}
impl<'a, T: io::Write> Formatter for Simple<'a, T> {}

#[cfg(test)]
mod tests {
    pub use super::*;
    pub use formatter::formatter::Formatter;
    pub use events::{Event, EventHandler};
    pub use std::io;
    pub use std::str;

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec![1u8]);
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _: &Formatter = &Simple::new(&mut vec![1u8]) as &Formatter;
    }

    mod event_start_runner {
        pub use super::*;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::StartRunner);
            }

            assert_eq!("Running tests:\n\n", str::from_utf8(&v).unwrap());
        }
    }

    mod event_finished_runner {
        pub use super::*;
        use runner::TestReport;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        macro_rules! test_and_compare_output {
            ($(
                $test_name:ident : (success: $succ:expr, errors: $err:expr) => $msg:expr
            ),+) => {

                $(
                    #[test]
                    fn $test_name() {
                        let mut v = vec!();
                        {
                            let mut s = Simple::new(&mut v);
                            s.trigger(&Event::FinishedRunner(make_report($succ, $err)))
                        }

                        assert_eq!($msg, str::from_utf8(&v).unwrap())
                    }
                )+
            }
        }

        test_and_compare_output! {
            no_test_is_ok: (success: 0, errors: 0) =>
                "\n\ntest result: ok. 0 examples; 0 passed; 0 failed;\n",
            one_test: (success: 1, errors: 0) =>
                "\n\ntest result: ok. 1 examples; 1 passed; 0 failed;\n",
            multiple_ok: (success: 42, errors: 0) =>
                "\n\ntest result: ok. 42 examples; 42 passed; 0 failed;\n",
            one_error: (success: 0, errors: 1) =>
              "\n\ntest result: FAILED. 1 examples; 0 passed; 1 failed;\n",
            multiple_errors: (success: 0, errors: 37) =>
              "\n\ntest result: FAILED. 37 examples; 0 passed; 37 failed;\n",
            one_of_each: (success: 1, errors: 1) =>
              "\n\ntest result: FAILED. 2 examples; 1 passed; 1 failed;\n",
            multiple_of_each: (success: 12, errors: 21) =>
              "\n\ntest result: FAILED. 33 examples; 12 passed; 21 failed;\n"
        }
    }

    mod event_end_test {
        pub use super::*;

        #[test]
        fn it_displays_a_dot_when_success() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Ok(())));
            }

            assert_eq!(".", str::from_utf8(&v).unwrap());
        }

        #[test]
        #[allow(non_snake_case)]
        fn it_displays_a_F_when_error() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Err(())));
            }

            assert_eq!("F", str::from_utf8(&v).unwrap());
        }
    }

    mod event_start_end_describe {
        pub use super::*;

        #[test]
        fn start_describe_event_push_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            assert_eq!(vec![String::from("Hey !")], s.name_stack);

            s.trigger(&Event::StartDescribe(String::from("Ho !")));
            assert_eq!(vec![String::from("Hey !"), String::from("Ho !")],
                       s.name_stack)
        }

        #[test]
        fn end_describe_event_pop_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            s.trigger(&Event::StartDescribe(String::from("Ho !")));

            s.trigger(&Event::EndDescribe);
            assert_eq!(vec![String::from("Hey !")], s.name_stack);

            s.trigger(&Event::EndDescribe);
            assert_eq!(0, s.name_stack.len());
        }
    }

    mod failures_pretty_printing {
        use super::*;

        #[test]
        fn it_register_failures() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(1, s.failures.len());
        }

        #[test]
        fn it_keep_track_of_the_failure_name() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola".into()), s.failures.get(0));
        }

        #[test]
        fn it_has_a_nice_diplay_for_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | holé".into()), s.failures.get(0));

            s.trigger(&Event::StartDescribe("ohééé".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | ohééé | holé".into()), s.failures.get(1));
        }

        #[test]
        fn it_works_with_multiple_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));

            s.trigger(&Event::EndDescribe);
            s.trigger(&Event::StartDescribe("ok".into()));
            s.trigger(&Event::StartTest("cacao".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"ok | cacao".into()), s.failures.get(1));
        }

        // test the correct formating of one failure
        // #[test]
        // fn format_all_failures() {
        //    let mut buf = vec!();
        //    {
        //        let mut s = Simple::new(&mut buf);
        //        s.trigger(&Event::StartDescribe("hola".into()));
        //        s.trigger(&Event::StartTest("holé".into()));
        //        s.trigger(&Event::EndTest(Err(())));
        //    }

        //    let expect = ""
        // }
    }
}
<commit_msg> add failures summary<commit_after>use events::{Event, EventHandler};
use formatter::formatter::Formatter;
use runner;
use std::io;

pub struct Simple<'a, Io: io::Write + 'a> {
    buf: &'a mut Io,
    pub name_stack: Vec<String>,
    pub failures: Vec<String>,
}

impl<'a, T: io::Write> Simple<'a, T> {
    pub fn new(buf: &mut T) -> Simple<T> {
        Simple {
            buf: buf,
            name_stack: vec![],
            failures: vec![],
        }
    }

    fn failures_summary(&self) -> String {
        let res = String::with_capacity(100);
        let mut idx = 0;
        self.failures.iter()
                     .map(|fail| {
                         idx += 1;
                         format!("  {}) {}\n", idx, fail)
                     })
                     .fold(res, |mut acc, elt| {
                        acc.push_str(&elt);
                        acc
                     })
    }

    fn write_summary(&mut self, result: runner::RunnerResult) -> Result<(), io::Error> {
        let (res, report) = match result {
            Ok(report) => ("ok", report),
            Err(report) => ("FAILED", report),
        };

        writeln!(self.buf,
                 "\n\ntest result: {}. {} examples; {} passed; {} failed;",
                 res,
                 report.total_tests,
                 report.success_count,
                 report.error_count)
    }
}

impl<'a, T: io::Write> EventHandler for Simple<'a, T> {
    fn trigger(&mut self, event: &Event) {
        // FIXME: do something with the io::Error ?
        let _ = match *event {
            Event::StartRunner => writeln!(self.buf, "Running tests:\n"),
            Event::StartDescribe(ref name) |
            Event::StartTest(ref name) => {
                self.name_stack.push(name.clone());
                Ok(())
            }
            Event::EndTest(result) => {
                if !self.name_stack.is_empty() {
                    let failure_name = self.name_stack.join(" | ");
                    self.failures.push(failure_name);
                    self.name_stack.pop();
                }
                let chr = if result.is_ok() {
                    "."
                } else {
                    "F"
                };
                write!(self.buf, "{}", chr)
            }
            Event::FinishedRunner(result) => self.write_summary(result),
            Event::EndDescribe => {
                self.name_stack.pop();
                Ok(())
            }
            // _ => Ok(()),
        };
    }
}
impl<'a, T: io::Write> Formatter for Simple<'a, T> {}

#[cfg(test)]
mod tests {
    pub use super::*;
    pub use formatter::formatter::Formatter;
    pub use events::{Event, EventHandler};
    pub use std::io;
    pub use std::str;

    #[test]
    fn it_can_be_instanciated() {
        Simple::new(&mut vec![1u8]);
    }

    #[test]
    fn it_impl_formatter_trait() {
        let _: &Formatter = &Simple::new(&mut vec![1u8]) as &Formatter;
    }

    mod event_start_runner {
        pub use super::*;

        #[test]
        fn it_display_that_tests_started() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::StartRunner);
            }

            assert_eq!("Running tests:\n\n", str::from_utf8(&v).unwrap());
        }
    }

    mod event_finished_runner {
        pub use super::*;
        use runner::TestReport;

        fn make_report(succes: u32, errors: u32) -> Result<TestReport, TestReport> {
            let mut report = TestReport::default();
            report.success_count = succes;
            report.error_count = errors;
            report.total_tests = succes + errors;

            if errors != 0 {
                Err(report)
            } else {
                Ok(report)
            }
        }

        macro_rules! test_and_compare_output {
            ($(
                $test_name:ident : (success: $succ:expr, errors: $err:expr) => $msg:expr
            ),+) => {

                $(
                    #[test]
                    fn $test_name() {
                        let mut v = vec!();
                        {
                            let mut s = Simple::new(&mut v);
                            s.trigger(&Event::FinishedRunner(make_report($succ, $err)))
                        }

                        assert_eq!($msg, str::from_utf8(&v).unwrap())
                    }
                )+
            }
        }

        test_and_compare_output! {
            no_test_is_ok: (success: 0, errors: 0) =>
                "\n\ntest result: ok. 0 examples; 0 passed; 0 failed;\n",
            one_test: (success: 1, errors: 0) =>
                "\n\ntest result: ok. 1 examples; 1 passed; 0 failed;\n",
            multiple_ok: (success: 42, errors: 0) =>
                "\n\ntest result: ok. 42 examples; 42 passed; 0 failed;\n",
            one_error: (success: 0, errors: 1) =>
              "\n\ntest result: FAILED. 1 examples; 0 passed; 1 failed;\n",
            multiple_errors: (success: 0, errors: 37) =>
              "\n\ntest result: FAILED. 37 examples; 0 passed; 37 failed;\n",
            one_of_each: (success: 1, errors: 1) =>
              "\n\ntest result: FAILED. 2 examples; 1 passed; 1 failed;\n",
            multiple_of_each: (success: 12, errors: 21) =>
              "\n\ntest result: FAILED. 33 examples; 12 passed; 21 failed;\n"
        }
    }

    mod event_end_test {
        pub use super::*;

        #[test]
        fn it_displays_a_dot_when_success() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Ok(())));
            }

            assert_eq!(".", str::from_utf8(&v).unwrap());
        }

        #[test]
        #[allow(non_snake_case)]
        fn it_displays_a_F_when_error() {
            let mut v = vec![];
            {
                let mut s = Simple::new(&mut v);
                s.trigger(&Event::EndTest(Err(())));
            }

            assert_eq!("F", str::from_utf8(&v).unwrap());
        }
    }

    mod event_start_end_describe {
        pub use super::*;

        #[test]
        fn start_describe_event_push_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            assert_eq!(vec![String::from("Hey !")], s.name_stack);

            s.trigger(&Event::StartDescribe(String::from("Ho !")));
            assert_eq!(vec![String::from("Hey !"), String::from("Ho !")],
                       s.name_stack)
        }

        #[test]
        fn end_describe_event_pop_the_name_stack() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);

            s.trigger(&Event::StartDescribe(String::from("Hey !")));
            s.trigger(&Event::StartDescribe(String::from("Ho !")));

            s.trigger(&Event::EndDescribe);
            assert_eq!(vec![String::from("Hey !")], s.name_stack);

            s.trigger(&Event::EndDescribe);
            assert_eq!(0, s.name_stack.len());
        }
    }

    mod failures_pretty_printing {
        use super::*;

        #[test]
        fn it_register_failures() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(1, s.failures.len());
        }

        #[test]
        fn it_keep_track_of_the_failure_name() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartTest("hola".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola".into()), s.failures.get(0));
        }

        #[test]
        fn it_has_a_nice_diplay_for_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | holé".into()), s.failures.get(0));

            s.trigger(&Event::StartDescribe("ohééé".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"hola | ohééé | holé".into()), s.failures.get(1));
        }

        #[test]
        fn it_works_with_multiple_describes() {
            let mut sink = &mut io::sink();
            let mut s = Simple::new(&mut sink);
            s.trigger(&Event::StartDescribe("hola".into()));
            s.trigger(&Event::StartTest("holé".into()));
            s.trigger(&Event::EndTest(Err(())));

            s.trigger(&Event::EndDescribe);
            s.trigger(&Event::StartDescribe("ok".into()));
            s.trigger(&Event::StartTest("cacao".into()));
            s.trigger(&Event::EndTest(Err(())));
            assert_eq!(Some(&"ok | cacao".into()), s.failures.get(1));
        }

        // test the correct formating of one failure
        #[test]
        fn format_all_failures_one_error() {
            let mut buf = vec!();
            let res = {
                let mut s = Simple::new(&mut buf);
                s.trigger(&Event::StartDescribe("hola".into()));
                s.trigger(&Event::StartTest("holé".into()));
                s.trigger(&Event::EndTest(Err(())));
                s.failures_summary()
            };

            assert_eq!("  1) hola | holé\n", res);
        }
        #[test]
        fn format_all_failures() {
            let mut buf = vec!();
            let res = {
                let mut s = Simple::new(&mut buf);
                s.trigger(&Event::StartDescribe("hola".into()));
                s.trigger(&Event::StartTest("holé".into()));
                s.trigger(&Event::EndTest(Err(())));
                s.trigger(&Event::StartTest("hola".into()));
                s.trigger(&Event::EndTest(Err(())));
                s.failures_summary()
            };

            assert_eq!("  1) hola | holé\n  2) hola | hola\n", res);

            let res = {
                let mut s = Simple::new(&mut buf);
                s.trigger(&Event::StartDescribe("hola".into()));
                s.trigger(&Event::StartTest("holé".into()));
                s.trigger(&Event::EndTest(Err(())));
                s.trigger(&Event::EndDescribe);
                s.trigger(&Event::StartDescribe("second".into()));
                s.trigger(&Event::StartDescribe("third".into()));
                s.trigger(&Event::StartTest("hola".into()));
                s.trigger(&Event::EndTest(Err(())));
                s.failures_summary()
            };

            assert_eq!("  1) hola | holé\n  2) second | third | hola\n", res);
        }
    }
}
<|endoftext|>


<commit_before>use game::board::{GoBoard, GoMove, State};
use std::iter;

struct Group {
    indicies: Vec<usize>,
    liberties: i8,
    owner: State,
}

// A very simple GoBoard implementation where little attempt is made to optimize space and
// time complexities.
pub struct SimpleBoard {
    pub intersections: Vec<State>,
    groups: Vec<Group>,
    xsize: i8,
    ysize: i8,
}

impl GoBoard for SimpleBoard {
    fn new(ysize: i8, xsize: i8) -> SimpleBoard {
        SimpleBoard {
            intersections: vec![State::Empty; ((xsize as i32)*(ysize as i32)) as usize],
            groups: Vec::new(),
            xsize: xsize,
            ysize: ysize
        }
    }

    fn play_move(&mut self, mv: GoMove) {
        match mv {
            GoMove::Move {x, y, player} => self.play_at_coordinates(x, y, player),
            GoMove::Pass => {},
        };
    }
}

impl SimpleBoard {
    fn play_at_coordinates(&mut self, x: i8, y: i8, player: State) {
        // First check if there is already a stone here
        let index = self.coordinates_to_index(x, y);
        if self.intersections[index.unwrap()] != State::Empty {
            // not a valid move
        }
        else {
            // If our move was valid, add it to the board
            self.intersections[index.unwrap()] = player;
            let neighbors = self.neighbor_indicies(x, y);
            // Update the neighboring groups if there are any
            let mut group_indicies: Vec<usize> = Vec::new();
            let mut num_neighbors: i8 = 0;
            for neighbor in neighbors.iter() {
                match *neighbor {
                    Some(x) => {
                        let group_index = self.group_ref(x);
                        if group_index != None {
                            group_indicies.push(group_index.unwrap());
                        }
                        num_neighbors += 1;
                    },
                    None => {},
                }
            }
            group_indicies.sort();
            group_indicies.dedup();
            let added_to_group = self.update_groups(&group_indicies, index.unwrap(), player);
            if !added_to_group {
                // There were no neighboring groups, so we have to add one
                self.groups.push(Group{
                    indicies: vec![index.unwrap(); 1],
                    liberties: num_neighbors,
                    owner: player,
                })
            }
        }
    }

    fn group_ref(&mut self, index: usize) -> Option<usize> {
        let mut ret: Option<usize> = None;
        for (i, group) in self.groups.iter().enumerate() {
            if group.indicies.contains(&index) {
                ret = Some(i);
            }
        }
        ret
    }

    fn update_groups(&mut self, group_indicies: &Vec<usize>, play_index: usize, player: State) -> bool {
        let mut groups_to_merge: Vec<usize> = Vec::new();
        let mut added_to_group = false;
        for i in group_indicies.iter() {
            if self.groups[*i].owner == player {
                // Add the stone to the group
                self.groups[*i].indicies.push(play_index);
                groups_to_merge.push(*i);
                added_to_group = true;
            }
            else {
                // Attaching to an enemy group, this will reduce liberties by 1
                self.groups[*i].liberties -= 1;
            }
        }

        if groups_to_merge.len() > 1 {
            // We have friendly groups that the played stone merged together
            // group indices is already sorted so loop in reverse order, ignoring the
            // first group element
            for (i, gidx) in groups_to_merge.iter().rev().enumerate() {
                if i != 0 {
                    let other_group_copy: Vec<usize> = self.groups[*gidx].indicies.clone();
                    self.groups[groups_to_merge[0]].indicies.extend_from_slice(other_group_copy.as_slice());
                    self.groups.remove(*gidx);
                }
            }
        }
        // Kill off any groups that were killed by playing the immediate stone
        self.remove_all_dead_groups();
        // Recalculate all liberties
        self.recalculate_liberties();
        added_to_group
    }

    fn recalculate_liberties(&mut self) {
        let mut new_liberties: Vec<i8> = Vec::new();
        for group in &self.groups {
            let mut liberties: i8 = 0;
            let mut all_neighbors: Vec<Option<usize>> = Vec::new();
            for stone in &group.indicies {
                let (x, y) = self.index_to_coordinates(*stone);
                let neighbor = self.neighbor_indicies(x, y);

                all_neighbors.extend_from_slice(&neighbor);
            }
            all_neighbors.sort();
            all_neighbors.dedup();
            for n in all_neighbors.iter() {
                match *n {
                    Some(x) => {
                        if self.intersections[x] == State::Empty {
                            liberties += 1;
                        }
                    }
                    None => {},
                }
            }
            new_liberties.push(liberties);
        }
        for (i, l) in new_liberties.iter().enumerate() {
            self.groups[i].liberties = *l;
        }
    }

    fn remove_all_dead_groups(&mut self) {
        // Remove all groups with 0 liberties
        let mut groups_to_kill: Vec<usize> = Vec::new();
        for (i, group) in self.groups.iter().enumerate() {
            if group.liberties == 0 {
                groups_to_kill.push(i);
            }
        }
        // Group indicies will already be sorted, so iterate in reverse order and remove
        // them from the board
        for i in groups_to_kill.iter().rev() {
            self.remove_group(*i);
        }
    }

    fn remove_group(&mut self, group_index: usize) {
        for index in self.groups[group_index].indicies.iter() {
            self.intersections[*index] = State::Empty;
        }
        self.groups.remove(group_index);
    }

    fn neighbor_indicies(&self, x: i8, y: i8) -> [Option<usize>; 4] {
        [self.coordinates_to_index(x-1, y),
         self.coordinates_to_index(x+1, y),
         self.coordinates_to_index(x, y-1),
         self.coordinates_to_index(x, y+1)]
    }

    fn coordinates_to_index(&self, x: i8, y: i8) -> Option<usize> {
        let index: i32 = ((x as i32) + (y as i32)*(self.xsize as i32)) as i32;
        if index < 0 || index >= (self.xsize as i32)*(self.ysize as i32) {
            None
        }
        else {
            Some(((x as i32) + (y as i32)*(self.xsize as i32)) as usize)
        }
    }

    fn index_to_coordinates(&self, index: usize) -> (i8, i8) {
        let x = (index % (self.xsize as usize)) as i8;
        let y = (index / (self.xsize as usize)) as i8;
        (x, y)
    }

    pub fn print_board(&self) {
        // upper boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());

        for y in 0..self.ysize {
            for x in 0..self.xsize {
                let index = (x + y*self.xsize) as usize;
                print!("|{:?}", self.intersections[index]);
            }
            println!("|", );
        }

        // lower boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use game::board::*;

    #[test]
    fn play_move() {
        let mut game_board = SimpleBoard::new(3, 4);
        let mv = GoMove::Move{x: 2, y: 2, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    #[should_panic]
    fn play_move_out_of_bounds() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Move{x: 3, y: 3, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    fn corner_capture() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::White};
        let mv2 = GoMove::Move{ x: 0, y: 1, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        assert_eq!(State::Empty, game_board.intersections[0]);
        assert_eq!(State::Black, game_board.intersections[1]);
        assert_eq!(State::Black, game_board.intersections[3]);
    }

    #[test]
    fn pass() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Pass;
        game_board.play_move(mv);
    }

    #[test]
    fn merge_groups() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::Black};
        let mv2 = GoMove::Move{ x: 2, y: 0, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);

        assert_eq!(game_board.groups.len(), 2);

        game_board.play_move(mv3);

        assert_eq!(game_board.groups.len(), 1);
    }

    #[test]
    fn capture_with_one_eye() {
        let mut game_board = SimpleBoard::new(2, 2);
        let mv1 = GoMove::Move{ x: 0, y: 1, player: State::Black };
        let mv2 = GoMove::Move{ x: 1, y: 1, player: State::Black };
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black };

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        let mv4 = GoMove::Move{ x: 0, y: 0, player: State::White };

        game_board.play_move(mv4);

        assert_eq!(State::White, game_board.intersections[0]);
        assert_eq!(State::Empty, game_board.intersections[1]);
        assert_eq!(State::Empty, game_board.intersections[2]);
        assert_eq!(State::Empty, game_board.intersections[3]);

        assert_eq!(game_board.groups.len(), 1);

        assert_eq!(game_board.groups[0].liberties, 2);
    }
}
<commit_msg>Removed unnecessary import<commit_after>use game::board::{GoBoard, GoMove, State};

struct Group {
    indicies: Vec<usize>,
    liberties: i8,
    owner: State,
}

// A very simple GoBoard implementation where little attempt is made to optimize space and
// time complexities.
pub struct SimpleBoard {
    pub intersections: Vec<State>,
    groups: Vec<Group>,
    xsize: i8,
    ysize: i8,
}

impl GoBoard for SimpleBoard {
    fn new(ysize: i8, xsize: i8) -> SimpleBoard {
        SimpleBoard {
            intersections: vec![State::Empty; ((xsize as i32)*(ysize as i32)) as usize],
            groups: Vec::new(),
            xsize: xsize,
            ysize: ysize
        }
    }

    fn play_move(&mut self, mv: GoMove) {
        match mv {
            GoMove::Move {x, y, player} => self.play_at_coordinates(x, y, player),
            GoMove::Pass => {},
        };
    }
}

impl SimpleBoard {
    fn play_at_coordinates(&mut self, x: i8, y: i8, player: State) {
        // First check if there is already a stone here
        let index = self.coordinates_to_index(x, y);
        if self.intersections[index.unwrap()] != State::Empty {
            // not a valid move
        }
        else {
            // If our move was valid, add it to the board
            self.intersections[index.unwrap()] = player;
            let neighbors = self.neighbor_indicies(x, y);
            // Update the neighboring groups if there are any
            let mut group_indicies: Vec<usize> = Vec::new();
            let mut num_neighbors: i8 = 0;
            for neighbor in neighbors.iter() {
                match *neighbor {
                    Some(x) => {
                        let group_index = self.group_ref(x);
                        if group_index != None {
                            group_indicies.push(group_index.unwrap());
                        }
                        num_neighbors += 1;
                    },
                    None => {},
                }
            }
            group_indicies.sort();
            group_indicies.dedup();
            let added_to_group = self.update_groups(&group_indicies, index.unwrap(), player);
            if !added_to_group {
                // There were no neighboring groups, so we have to add one
                self.groups.push(Group{
                    indicies: vec![index.unwrap(); 1],
                    liberties: num_neighbors,
                    owner: player,
                })
            }
        }
    }

    fn group_ref(&mut self, index: usize) -> Option<usize> {
        let mut ret: Option<usize> = None;
        for (i, group) in self.groups.iter().enumerate() {
            if group.indicies.contains(&index) {
                ret = Some(i);
            }
        }
        ret
    }

    fn update_groups(&mut self, group_indicies: &Vec<usize>, play_index: usize, player: State) -> bool {
        let mut groups_to_merge: Vec<usize> = Vec::new();
        let mut added_to_group = false;
        for i in group_indicies.iter() {
            if self.groups[*i].owner == player {
                // Add the stone to the group
                self.groups[*i].indicies.push(play_index);
                groups_to_merge.push(*i);
                added_to_group = true;
            }
            else {
                // Attaching to an enemy group, this will reduce liberties by 1
                self.groups[*i].liberties -= 1;
            }
        }

        if groups_to_merge.len() > 1 {
            // We have friendly groups that the played stone merged together
            // group indices is already sorted so loop in reverse order, ignoring the
            // first group element
            for (i, gidx) in groups_to_merge.iter().rev().enumerate() {
                if i != 0 {
                    let other_group_copy: Vec<usize> = self.groups[*gidx].indicies.clone();
                    self.groups[groups_to_merge[0]].indicies.extend_from_slice(other_group_copy.as_slice());
                    self.groups.remove(*gidx);
                }
            }
        }
        // Kill off any groups that were killed by playing the immediate stone
        self.remove_all_dead_groups();
        // Recalculate all liberties
        self.recalculate_liberties();
        added_to_group
    }

    fn recalculate_liberties(&mut self) {
        let mut new_liberties: Vec<i8> = Vec::new();
        for group in &self.groups {
            let mut liberties: i8 = 0;
            let mut all_neighbors: Vec<Option<usize>> = Vec::new();
            for stone in &group.indicies {
                let (x, y) = self.index_to_coordinates(*stone);
                let neighbor = self.neighbor_indicies(x, y);

                all_neighbors.extend_from_slice(&neighbor);
            }
            all_neighbors.sort();
            all_neighbors.dedup();
            for n in all_neighbors.iter() {
                match *n {
                    Some(x) => {
                        if self.intersections[x] == State::Empty {
                            liberties += 1;
                        }
                    }
                    None => {},
                }
            }
            new_liberties.push(liberties);
        }
        for (i, l) in new_liberties.iter().enumerate() {
            self.groups[i].liberties = *l;
        }
    }

    fn remove_all_dead_groups(&mut self) {
        // Remove all groups with 0 liberties
        let mut groups_to_kill: Vec<usize> = Vec::new();
        for (i, group) in self.groups.iter().enumerate() {
            if group.liberties == 0 {
                groups_to_kill.push(i);
            }
        }
        // Group indicies will already be sorted, so iterate in reverse order and remove
        // them from the board
        for i in groups_to_kill.iter().rev() {
            self.remove_group(*i);
        }
    }

    fn remove_group(&mut self, group_index: usize) {
        for index in self.groups[group_index].indicies.iter() {
            self.intersections[*index] = State::Empty;
        }
        self.groups.remove(group_index);
    }

    fn neighbor_indicies(&self, x: i8, y: i8) -> [Option<usize>; 4] {
        [self.coordinates_to_index(x-1, y),
         self.coordinates_to_index(x+1, y),
         self.coordinates_to_index(x, y-1),
         self.coordinates_to_index(x, y+1)]
    }

    fn coordinates_to_index(&self, x: i8, y: i8) -> Option<usize> {
        let index: i32 = ((x as i32) + (y as i32)*(self.xsize as i32)) as i32;
        if index < 0 || index >= (self.xsize as i32)*(self.ysize as i32) {
            None
        }
        else {
            Some(((x as i32) + (y as i32)*(self.xsize as i32)) as usize)
        }
    }

    fn index_to_coordinates(&self, index: usize) -> (i8, i8) {
        let x = (index % (self.xsize as usize)) as i8;
        let y = (index / (self.xsize as usize)) as i8;
        (x, y)
    }

    pub fn print_board(&self) {
        // upper boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());

        for y in 0..self.ysize {
            for x in 0..self.xsize {
                let index = (x + y*self.xsize) as usize;
                print!("|{:?}", self.intersections[index]);
            }
            println!("|", );
        }

        // lower boundary
        // println!("{}", iter::repeat("_").take(10).collect::<String>());
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use game::board::*;

    #[test]
    fn play_move() {
        let mut game_board = SimpleBoard::new(3, 4);
        let mv = GoMove::Move{x: 2, y: 2, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    #[should_panic]
    fn play_move_out_of_bounds() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Move{x: 3, y: 3, player: State::White};
        game_board.play_move(mv);
    }

    #[test]
    fn corner_capture() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::White};
        let mv2 = GoMove::Move{ x: 0, y: 1, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        assert_eq!(State::Empty, game_board.intersections[0]);
        assert_eq!(State::Black, game_board.intersections[1]);
        assert_eq!(State::Black, game_board.intersections[3]);
    }

    #[test]
    fn pass() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv = GoMove::Pass;
        game_board.play_move(mv);
    }

    #[test]
    fn merge_groups() {
        let mut game_board = SimpleBoard::new(3, 3);
        let mv1 = GoMove::Move{ x: 0, y: 0, player: State::Black};
        let mv2 = GoMove::Move{ x: 2, y: 0, player: State::Black};
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black};

        game_board.play_move(mv1);
        game_board.play_move(mv2);

        assert_eq!(game_board.groups.len(), 2);

        game_board.play_move(mv3);

        assert_eq!(game_board.groups.len(), 1);
    }

    #[test]
    fn capture_with_one_eye() {
        let mut game_board = SimpleBoard::new(2, 2);
        let mv1 = GoMove::Move{ x: 0, y: 1, player: State::Black };
        let mv2 = GoMove::Move{ x: 1, y: 1, player: State::Black };
        let mv3 = GoMove::Move{ x: 1, y: 0, player: State::Black };

        game_board.play_move(mv1);
        game_board.play_move(mv2);
        game_board.play_move(mv3);

        let mv4 = GoMove::Move{ x: 0, y: 0, player: State::White };

        game_board.play_move(mv4);

        assert_eq!(State::White, game_board.intersections[0]);
        assert_eq!(State::Empty, game_board.intersections[1]);
        assert_eq!(State::Empty, game_board.intersections[2]);
        assert_eq!(State::Empty, game_board.intersections[3]);

        assert_eq!(game_board.groups.len(), 1);

        assert_eq!(game_board.groups[0].liberties, 2);
    }
}
<|endoftext|>


<commit_before>
//! Implements the gerrit structure

use call::Call;
use entities::*;
use entities;
use error::GGRError;
use error::GGRResult;
use rustc_serialize;
use std::error::Error;

/// `Gerrit` structure for management of several gerrit endpoints
pub struct Gerrit {
    call: Call,
}

impl Gerrit {
    /// Creates a new `Gerrit` object
    ///
    /// The url points to the http endpoint of an gerrit server like
    /// `http://localhost:8080/gerrit`. All other function append to this url there endpoint pathes
    /// and query parameters.
    pub fn new<S>(url: S) -> Gerrit
    where S: Into<String> {
        Gerrit {
            call: Call::new(url.into()),
        }
    }

    /// pull changes from gerrit server
    ///
    /// `querylist` and `additional_info` are used as filter in the call to gerrit.
    pub fn changes(&self, querylist: Option<&Vec<&str>>, additional_infos: Option<&Vec<&str>>)
        -> GGRResult<Vec<entities::ChangeInfo>>
    {
        let mut querystring = "pp=0&q=".to_string();
        match querylist {
            None => { /* nothing to do, we call without filter */ },
            Some(x) => {
                let urlfragment = Changes::build_url(x);
                querystring = format!("{}{}", querystring, urlfragment);
            },
        };

        if let Ok(cr) = self.call.get("/changes/".into(), querystring) {
            // TODO: too much unwrap's here
            let data2 = String::from_utf8(cr.body.unwrap()).unwrap();

            let data4: Vec<ChangeInfo> = match rustc_serialize::json::decode(&data2) {
                Ok(d) => {
                    d
                },
                Err(err) => {
                    return Err(GGRError::General(format!("{}: {}", err.description(), data2)));
                },
            };
            return Ok(data4);
        } else {
            println!("call problem");
        }
        Ok(Vec::new())
    }
}

// helper structures
struct Changes;
impl Changes {
    pub fn build_url(querylist: &Vec<&str>) -> String {
        let mut out = String::new();
        for el in querylist.iter() {
            out.push_str(el.clone());
            out.push_str("+");
        }
        if let Some(x) = out.chars().last() {
            if x == '+' {
                out = out.trim_right_matches(x).to_string();
            }
        };

        out
    }
}

#[test]
fn test_changes_build_url() {
    assert_eq!(Changes::build_url(&vec!()), "");
    assert_eq!(Changes::build_url(&vec!("a:1", "b:2")), "a:1+b:2");
    assert_eq!(Changes::build_url(&vec!("a:1")), "a:1");
}
<commit_msg>gerrit: usage of &[str] rather then &Vec[&str]<commit_after>
//! Implements the gerrit structure

use call::Call;
use entities::*;
use entities;
use error::GGRError;
use error::GGRResult;
use rustc_serialize;
use std::error::Error;

/// `Gerrit` structure for management of several gerrit endpoints
pub struct Gerrit {
    call: Call,
}

impl Gerrit {
    /// Creates a new `Gerrit` object
    ///
    /// The url points to the http endpoint of an gerrit server like
    /// `http://localhost:8080/gerrit`. All other function append to this url there endpoint pathes
    /// and query parameters.
    pub fn new<S>(url: S) -> Gerrit
    where S: Into<String> {
        Gerrit {
            call: Call::new(url.into()),
        }
    }

    /// pull changes from gerrit server
    ///
    /// `querylist` and `additional_info` are used as filter in the call to gerrit.
    pub fn changes(&self, querylist: Option<&[&str]>, additional_infos: Option<&[&str]>)
        -> GGRResult<Vec<entities::ChangeInfo>>
    {
        let mut querystring = "pp=0&q=".to_string();
        match querylist {
            None => { /* nothing to do, we call without filter */ },
            Some(x) => {
                let urlfragment = Changes::build_url(x);
                querystring = format!("{}{}", querystring, urlfragment);
            },
        };

        if let Ok(cr) = self.call.get("/changes/".into(), querystring) {
            // TODO: too much unwrap's here
            let data2 = String::from_utf8(cr.body.unwrap()).unwrap();

            let data4: Vec<ChangeInfo> = match rustc_serialize::json::decode(&data2) {
                Ok(d) => {
                    d
                },
                Err(err) => {
                    return Err(GGRError::General(format!("{}: {}", err.description(), data2)));
                },
            };
            return Ok(data4);
        } else {
            println!("call problem");
        }
        Ok(Vec::new())
    }
}

// helper structures
struct Changes;
impl Changes {
    pub fn build_url(querylist: &[&str]) -> String {
        let mut out = String::new();
        for el in querylist.iter() {
            out.push_str(el.clone());
            out.push_str("+");
        }
        if let Some(x) = out.chars().last() {
            if x == '+' {
                out = out.trim_right_matches(x).to_string();
            }
        };

        out
    }
}

#[test]
fn test_changes_build_url() {
    assert_eq!(Changes::build_url(&vec!()), "");
    assert_eq!(Changes::build_url(&vec!("a:1", "b:2")), "a:1+b:2");
    assert_eq!(Changes::build_url(&vec!("a:1")), "a:1");
}
<|endoftext|>


<commit_before>#[crate_type = "lib"];

class foo {
    let mut x: int;
    new(xx: int) { self.x = xx; }
}
<commit_msg>Remove test case that doesn't work on its own<commit_after><|endoftext|>


<commit_before>// xfail-fast

// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// tjc: I don't know why
pub mod pipes {
    use core::cast::{forget, transmute};

    pub enum state {
        empty,
        full,
        blocked,
        terminated
    }

    pub impl state : cmp::Eq {
        pure fn eq(&self, other: &state) -> bool {
            ((*self) as uint) == ((*other) as uint)
        }
        pure fn ne(&self, other: &state) -> bool { !(*self).eq(other) }
    }

    pub type packet<T: Owned> = {
        mut state: state,
        mut blocked_task: Option<task::Task>,
        mut payload: Option<T>
    };

    pub fn packet<T: Owned>() -> *packet<T> {
        unsafe {
            let p: *packet<T> = cast::transmute(~{
                mut state: empty,
                mut blocked_task: None::<task::Task>,
                mut payload: None::<T>
            });
            p
        }
    }

    #[abi = "rust-intrinsic"]
    mod rusti {
      pub fn atomic_xchg(_dst: &mut int, _src: int) -> int { fail; }
      pub fn atomic_xchg_acq(_dst: &mut int, _src: int) -> int { fail; }
      pub fn atomic_xchg_rel(_dst: &mut int, _src: int) -> int { fail; }
    }

    // We should consider moving this to ::core::unsafe, although I
    // suspect graydon would want us to use void pointers instead.
    pub unsafe fn uniquify<T>(+x: *T) -> ~T {
        unsafe { cast::transmute(move x) }
    }

    pub fn swap_state_acq(+dst: &mut state, src: state) -> state {
        unsafe {
            transmute(rusti::atomic_xchg_acq(transmute(move dst), src as int))
        }
    }

    pub fn swap_state_rel(+dst: &mut state, src: state) -> state {
        unsafe {
            transmute(rusti::atomic_xchg_rel(transmute(move dst), src as int))
        }
    }

    pub fn send<T: Owned>(-p: send_packet<T>, -payload: T) {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        assert (*p).payload.is_none();
        (*p).payload = move Some(move payload);
        let old_state = swap_state_rel(&mut (*p).state, full);
        match old_state {
          empty => {
            // Yay, fastpath.

            // The receiver will eventually clean this up.
            unsafe { forget(move p); }
          }
          full => { fail ~"duplicate send" }
          blocked => {

            // The receiver will eventually clean this up.
            unsafe { forget(move p); }
          }
          terminated => {
            // The receiver will never receive this. Rely on drop_glue
            // to clean everything up.
          }
        }
    }

    pub fn recv<T: Owned>(-p: recv_packet<T>) -> Option<T> {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        loop {
            let old_state = swap_state_acq(&mut (*p).state,
                                           blocked);
            match old_state {
              empty | blocked => { task::yield(); }
              full => {
                let mut payload = None;
                payload <-> (*p).payload;
                return Some(option::unwrap(move payload))
              }
              terminated => {
                assert old_state == terminated;
                return None;
              }
            }
        }
    }

    pub fn sender_terminate<T: Owned>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        match swap_state_rel(&mut (*p).state, terminated) {
          empty | blocked => {
            // The receiver will eventually clean up.
            unsafe { forget(move p) }
          }
          full => {
            // This is impossible
            fail ~"you dun goofed"
          }
          terminated => {
            // I have to clean up, use drop_glue
          }
        }
    }

    pub fn receiver_terminate<T: Owned>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        match swap_state_rel(&mut (*p).state, terminated) {
          empty => {
            // the sender will clean up
            unsafe { forget(move p) }
          }
          blocked => {
            // this shouldn't happen.
            fail ~"terminating a blocked packet"
          }
          terminated | full => {
            // I have to clean up, use drop_glue
          }
        }
    }

    pub struct send_packet<T: Owned> {
        mut p: Option<*packet<T>>,
    }

    pub impl<T: Owned> send_packet<T> : Drop {
        fn finalize(&self) {
            if self.p != None {
                let mut p = None;
                p <-> self.p;
                sender_terminate(option::unwrap(move p))
            }
        }
    }

    pub impl<T: Owned> send_packet<T> {
        fn unwrap() -> *packet<T> {
            let mut p = None;
            p <-> self.p;
            option::unwrap(move p)
        }
    }

    pub fn send_packet<T: Owned>(p: *packet<T>) -> send_packet<T> {
        send_packet {
            p: Some(p)
        }
    }

    pub struct recv_packet<T: Owned> {
        mut p: Option<*packet<T>>,
    }

    pub impl<T: Owned> recv_packet<T> : Drop {
        fn finalize(&self) {
            if self.p != None {
                let mut p = None;
                p <-> self.p;
                receiver_terminate(option::unwrap(move p))
            }
        }
    }

    pub impl<T: Owned> recv_packet<T> {
        fn unwrap() -> *packet<T> {
            let mut p = None;
            p <-> self.p;
            option::unwrap(move p)
        }
    }

    pub fn recv_packet<T: Owned>(p: *packet<T>) -> recv_packet<T> {
        recv_packet {
            p: Some(p)
        }
    }

    pub fn entangle<T: Owned>() -> (send_packet<T>, recv_packet<T>) {
        let p = packet();
        (send_packet(p), recv_packet(p))
    }
}

pub mod pingpong {
    use core::cast;
    use core::ptr;

    pub enum ping = ::pipes::send_packet<pong>;
    pub enum pong = ::pipes::send_packet<ping>;

    pub fn liberate_ping(-p: ping) -> ::pipes::send_packet<pong> {
        unsafe {
            let addr : *::pipes::send_packet<pong> = match &p {
              &ping(ref x) => { cast::transmute(ptr::addr_of(x)) }
            };
            let liberated_value = move *addr;
            cast::forget(move p);
            move liberated_value
        }
    }

    pub fn liberate_pong(-p: pong) -> ::pipes::send_packet<ping> {
        unsafe {
            let addr : *::pipes::send_packet<ping> = match &p {
              &pong(ref x) => { cast::transmute(ptr::addr_of(x)) }
            };
            let liberated_value = move *addr;
            cast::forget(move p);
            move liberated_value
        }
    }

    pub fn init() -> (client::ping, server::ping) {
        ::pipes::entangle()
    }

    pub mod client {
        use core::option;
        use pingpong;

        pub type ping = ::pipes::send_packet<pingpong::ping>;
        pub type pong = ::pipes::recv_packet<pingpong::pong>;

        pub fn do_ping(-c: ping) -> pong {
            let (sp, rp) = ::pipes::entangle();

            ::pipes::send(move c, pingpong::ping(move sp));
            move rp
        }

        pub fn do_pong(-c: pong) -> (ping, ()) {
            let packet = ::pipes::recv(move c);
            if packet.is_none() {
                fail ~"sender closed the connection"
            }
            (pingpong::liberate_pong(option::unwrap(move packet)), ())
        }
    }

    pub mod server {
        use pingpong;

        pub type ping = ::pipes::recv_packet<pingpong::ping>;
        pub type pong = ::pipes::send_packet<pingpong::pong>;

        pub fn do_ping(-c: ping) -> (pong, ()) {
            let packet = ::pipes::recv(move c);
            if packet.is_none() {
                fail ~"sender closed the connection"
            }
            (pingpong::liberate_ping(option::unwrap(move packet)), ())
        }

        pub fn do_pong(-c: pong) -> ping {
            let (sp, rp) = ::pipes::entangle();
            ::pipes::send(move c, pingpong::pong(move sp));
            move rp
        }
    }
}

fn client(-chan: pingpong::client::ping) {
    let chan = pingpong::client::do_ping(move chan);
    log(error, ~"Sent ping");
    let (_chan, _data) = pingpong::client::do_pong(move chan);
    log(error, ~"Received pong");
}

fn server(-chan: pingpong::server::ping) {
    let (chan, _data) = pingpong::server::do_ping(move chan);
    log(error, ~"Received ping");
    let _chan = pingpong::server::do_pong(move chan);
    log(error, ~"Sent pong");
}

fn main() {
  /*
//    Commented out because of option::get error

    let (client_, server_) = pingpong::init();
    let client_ = ~mut some(client_);
    let server_ = ~mut some(server_);

    task::spawn {|move client_|
        let mut client__ = none;
        *client_ <-> client__;
        client(option::unwrap(client__));
    };
    task::spawn {|move server_|
        let mut server_ˊ = none;
        *server_ <-> server_ˊ;
        server(option::unwrap(server_ˊ));
    };
  */
}
<commit_msg>Fix Option camel case in commented portion of test<commit_after>// xfail-fast

// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// tjc: I don't know why
pub mod pipes {
    use core::cast::{forget, transmute};

    pub enum state {
        empty,
        full,
        blocked,
        terminated
    }

    pub impl state : cmp::Eq {
        pure fn eq(&self, other: &state) -> bool {
            ((*self) as uint) == ((*other) as uint)
        }
        pure fn ne(&self, other: &state) -> bool { !(*self).eq(other) }
    }

    pub type packet<T: Owned> = {
        mut state: state,
        mut blocked_task: Option<task::Task>,
        mut payload: Option<T>
    };

    pub fn packet<T: Owned>() -> *packet<T> {
        unsafe {
            let p: *packet<T> = cast::transmute(~{
                mut state: empty,
                mut blocked_task: None::<task::Task>,
                mut payload: None::<T>
            });
            p
        }
    }

    #[abi = "rust-intrinsic"]
    mod rusti {
      pub fn atomic_xchg(_dst: &mut int, _src: int) -> int { fail; }
      pub fn atomic_xchg_acq(_dst: &mut int, _src: int) -> int { fail; }
      pub fn atomic_xchg_rel(_dst: &mut int, _src: int) -> int { fail; }
    }

    // We should consider moving this to ::core::unsafe, although I
    // suspect graydon would want us to use void pointers instead.
    pub unsafe fn uniquify<T>(+x: *T) -> ~T {
        unsafe { cast::transmute(move x) }
    }

    pub fn swap_state_acq(+dst: &mut state, src: state) -> state {
        unsafe {
            transmute(rusti::atomic_xchg_acq(transmute(move dst), src as int))
        }
    }

    pub fn swap_state_rel(+dst: &mut state, src: state) -> state {
        unsafe {
            transmute(rusti::atomic_xchg_rel(transmute(move dst), src as int))
        }
    }

    pub fn send<T: Owned>(-p: send_packet<T>, -payload: T) {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        assert (*p).payload.is_none();
        (*p).payload = move Some(move payload);
        let old_state = swap_state_rel(&mut (*p).state, full);
        match old_state {
          empty => {
            // Yay, fastpath.

            // The receiver will eventually clean this up.
            unsafe { forget(move p); }
          }
          full => { fail ~"duplicate send" }
          blocked => {

            // The receiver will eventually clean this up.
            unsafe { forget(move p); }
          }
          terminated => {
            // The receiver will never receive this. Rely on drop_glue
            // to clean everything up.
          }
        }
    }

    pub fn recv<T: Owned>(-p: recv_packet<T>) -> Option<T> {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        loop {
            let old_state = swap_state_acq(&mut (*p).state,
                                           blocked);
            match old_state {
              empty | blocked => { task::yield(); }
              full => {
                let mut payload = None;
                payload <-> (*p).payload;
                return Some(option::unwrap(move payload))
              }
              terminated => {
                assert old_state == terminated;
                return None;
              }
            }
        }
    }

    pub fn sender_terminate<T: Owned>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        match swap_state_rel(&mut (*p).state, terminated) {
          empty | blocked => {
            // The receiver will eventually clean up.
            unsafe { forget(move p) }
          }
          full => {
            // This is impossible
            fail ~"you dun goofed"
          }
          terminated => {
            // I have to clean up, use drop_glue
          }
        }
    }

    pub fn receiver_terminate<T: Owned>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        match swap_state_rel(&mut (*p).state, terminated) {
          empty => {
            // the sender will clean up
            unsafe { forget(move p) }
          }
          blocked => {
            // this shouldn't happen.
            fail ~"terminating a blocked packet"
          }
          terminated | full => {
            // I have to clean up, use drop_glue
          }
        }
    }

    pub struct send_packet<T: Owned> {
        mut p: Option<*packet<T>>,
    }

    pub impl<T: Owned> send_packet<T> : Drop {
        fn finalize(&self) {
            if self.p != None {
                let mut p = None;
                p <-> self.p;
                sender_terminate(option::unwrap(move p))
            }
        }
    }

    pub impl<T: Owned> send_packet<T> {
        fn unwrap() -> *packet<T> {
            let mut p = None;
            p <-> self.p;
            option::unwrap(move p)
        }
    }

    pub fn send_packet<T: Owned>(p: *packet<T>) -> send_packet<T> {
        send_packet {
            p: Some(p)
        }
    }

    pub struct recv_packet<T: Owned> {
        mut p: Option<*packet<T>>,
    }

    pub impl<T: Owned> recv_packet<T> : Drop {
        fn finalize(&self) {
            if self.p != None {
                let mut p = None;
                p <-> self.p;
                receiver_terminate(option::unwrap(move p))
            }
        }
    }

    pub impl<T: Owned> recv_packet<T> {
        fn unwrap() -> *packet<T> {
            let mut p = None;
            p <-> self.p;
            option::unwrap(move p)
        }
    }

    pub fn recv_packet<T: Owned>(p: *packet<T>) -> recv_packet<T> {
        recv_packet {
            p: Some(p)
        }
    }

    pub fn entangle<T: Owned>() -> (send_packet<T>, recv_packet<T>) {
        let p = packet();
        (send_packet(p), recv_packet(p))
    }
}

pub mod pingpong {
    use core::cast;
    use core::ptr;

    pub enum ping = ::pipes::send_packet<pong>;
    pub enum pong = ::pipes::send_packet<ping>;

    pub fn liberate_ping(-p: ping) -> ::pipes::send_packet<pong> {
        unsafe {
            let addr : *::pipes::send_packet<pong> = match &p {
              &ping(ref x) => { cast::transmute(ptr::addr_of(x)) }
            };
            let liberated_value = move *addr;
            cast::forget(move p);
            move liberated_value
        }
    }

    pub fn liberate_pong(-p: pong) -> ::pipes::send_packet<ping> {
        unsafe {
            let addr : *::pipes::send_packet<ping> = match &p {
              &pong(ref x) => { cast::transmute(ptr::addr_of(x)) }
            };
            let liberated_value = move *addr;
            cast::forget(move p);
            move liberated_value
        }
    }

    pub fn init() -> (client::ping, server::ping) {
        ::pipes::entangle()
    }

    pub mod client {
        use core::option;
        use pingpong;

        pub type ping = ::pipes::send_packet<pingpong::ping>;
        pub type pong = ::pipes::recv_packet<pingpong::pong>;

        pub fn do_ping(-c: ping) -> pong {
            let (sp, rp) = ::pipes::entangle();

            ::pipes::send(move c, pingpong::ping(move sp));
            move rp
        }

        pub fn do_pong(-c: pong) -> (ping, ()) {
            let packet = ::pipes::recv(move c);
            if packet.is_none() {
                fail ~"sender closed the connection"
            }
            (pingpong::liberate_pong(option::unwrap(move packet)), ())
        }
    }

    pub mod server {
        use pingpong;

        pub type ping = ::pipes::recv_packet<pingpong::ping>;
        pub type pong = ::pipes::send_packet<pingpong::pong>;

        pub fn do_ping(-c: ping) -> (pong, ()) {
            let packet = ::pipes::recv(move c);
            if packet.is_none() {
                fail ~"sender closed the connection"
            }
            (pingpong::liberate_ping(option::unwrap(move packet)), ())
        }

        pub fn do_pong(-c: pong) -> ping {
            let (sp, rp) = ::pipes::entangle();
            ::pipes::send(move c, pingpong::pong(move sp));
            move rp
        }
    }
}

fn client(-chan: pingpong::client::ping) {
    let chan = pingpong::client::do_ping(move chan);
    log(error, ~"Sent ping");
    let (_chan, _data) = pingpong::client::do_pong(move chan);
    log(error, ~"Received pong");
}

fn server(-chan: pingpong::server::ping) {
    let (chan, _data) = pingpong::server::do_ping(move chan);
    log(error, ~"Received ping");
    let _chan = pingpong::server::do_pong(move chan);
    log(error, ~"Sent pong");
}

fn main() {
  /*
//    Commented out because of option::get error

    let (client_, server_) = pingpong::init();
    let client_ = ~mut Some(client_);
    let server_ = ~mut Some(server_);

    task::spawn {|move client_|
        let mut client__ = none;
        *client_ <-> client__;
        client(option::unwrap(client__));
    };
    task::spawn {|move server_|
        let mut server_ˊ = none;
        *server_ <-> server_ˊ;
        server(option::unwrap(server_ˊ));
    };
  */
}
<|endoftext|>


<commit_before>struct thing<Q> {
    x: &Q
}

fn thing<Q>(x: &Q) -> thing<Q> {
    thing{ x: x }
}

fn main() {
    thing(&());
}<commit_msg>Remove compile-fail test from run-pass<commit_after><|endoftext|>


<commit_before>use graphics::{DrawState, Transformed, rectangle};
use graphics::polygon::Polygon;
use graphics::line::Line;
use opengl_graphics::GlGraphics;
use piston::input::Key;
use rand::Rng;
use std::f64::consts::PI;
use std::ops::{Sub, Mul, Div};

fn to_cartesian(theta: f64, r: f64) -> (f64, f64) {
    return (
        theta.sin()*r,
        -theta.cos()*r,
    )
}

#[derive(Copy, Clone)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn new(x: f64, y: f64) -> Self {
        Point {
            x: x,
            y: y,
        }
    }

    fn cross(self, other: Point) -> f64 {
        return self.x*other.y - other.x*self.y;
    }

    fn dot(self, other: Point) -> f64 {
        return self.x*other.x + self.y*other.y;
    }
}

impl Sub<Point> for Point {
    type Output = Point;

    fn sub(self, other: Point) -> Self::Output {
        return Point{
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl Div<f64> for Point {
    type Output = Point;

    fn div(self, other: f64) -> Self::Output {
        return Point{
            x: self.x / other,
            y: self.y / other,
        }
    }
}

// Intersection of p, p+r and q, q+s
// p + t r = q + u s
// t = ((q − p) × s) / (r × s)
// u = ((q − p) × r) / (r × s)

fn lines_intersect(l1: [f64; 4], l2: [f64; 4]) -> bool {
    let p = Point::new(l1[0], l1[1]);
    let q = Point::new(l2[0], l2[1]);
    let r = Point::new(l1[2] - l1[0], l1[3] - l1[1]);
    let s = Point::new(l2[2] - l2[0], l2[3] - l2[1]);

    //If r × s = 0 and (q − p) × r = 0, then the two lines are collinear.
    if (r.cross(s) == 0.0 && (p - q).cross(r) == 0.0) {
        // If the interval between t0 and t1 intersects the interval [0, 1] then the line segments are collinear and overlapping; otherwise they are collinear and disjoint.
        // Note that if s and r point in opposite directions, then s · r < 0 and so the interval to be checked is [t1, t0] rather than [t0, t1].
        //t0 = (q − p) · r / (r · r)
        //t1 = (q + s − p) · r / (r · r) = t0 + s · r / (r · r)
        let t0 = (q - p).dot(r / r.dot(r));
        let t1 = t0 + s.dot(r / r.dot(r));
        return !(t0 <= 0.0 && t1 <= 0.0 || t0 >= 1.0 && t1 >= 1.0)
    }

    // If r × s = 0 and (q − p) × r ≠ 0, then the two lines are parallel and non-intersecting.
    if (r.cross(s) == 0.0) {
        return false;
    }

    // t = (q − p) × s / (r × s)
    // u = (p − q) × r / (s × r)
    let t = (q - p).cross(s / (r.cross(s)));
    let u = (p - q).cross(r / (s.cross(r)));

    // If r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t r = q + u s.
    return 0.0 <= t && t <= 1.0 && 0.0 <= u && u <= 1.0;
}

pub struct Spaceship {
    x: f64,
    y: f64,
    v: f64,
    v_theta: f64,
    theta: f64,
    accel: f64,
    reverse: f64,
    left: f64,
    right: f64,
    firing: bool,
    cooldown: f64,
}

const SPACESHIP_POINTS: [[f64; 2]; 3] = [
    [5.0, 7.0],
    [-5.0, 7.0],
    [0.0, -13.0],
];

impl Spaceship {
    pub fn new() -> Spaceship {
        return Spaceship{
            x: 100.0,
            y: 100.0,
            v: 0.0,
            v_theta: 0.0,
            theta: 0.0,
            accel: 0.0,
            reverse: 0.0,
            left: 0.0,
            right: 0.0,
            firing: false,
            cooldown: 0.0,
        };
    }

    pub fn handle_press(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 1.0,
            Key::Down => self.reverse = 1.0,
            Key::Left => self.left = 0.05,
            Key::Right => self.right = 0.05,
            Key::Space => self.firing = true,
            _ => (),
        }
    }

    pub fn handle_release(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 0.0,
            Key::Down => self.reverse = 0.0,
            Key::Left => self.left = 0.0,
            Key::Right => self.right = 0.0,
            Key::Space => self.firing = false,
            _ => (),
        }
    }

    pub fn draw(&mut self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        Polygon::new(color).draw(
            &SPACESHIP_POINTS,
            ds,
            t
                .trans(self.x, self.y)
                .rot_rad(self.theta),
            gl,
        );
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let (dx, dy) = to_cartesian(self.v_theta, self.v*dt);
        self.x = (self.x + dx + x_max) % x_max;
        self.y = (self.y + dy + y_max) % y_max;
    }

    pub fn accelerate(&mut self, dt: f64) {
        let net_accel = (self.accel - self.reverse)*dt*100.0;
        let (dx, dy) = to_cartesian(self.v_theta, self.v);
        let (ddx, ddy) = to_cartesian(self.theta, net_accel);
        let new_dx = dx + ddx;
        let new_dy = dy + ddy;
        self.v = (new_dx*new_dx+new_dy*new_dy).sqrt().min(200.0).max(-200.0);
        self.v_theta = new_dx.atan2(-new_dy);
    }

    pub fn turn(&mut self, dt: f64) {
        self.theta += (self.right - self.left)*dt*100.0;
    }

    pub fn cooldown(&mut self, dt: f64) {
        self.cooldown = (self.cooldown - dt).max(0.0);
    }

    pub fn ready_to_fire(&self) -> bool {
        return self.cooldown == 0.0;
    }

    pub fn is_firing(&self) -> bool {
        return self.firing;
    }

    pub fn fire(&mut self, bullets: &mut Vec<Bullet>) {
        self.cooldown = 0.5;
        bullets.push(Bullet::new(self.x, self.y, self.theta));
    }
}

pub struct Bullet {
    x: f64,
    y: f64,
    theta: f64,
    distance: f64,
}

impl Bullet {
    fn new(x: f64, y: f64, theta: f64) -> Bullet {
        return Bullet{
            x: x,
            y: y,
            theta: theta,
            distance: 0.0,
        };
    }

    pub fn draw(&self, color: [f32; 4], t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        rectangle(color, rectangle::square(self.x, self.y, 2.0), t, gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let v = 100.0;
        self.x = (self.x + self.theta.sin()*v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*v*dt + y_max) % y_max;
        self.distance += v*dt;
    }

    pub fn is_alive(&self) -> bool {
        return self.distance < 100.0;
    }
}

pub struct Astroid {
    x: f64,
    y: f64,
    v: f64,
    theta: f64,
    border: Vec<[f64; 4]>,
}

impl Astroid {
    pub fn new<R: Rng>(rng: &mut R) -> Astroid {
        let radius = (rng.gen_range(1, 3)*5) as f64;
        return Astroid {
            x: rng.gen_range(0.0, 100.0),
            y: rng.gen_range(0.0, 100.0),
            v: rng.gen_range(40.0, 60.0),
            theta: rng.gen_range(0.0, 2.0*PI),
            border: Astroid::create_border(rng, radius),
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        let line_info = Line::new(color, 0.5);
        for line_points in self.border.iter() {
            line_info.draw(*line_points, ds, t.trans(self.x, self.y), gl);
        }
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.x = (self.x + self.theta.sin()*self.v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*self.v*dt + y_max) % y_max;
    }

    pub fn create_border<R: Rng>(rng: &mut R, radius: f64) -> Vec<[f64; 4]> {
        let spread = radius/5.0;
        let point_count = rng.gen_range(8, 12);
        let mut points = Vec::with_capacity(point_count);
        let theta_0 = rng.gen_range(0.0, 2.0*PI);
        for theta in (1..point_count+1).map(|i| theta_0 + 2.0*PI*i as f64/point_count as f64) {
            let distance = radius + rng.gen_range(-spread, spread);
            points.push(to_cartesian(theta, distance));
        };
        let point = points[0];
        points.push(point);
        let mut lines = Vec::with_capacity(point_count);
        for point in points.iter().zip(points.iter().skip(1)) {
            let (&(x1, x2), &(y1, y2)) = point;
            lines.push([x1, x2, y1, y2]);
        }
        return lines;
    }

    pub fn is_collision(&self, bullet_path: [f64; 4]) -> bool {
        return false;
    }
}<commit_msg>Added tests for the line intersection<commit_after>use graphics::{DrawState, Transformed, rectangle};
use graphics::polygon::Polygon;
use graphics::line::Line;
use opengl_graphics::GlGraphics;
use piston::input::Key;
use rand::Rng;
use std::f64::consts::PI;
use std::ops::{Sub, Mul, Div};

fn to_cartesian(theta: f64, r: f64) -> (f64, f64) {
    return (
        theta.sin()*r,
        -theta.cos()*r,
    )
}

#[derive(Copy, Clone)]
struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn new(x: f64, y: f64) -> Self {
        Point {
            x: x,
            y: y,
        }
    }

    fn cross(self, other: Point) -> f64 {
        return self.x*other.y - other.x*self.y;
    }

    fn dot(self, other: Point) -> f64 {
        return self.x*other.x + self.y*other.y;
    }
}

impl Sub<Point> for Point {
    type Output = Point;

    fn sub(self, other: Point) -> Self::Output {
        return Point{
            x: self.x - other.x,
            y: self.y - other.y,
        }
    }
}

impl Div<f64> for Point {
    type Output = Point;

    fn div(self, other: f64) -> Self::Output {
        return Point{
            x: self.x / other,
            y: self.y / other,
        }
    }
}

// Intersection of p, p+r and q, q+s
// p + t r = q + u s
// t = ((q − p) × s) / (r × s)
// u = ((q − p) × r) / (r × s)

fn lines_intersect(l1: [f64; 4], l2: [f64; 4]) -> bool {
    let p = Point::new(l1[0], l1[1]);
    let q = Point::new(l2[0], l2[1]);
    let r = Point::new(l1[2] - l1[0], l1[3] - l1[1]);
    let s = Point::new(l2[2] - l2[0], l2[3] - l2[1]);

    //If r × s = 0 and (q − p) × r = 0, then the two lines are collinear.
    if (r.cross(s) == 0.0 && (p - q).cross(r) == 0.0) {
        // If the interval between t0 and t1 intersects the interval [0, 1] then the line segments are collinear and overlapping; otherwise they are collinear and disjoint.
        // Note that if s and r point in opposite directions, then s · r < 0 and so the interval to be checked is [t1, t0] rather than [t0, t1].
        //t0 = (q − p) · r / (r · r)
        //t1 = (q + s − p) · r / (r · r) = t0 + s · r / (r · r)
        let t0 = (q - p).dot(r / r.dot(r));
        let t1 = t0 + s.dot(r / r.dot(r));
        return !(t0 < 0.0 && t1 < 0.0 || t0 > 1.0 && t1 > 1.0)
    }

    // If r × s = 0 and (q − p) × r ≠ 0, then the two lines are parallel and non-intersecting.
    if (r.cross(s) == 0.0) {
        return false;
    }

    // t = (q − p) × s / (r × s)
    // u = (p − q) × r / (s × r)
    let t = (q - p).cross(s / (r.cross(s)));
    let u = (p - q).cross(r / (s.cross(r)));

    // If r × s ≠ 0 and 0 ≤ t ≤ 1 and 0 ≤ u ≤ 1, the two line segments meet at the point p + t r = q + u s.
    return 0.0 <= t && t <= 1.0 && 0.0 <= u && u <= 1.0;
}

#[cfg(test)]
#[test]
fn test_lines_intersect() {
    let line = [-1.0, -1.0, 1.0, 1.0];
    // Two lines intersect normally
    assert!(lines_intersect(line, [1.0, -1.0, -1.0, 1.0]));
    // Two lines don't intersect at all
    assert!(!lines_intersect(line, [-2.0, -2.0, -3.0, -3.0]));
    // Two lines are parallel and don't intersect
    assert!(!lines_intersect(line, [-1.0, 0.0, 1.0, 2.0]));
    // Two lines are co-linear and overlapping
    assert!(lines_intersect(line, [-1.5, -1.5, 0.5, 0.5]));
    assert!(lines_intersect(line, [0.5, 0.5, 1.5, 1.5]));
    // Two lines are co-linear and one contains the other
    assert!(lines_intersect(line, [-2.0, -2.0, 2.0, 2.0]));
    assert!(lines_intersect(line, [-0.5, -0.5, 0.5, 0.5]));
    // Two lines are co-linear and non-overlapping
    assert!(!lines_intersect(line, [-3.0, -3.0, -2.0, -2.0]));
    assert!(!lines_intersect(line, [2.0, 2.0, 3.0, 3.0]));
    // Two lines are the same
    assert!(lines_intersect(line, line));
    // Two lines intersect at one point
    assert!(lines_intersect(line, [1.0, 1.0, 2.0, 2.0]));
    assert!(lines_intersect(line, [1.0, 1.0, 1.0, 2.0]));
    // One line's point touches the other line
    assert!(lines_intersect(line, [0.0, 2.0, 2.0, 0.0]));
}

pub struct Spaceship {
    x: f64,
    y: f64,
    v: f64,
    v_theta: f64,
    theta: f64,
    accel: f64,
    reverse: f64,
    left: f64,
    right: f64,
    firing: bool,
    cooldown: f64,
}

const SPACESHIP_POINTS: [[f64; 2]; 3] = [
    [5.0, 7.0],
    [-5.0, 7.0],
    [0.0, -13.0],
];

impl Spaceship {
    pub fn new() -> Spaceship {
        return Spaceship{
            x: 100.0,
            y: 100.0,
            v: 0.0,
            v_theta: 0.0,
            theta: 0.0,
            accel: 0.0,
            reverse: 0.0,
            left: 0.0,
            right: 0.0,
            firing: false,
            cooldown: 0.0,
        };
    }

    pub fn handle_press(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 1.0,
            Key::Down => self.reverse = 1.0,
            Key::Left => self.left = 0.05,
            Key::Right => self.right = 0.05,
            Key::Space => self.firing = true,
            _ => (),
        }
    }

    pub fn handle_release(&mut self, key: Key) {
        match key {
            Key::Up => self.accel = 0.0,
            Key::Down => self.reverse = 0.0,
            Key::Left => self.left = 0.0,
            Key::Right => self.right = 0.0,
            Key::Space => self.firing = false,
            _ => (),
        }
    }

    pub fn draw(&mut self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        Polygon::new(color).draw(
            &SPACESHIP_POINTS,
            ds,
            t
                .trans(self.x, self.y)
                .rot_rad(self.theta),
            gl,
        );
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let (dx, dy) = to_cartesian(self.v_theta, self.v*dt);
        self.x = (self.x + dx + x_max) % x_max;
        self.y = (self.y + dy + y_max) % y_max;
    }

    pub fn accelerate(&mut self, dt: f64) {
        let net_accel = (self.accel - self.reverse)*dt*100.0;
        let (dx, dy) = to_cartesian(self.v_theta, self.v);
        let (ddx, ddy) = to_cartesian(self.theta, net_accel);
        let new_dx = dx + ddx;
        let new_dy = dy + ddy;
        self.v = (new_dx*new_dx+new_dy*new_dy).sqrt().min(200.0).max(-200.0);
        self.v_theta = new_dx.atan2(-new_dy);
    }

    pub fn turn(&mut self, dt: f64) {
        self.theta += (self.right - self.left)*dt*100.0;
    }

    pub fn cooldown(&mut self, dt: f64) {
        self.cooldown = (self.cooldown - dt).max(0.0);
    }

    pub fn ready_to_fire(&self) -> bool {
        return self.cooldown == 0.0;
    }

    pub fn is_firing(&self) -> bool {
        return self.firing;
    }

    pub fn fire(&mut self, bullets: &mut Vec<Bullet>) {
        self.cooldown = 0.5;
        bullets.push(Bullet::new(self.x, self.y, self.theta));
    }
}

pub struct Bullet {
    x: f64,
    y: f64,
    theta: f64,
    distance: f64,
}

impl Bullet {
    fn new(x: f64, y: f64, theta: f64) -> Bullet {
        return Bullet{
            x: x,
            y: y,
            theta: theta,
            distance: 0.0,
        };
    }

    pub fn draw(&self, color: [f32; 4], t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        rectangle(color, rectangle::square(self.x, self.y, 2.0), t, gl);
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        let v = 100.0;
        self.x = (self.x + self.theta.sin()*v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*v*dt + y_max) % y_max;
        self.distance += v*dt;
    }

    pub fn is_alive(&self) -> bool {
        return self.distance < 100.0;
    }
}

pub struct Astroid {
    x: f64,
    y: f64,
    v: f64,
    theta: f64,
    border: Vec<[f64; 4]>,
}

impl Astroid {
    pub fn new<R: Rng>(rng: &mut R) -> Astroid {
        let radius = (rng.gen_range(1, 3)*5) as f64;
        return Astroid {
            x: rng.gen_range(0.0, 100.0),
            y: rng.gen_range(0.0, 100.0),
            v: rng.gen_range(40.0, 60.0),
            theta: rng.gen_range(0.0, 2.0*PI),
            border: Astroid::create_border(rng, radius),
        }
    }

    pub fn draw(&self, color: [f32; 4], ds: &DrawState, t: [[f64; 3]; 2], gl: &mut GlGraphics) {
        let line_info = Line::new(color, 0.5);
        for line_points in self.border.iter() {
            line_info.draw(*line_points, ds, t.trans(self.x, self.y), gl);
        }
    }

    pub fn go(&mut self, dt: f64, x_max: f64, y_max: f64) {
        self.x = (self.x + self.theta.sin()*self.v*dt + x_max) % x_max;
        self.y = (self.y - self.theta.cos()*self.v*dt + y_max) % y_max;
    }

    pub fn create_border<R: Rng>(rng: &mut R, radius: f64) -> Vec<[f64; 4]> {
        let spread = radius/5.0;
        let point_count = rng.gen_range(8, 12);
        let mut points = Vec::with_capacity(point_count);
        let theta_0 = rng.gen_range(0.0, 2.0*PI);
        for theta in (1..point_count+1).map(|i| theta_0 + 2.0*PI*i as f64/point_count as f64) {
            let distance = radius + rng.gen_range(-spread, spread);
            points.push(to_cartesian(theta, distance));
        };
        let point = points[0];
        points.push(point);
        let mut lines = Vec::with_capacity(point_count);
        for point in points.iter().zip(points.iter().skip(1)) {
            let (&(x1, x2), &(y1, y2)) = point;
            lines.push([x1, x2, y1, y2]);
        }
        return lines;
    }

    pub fn is_collision(&self, bullet_path: [f64; 4]) -> bool {
        return false;
    }
}<|endoftext|>