<commit_before>//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
//! itself is exposed at the crate root.

use crate::extern_type::ExternType;
use crate::kind::Trivial;
use crate::string::CxxString;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::marker::{PhantomData, PhantomPinned};
use core::mem;
use core::ptr;
use core::slice;

#[doc(inline)]
pub use crate::Vector;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl<T> CxxVector<T>
where
    T: VectorElement,
{
    /// Returns the number of elements in the vector.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked(pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\]][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        &*T::__get_unchecked(self, pos)
    }

    /// Returns a slice to the underlying contiguous array of elements.
    pub fn as_slice(&self) -> &[T]
    where
        T: ExternType<Kind = Trivial>,
    {
        let len = self.len();
        if len == 0 {
            // The slice::from_raw_parts in the other branch requires a nonnull
            // and properly aligned data ptr. C++ standard does not guarantee
            // that data() on a vector with size 0 would return a nonnull
            // pointer or sufficiently aligned pointer, so using it would be
            // undefined behavior. Create our own empty slice in Rust instead
            // which upholds the invariants.
            &[]
        } else {
            let ptr = unsafe { T::__get_unchecked(self, 0) };
            unsafe { slice::from_raw_parts(ptr, len) }
        }
    }

    /// Returns an iterator over elements of type `&T`.
    pub fn iter(&self) -> Iter<T> {
        Iter { v: self, index: 0 }
    }
}

/// Iterator over elements of a `CxxVector` by shared reference.
///
/// The iterator element type is `&'a T`.
pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T> IntoIterator for &'a CxxVector<T>
where
    T: VectorElement,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, T> Iterator for Iter<'a, T>
where
    T: VectorElement,
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.get(self.index);
        self.index += 1;
        next
    }
}

impl<T> Debug for CxxVector<T>
where
    T: VectorElement + Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_list().entries(self).finish()
    }
}

pub(crate) struct TypeName<T> {
    element: PhantomData<T>,
}

impl<T> TypeName<T> {
    pub const fn new() -> Self {
        TypeName {
            element: PhantomData,
        }
    }
}

impl<T> Display for TypeName<T>
where
    T: VectorElement,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "CxxVector<{}>", T::__NAME)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    const __NAME: &'static dyn Display;
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: &CxxVector<Self>, pos: usize) -> *const Self;
    fn __unique_ptr_null() -> *mut c_void;
    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void;
    unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
    unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
    unsafe fn __unique_ptr_drop(repr: *mut c_void);
}

macro_rules! impl_vector_element {
    ($segment:expr, $name:expr, $ty:ty) => {
        const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());

        unsafe impl VectorElement for $ty {
            const __NAME: &'static dyn Display = &$name;
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: &CxxVector<$ty>, pos: usize) -> *const $ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
                        fn __get_unchecked(_: &CxxVector<$ty>, _: usize) -> *const $ty;
                    }
                }
                __get_unchecked(v, pos)
            }
            fn __unique_ptr_null() -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
                        fn __unique_ptr_null(this: *mut *mut c_void);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                unsafe { __unique_ptr_null(&mut repr) }
                repr
            }
            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
                        fn __unique_ptr_raw(this: *mut *mut c_void, raw: *mut CxxVector<$ty>);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                __unique_ptr_raw(&mut repr, raw);
                repr
            }
            unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
                        fn __unique_ptr_get(this: *const *mut c_void) -> *const CxxVector<$ty>;
                    }
                }
                __unique_ptr_get(&repr)
            }
            unsafe fn __unique_ptr_release(mut repr: *mut c_void) -> *mut CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
                        fn __unique_ptr_release(this: *mut *mut c_void) -> *mut CxxVector<$ty>;
                    }
                }
                __unique_ptr_release(&mut repr)
            }
            unsafe fn __unique_ptr_drop(mut repr: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
                        fn __unique_ptr_drop(this: *mut *mut c_void);
                    }
                }
                __unique_ptr_drop(&mut repr);
            }
        }
    };
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        impl_vector_element!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

impl_vector_element!("string", "CxxString", CxxString);
<commit_msg>Make CxxVector's iterator an ExactSizeIterator<commit_after>//! Less used details of `CxxVector` are exposed in this module. `CxxVector`
//! itself is exposed at the crate root.

use crate::extern_type::ExternType;
use crate::kind::Trivial;
use crate::string::CxxString;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::marker::{PhantomData, PhantomPinned};
use core::mem;
use core::ptr;
use core::slice;

#[doc(inline)]
pub use crate::Vector;

/// Binding to C++ `std::vector<T, std::allocator<T>>`.
///
/// # Invariants
///
/// As an invariant of this API and the static analysis of the cxx::bridge
/// macro, in Rust code we can never obtain a `CxxVector` by value. Instead in
/// Rust code we will only ever look at a vector behind a reference or smart
/// pointer, as in `&CxxVector<T>` or `UniquePtr<CxxVector<T>>`.
#[repr(C, packed)]
pub struct CxxVector<T> {
    _private: [T; 0],
    _pinned: PhantomData<PhantomPinned>,
}

impl<T> CxxVector<T>
where
    T: VectorElement,
{
    /// Returns the number of elements in the vector.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::size][size].
    ///
    /// [size]: https://en.cppreference.com/w/cpp/container/vector/size
    pub fn len(&self) -> usize {
        T::__vector_size(self)
    }

    /// Returns true if the vector contains no elements.
    ///
    /// Matches the behavior of C++ [std::vector\<T\>::empty][empty].
    ///
    /// [empty]: https://en.cppreference.com/w/cpp/container/vector/empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns a reference to an element at the given position, or `None` if
    /// out of bounds.
    pub fn get(&self, pos: usize) -> Option<&T> {
        if pos < self.len() {
            Some(unsafe { self.get_unchecked(pos) })
        } else {
            None
        }
    }

    /// Returns a reference to an element without doing bounds checking.
    ///
    /// This is generally not recommended, use with caution! Calling this method
    /// with an out-of-bounds index is undefined behavior even if the resulting
    /// reference is not used.
    ///
    /// Matches the behavior of C++
    /// [std::vector\<T\>::operator\[\]][operator_at].
    ///
    /// [operator_at]: https://en.cppreference.com/w/cpp/container/vector/operator_at
    pub unsafe fn get_unchecked(&self, pos: usize) -> &T {
        &*T::__get_unchecked(self, pos)
    }

    /// Returns a slice to the underlying contiguous array of elements.
    pub fn as_slice(&self) -> &[T]
    where
        T: ExternType<Kind = Trivial>,
    {
        let len = self.len();
        if len == 0 {
            // The slice::from_raw_parts in the other branch requires a nonnull
            // and properly aligned data ptr. C++ standard does not guarantee
            // that data() on a vector with size 0 would return a nonnull
            // pointer or sufficiently aligned pointer, so using it would be
            // undefined behavior. Create our own empty slice in Rust instead
            // which upholds the invariants.
            &[]
        } else {
            let ptr = unsafe { T::__get_unchecked(self, 0) };
            unsafe { slice::from_raw_parts(ptr, len) }
        }
    }

    /// Returns an iterator over elements of type `&T`.
    pub fn iter(&self) -> Iter<T> {
        Iter { v: self, index: 0 }
    }
}

/// Iterator over elements of a `CxxVector` by shared reference.
///
/// The iterator element type is `&'a T`.
pub struct Iter<'a, T> {
    v: &'a CxxVector<T>,
    index: usize,
}

impl<'a, T> IntoIterator for &'a CxxVector<T>
where
    T: VectorElement,
{
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

impl<'a, T> Iterator for Iter<'a, T>
where
    T: VectorElement,
{
    type Item = &'a T;

    fn next(&mut self) -> Option<Self::Item> {
        let next = self.v.get(self.index);
        self.index += next.is_some() as usize;
        next
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl<'a, T> ExactSizeIterator for Iter<'a, T>
where
    T: VectorElement,
{
    fn len(&self) -> usize {
        self.v.len() - self.index
    }
}

impl<T> Debug for CxxVector<T>
where
    T: VectorElement + Debug,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.debug_list().entries(self).finish()
    }
}

pub(crate) struct TypeName<T> {
    element: PhantomData<T>,
}

impl<T> TypeName<T> {
    pub const fn new() -> Self {
        TypeName {
            element: PhantomData,
        }
    }
}

impl<T> Display for TypeName<T>
where
    T: VectorElement,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "CxxVector<{}>", T::__NAME)
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
#[doc(hidden)]
pub unsafe trait VectorElement: Sized {
    const __NAME: &'static dyn Display;
    fn __vector_size(v: &CxxVector<Self>) -> usize;
    unsafe fn __get_unchecked(v: &CxxVector<Self>, pos: usize) -> *const Self;
    fn __unique_ptr_null() -> *mut c_void;
    unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void;
    unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self>;
    unsafe fn __unique_ptr_release(repr: *mut c_void) -> *mut CxxVector<Self>;
    unsafe fn __unique_ptr_drop(repr: *mut c_void);
}

macro_rules! impl_vector_element {
    ($segment:expr, $name:expr, $ty:ty) => {
        const_assert_eq!(1, mem::align_of::<CxxVector<$ty>>());

        unsafe impl VectorElement for $ty {
            const __NAME: &'static dyn Display = &$name;
            fn __vector_size(v: &CxxVector<$ty>) -> usize {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$size")]
                        fn __vector_size(_: &CxxVector<$ty>) -> usize;
                    }
                }
                unsafe { __vector_size(v) }
            }
            unsafe fn __get_unchecked(v: &CxxVector<$ty>, pos: usize) -> *const $ty {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$std$vector$", $segment, "$get_unchecked")]
                        fn __get_unchecked(_: &CxxVector<$ty>, _: usize) -> *const $ty;
                    }
                }
                __get_unchecked(v, pos)
            }
            fn __unique_ptr_null() -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$null")]
                        fn __unique_ptr_null(this: *mut *mut c_void);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                unsafe { __unique_ptr_null(&mut repr) }
                repr
            }
            unsafe fn __unique_ptr_raw(raw: *mut CxxVector<Self>) -> *mut c_void {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$raw")]
                        fn __unique_ptr_raw(this: *mut *mut c_void, raw: *mut CxxVector<$ty>);
                    }
                }
                let mut repr = ptr::null_mut::<c_void>();
                __unique_ptr_raw(&mut repr, raw);
                repr
            }
            unsafe fn __unique_ptr_get(repr: *mut c_void) -> *const CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$get")]
                        fn __unique_ptr_get(this: *const *mut c_void) -> *const CxxVector<$ty>;
                    }
                }
                __unique_ptr_get(&repr)
            }
            unsafe fn __unique_ptr_release(mut repr: *mut c_void) -> *mut CxxVector<Self> {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$release")]
                        fn __unique_ptr_release(this: *mut *mut c_void) -> *mut CxxVector<$ty>;
                    }
                }
                __unique_ptr_release(&mut repr)
            }
            unsafe fn __unique_ptr_drop(mut repr: *mut c_void) {
                extern "C" {
                    attr! {
                        #[link_name = concat!("cxxbridge1$unique_ptr$std$vector$", $segment, "$drop")]
                        fn __unique_ptr_drop(this: *mut *mut c_void);
                    }
                }
                __unique_ptr_drop(&mut repr);
            }
        }
    };
}

macro_rules! impl_vector_element_for_primitive {
    ($ty:ident) => {
        impl_vector_element!(stringify!($ty), stringify!($ty), $ty);
    };
}

impl_vector_element_for_primitive!(u8);
impl_vector_element_for_primitive!(u16);
impl_vector_element_for_primitive!(u32);
impl_vector_element_for_primitive!(u64);
impl_vector_element_for_primitive!(usize);
impl_vector_element_for_primitive!(i8);
impl_vector_element_for_primitive!(i16);
impl_vector_element_for_primitive!(i32);
impl_vector_element_for_primitive!(i64);
impl_vector_element_for_primitive!(isize);
impl_vector_element_for_primitive!(f32);
impl_vector_element_for_primitive!(f64);

impl_vector_element!("string", "CxxString", CxxString);
<|endoftext|>


<commit_before>pub trait Dominate<Rhs=Self> {
    fn dominates(&self, other: &Rhs) -> bool;
}

/// Stop after we have found `n` solutions. As we include the whole pareto
/// front, there are probably more solutions returned.
pub fn fast_non_dominated_sort<P: Dominate>(solutions: &[P], n: usize) -> Vec<Vec<usize>> {
    let mut fronts: Vec<Vec<usize>> = Vec::new();
    let mut current_front = Vec::new();

    let mut domination_count: Vec<usize> = (0..solutions.len()).map(|_| 0).collect();
    let mut dominated_solutions: Vec<Vec<usize>> = (0..solutions.len())
                                                       .map(|_| Vec::new())
                                                       .collect();
    let mut found_solutions: usize = 0;

    for (i, p) in solutions.iter().enumerate() {
        for (j, q) in solutions.iter().enumerate() {
            if i == j {
                continue;
            }
            if p.dominates(q) {
                // Add `q` to the set of solutions dominated by `p`.
                dominated_solutions[i].push(j);
            } else if q.dominates(p) {
                // Increment domination counter of `p`.
                domination_count[i] += 1;
            }
        }

        if domination_count[i] == 0 {
            // `p` belongs to the first front as it is not dominated by any
            // other solution.
            current_front.push(i);
        }
    }

    while !current_front.is_empty() {
        found_solutions += current_front.len();
        if found_solutions >= n {
            fronts.push(current_front);
            break;
        } else {
            // we haven't found enough solutions yet.
            let mut next_front = Vec::new();
            for &p_i in current_front.iter() {
                for &q_i in dominated_solutions[p_i].iter() {
                    domination_count[q_i] -= 1;
                    if domination_count[q_i] == 0 {
                        // q belongs to the next front
                        next_front.push(q_i);
                    }
                }
            }
            fronts.push(current_front);
            current_front = next_front;
        }
    }

    return fronts;
}
<commit_msg>Add test case for non dominated sort<commit_after>/// The (minimum) dominance relation.

pub trait Dominate<Rhs=Self> {
    fn dominates(&self, other: &Rhs) -> bool;
}

/// Perform a non dominated sort of the `solutions`.
///
/// Stop after we have found `n` solutions. As we include the whole pareto front, there are
/// probably more solutions returned.

pub fn fast_non_dominated_sort<P: Dominate>(solutions: &[P], n: usize) -> Vec<Vec<usize>> {
    let mut fronts: Vec<Vec<usize>> = Vec::new();
    let mut current_front = Vec::new();

    let mut domination_count: Vec<usize> = (0..solutions.len()).map(|_| 0).collect();
    let mut dominated_solutions: Vec<Vec<usize>> = (0..solutions.len())
                                                       .map(|_| Vec::new())
                                                       .collect();
    let mut found_solutions: usize = 0;

    for (i, p) in solutions.iter().enumerate() {
        for (j, q) in solutions.iter().enumerate() {
            if i == j {
                continue;
            }
            if p.dominates(q) {
                // Add `q` to the set of solutions dominated by `p`.
                dominated_solutions[i].push(j);
            } else if q.dominates(p) {
                // Increment domination counter of `p`.
                domination_count[i] += 1;
            }
        }

        if domination_count[i] == 0 {
            // `p` belongs to the first front as it is not dominated by any
            // other solution.
            current_front.push(i);
        }
    }

    while !current_front.is_empty() {
        found_solutions += current_front.len();
        if found_solutions >= n {
            fronts.push(current_front);
            break;
        } else {
            // we haven't found enough solutions yet.
            let mut next_front = Vec::new();
            for &p_i in current_front.iter() {
                for &q_i in dominated_solutions[p_i].iter() {
                    domination_count[q_i] -= 1;
                    if domination_count[q_i] == 0 {
                        // q belongs to the next front
                        next_front.push(q_i);
                    }
                }
            }
            fronts.push(current_front);
            current_front = next_front;
        }
    }

    return fronts;
}

#[cfg(test)]
mod tests {
    use super::Dominate;

    struct T(u32, u32);

    impl Dominate for T {
        fn dominates(&self, other: &Self) -> bool {
            if self.0 > other.0 || self.1 > other.1 {
                return false;
            }

            debug_assert!(self.0 <= other.0 && self.1 <= other.1);

            if self.0 < other.0 || self.1 < other.1 {
                return true;
            }

            return false;
        }
    }

    #[test]
    fn test_dominates() {
        assert_eq!(false, T(1, 2).dominates(&T(1, 2)));
        assert_eq!(false, T(1, 2).dominates(&T(2, 1)));
        assert_eq!(true, T(1, 2).dominates(&T(1, 3)));
        assert_eq!(true, T(0, 2).dominates(&T(1, 2)));
    }

    #[test]
    fn test_non_dominated_sort() {
        let solutions = vec![T(1, 2), T(1, 2), T(2, 1), T(1, 3), T(0, 2)];
        let fronts = super::fast_non_dominated_sort(&solutions, solutions.len());

        assert_eq!(3, fronts.len());
        assert_eq!(&vec![2, 4], &fronts[0]);
        assert_eq!(&vec![0, 1], &fronts[1]);
        assert_eq!(&vec![3], &fronts[2]);
    }
}
<|endoftext|>


<commit_before>#[test]
fn num_cards() {
    let deck = deck::Deck::new();
    assert_eq!(deck.cards.len(), 52);
}

#[test]
fn draw_card() {
    let mut deck = deck::Deck::new();
    let top_card_value = deck.cards.get(51).unwrap().value.clone();
    let top_card_suit = deck.cards.get(51).unwrap().suit.clone();
    let card = deck.draw().unwrap();
    assert_eq!(deck.cards.len(), 51);

    assert!(card.value != ::card::Value::None);
    assert!(card.suit != ::card::Suit::None);

    assert_eq!(card.value, top_card_value);
    assert_eq!(card.suit, top_card_suit);
}

#[test]
fn draw_too_many_cards() {
    let mut deck = deck::Deck::new();
    for i in 0..53 {
        let exists = match deck.draw() {
            None    => false,
            Some(_) => true
        };
        if i < 52 {
            assert!(exists);
        } else {
            assert!(!exists);
        }
    }
}
<commit_msg>Fixed scoping error in deck tests<commit_after>#[test]
fn num_cards() {
    let deck = ::deck::Deck::new();
    assert_eq!(deck.cards.len(), 52);
}

#[test]
fn draw_card() {
    let mut deck = ::deck::Deck::new();
    let top_card_value = deck.cards.get(51).unwrap().value.clone();
    let top_card_suit = deck.cards.get(51).unwrap().suit.clone();
    let card = deck.draw().unwrap();
    assert_eq!(deck.cards.len(), 51);

    assert!(card.value != ::card::Value::None);
    assert!(card.suit != ::card::Suit::None);

    assert_eq!(card.value, top_card_value);
    assert_eq!(card.suit, top_card_suit);
}

#[test]
fn draw_too_many_cards() {
    let mut deck = ::deck::Deck::new();
    for i in 0..53 {
        let exists = match deck.draw() {
            None    => false,
            Some(_) => true
        };
        if i < 52 {
            assert!(exists);
        } else {
            assert!(!exists);
        }
    }
}
<|endoftext|>


<commit_before>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

enum Order {
    Search(Position),
    Stop,
    Exit,
}

struct DeepeningSearcher {
    orders: Sender<Order>,
}

impl DeepeningSearcher {
    fn new(tt: Arc<TranspositionTable>) -> DeepeningSearcher {
        let (orders_tx, orders_rx) = channel();
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        thread::spawn(move || {
            search::run(&tt, commands_rx, reports_tx);
        });
        thread::spawn(move || {
            let mut pending_order = None;
            loop {
                // If there is a pending order, we take it, otherwise
                // we block and wait to receive a new one.
                match pending_order.take().unwrap_or(orders_rx.recv().unwrap()) {
                    Order::Search(position) => {
                        'depthloop: for depth in 1.. {
                            commands_tx.send(search::Command::Search {
                                           search_id: 0,
                                           position: position.clone(),
                                           depth: depth,
                                           lower_bound: -20000,
                                           upper_bound: 20000,
                                       })
                                       .unwrap();
                            loop {
                                match reports_rx.recv().unwrap() {
                                    search::Report::Progress { .. } => {
                                        if let Ok(x) = orders_rx.try_recv() {
                                            // There is a new position pending -- we
                                            // should terminate the current search.
                                            pending_order = Some(x);
                                            break 'depthloop;
                                        }
                                    }
                                    search::Report::Done { .. } => break,
                                }
                            }
                        }
                    }
                    Order::Stop => continue,
                    Order::Exit => break,
                }
            }
            commands_tx.send(search::Command::Exit).unwrap();
        });
        DeepeningSearcher { orders: orders_tx }
    }

    fn search(&mut self, p: &Position) {
        self.orders.send(Order::Search(p.clone())).unwrap();
    }

    fn stop(&mut self) {
        self.orders.send(Order::Stop).unwrap();
    }
}

impl Drop for DeepeningSearcher {
    fn drop(&mut self) {
        self.orders.send(Order::Exit).unwrap();
    }
}

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    multi_pv: usize,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    searcher: DeepeningSearcher,
    started_thinking_at: SystemTime,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            multi_pv: 1,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt.clone(),
            searcher: DeepeningSearcher::new(tt),
            started_thinking_at: SystemTime::now(),
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // We do not support re-sizing of the transposition table
            // once the engine had started, so we do nothing.
            "Hash" => (),

            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // Tells the engine to output multiple best lines.
            // the default value is `1`.)
            "MultiPV" => {
                self.multi_pv = value.parse::<usize>().ok().unwrap_or(1);
            }

            // An invalid option.
            _ => {
                self.replies.push(EngineReply::Info(vec![("string".to_string(),
                                                          format!("Invalid option \"{}\"", name))]));
            }
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.searcher.search(&self.position);
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.searcher.stop();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 5 {
            self.stop();
        }

        self.replies.pop()
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::from_u32(0);
            let mut v = Vec::with_capacity(128);
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.move16();
        }
        if m != 0 {
            let move_type = ((m & 0b1100000000000000) >> 14) as MoveType;
            let orig_square = ((m & 0b0011111100000000) >> 8) as Square;
            let dest_square = ((m & 0b0000000011111100) >> 2) as Square;
            let promoted_piece = match m & 0b11 {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 32, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<commit_msg>make run_deepening()<commit_after>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

enum Order {
    Search(Position),
    Stop,
    Exit,
}

fn run_deepening(tt: Arc<TranspositionTable>, orders_rx: Receiver<Order>) {
    thread::spawn(move || {
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let slave = thread::spawn(move || {
            search::run(&tt, commands_rx, reports_tx);
        });
        let mut pending_order = None;
        loop {
            // If there is a pending order, we take it, otherwise
            // we block and wait to receive a new one.
            match pending_order.take().unwrap_or(orders_rx.recv().unwrap()) {
                Order::Search(position) => {
                    'depthloop: for depth in 1.. {
                        commands_tx.send(search::Command::Search {
                                       search_id: 0,
                                       position: position.clone(),
                                       depth: depth,
                                       lower_bound: -20000,
                                       upper_bound: 20000,
                                   })
                                   .unwrap();
                        loop {
                            match reports_rx.recv().unwrap() {
                                search::Report::Progress { .. } => {
                                    if let Ok(x) = orders_rx.try_recv() {
                                        // There is a new position pending -- we
                                        // should terminate the current search.
                                        pending_order = Some(x);
                                        break 'depthloop;
                                    }
                                }
                                search::Report::Done { .. } => break,
                            }
                        }
                    }
                }
                Order::Stop => continue,
                Order::Exit => break,
            }
        }
        commands_tx.send(search::Command::Exit).unwrap();
        slave.join().unwrap();
    });
}

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    multi_pv: usize,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    searcher: Sender<Order>,
    started_thinking_at: SystemTime,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (orders_tx, orders_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            run_deepening(tt2, orders_rx);
        });

        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            multi_pv: 1,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt,
            searcher: orders_tx,
            started_thinking_at: SystemTime::now(),
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // We do not support re-sizing of the transposition table
            // once the engine had started, so we do nothing.
            "Hash" => (),

            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // Tells the engine to output multiple best lines.
            // the default value is `1`.)
            "MultiPV" => {
                self.multi_pv = value.parse::<usize>().ok().unwrap_or(1);
            }

            // An invalid option.
            _ => {
                self.replies.push(EngineReply::Info(vec![("string".to_string(),
                                                          format!("Invalid option \"{}\"", name))]));
            }
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.searcher.send(Order::Search(self.position.clone())).unwrap();
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.searcher.send(Order::Stop).unwrap();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 5 {
            self.stop();
        }

        self.replies.pop()
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::from_u32(0);
            let mut v = Vec::with_capacity(128);
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.move16();
        }
        if m != 0 {
            let move_type = ((m & 0b1100000000000000) >> 14) as MoveType;
            let orig_square = ((m & 0b0011111100000000) >> 8) as Square;
            let dest_square = ((m & 0b0000000011111100) >> 2) as Square;
            let promoted_piece = match m & 0b11 {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 32, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<|endoftext|>


<commit_before>use std::convert::{From, TryFrom, TryInto};
use std::str::FromStr;
use stack::Stack;
use operate::Operate;

#[derive(Debug, Copy, Clone)]
pub enum Arithm<T, O: Operate<T>> {
    Operand(T),
    Operator(O),
}

#[derive(Debug)]
pub struct Expression<T, O: Operate<T>>(Vec<Arithm<T, O>>);

impl<T: Copy, O: Operate<T> + Copy> Expression<T, O> {
    pub fn operate(&self) -> Result<T, O::Err> {
        let mut stack = Stack::new();
        for arithm in &self.0 {
            match *arithm {
                Arithm::Operand(operand) => stack.push(operand),
                Arithm::Operator(operator) => operator.operate(&mut stack)?,
            }
        }
        Ok(stack.pop().unwrap())
    }
}

#[derive(Debug, PartialEq)]
pub enum ExprResult<A, B> {
    TooManyOperands,
    NotEnoughOperand,
    InvalidToken(A, B),
}

use self::ExprResult::*;

impl<'a, T, O> TryFrom<&'a str> for Expression<T, O>
    where T: FromStr,
          O: Operate<T> + TryFrom<&'a str>
{
    type Err = ExprResult<<T as FromStr>::Err, <O as TryFrom<&'a str>>::Err>;
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        let mut expression = Vec::new();
        let mut num_operands: usize = 0;
        for token in expr.split_whitespace() {
            let arithm = match token.parse() {
                Ok(operand) => {
                    num_operands += 1;
                    Arithm::Operand(operand)
                }
                Err(operand_err) => {
                    match TryInto::<O>::try_into(token) {
                        Ok(operator) => {
                            let needed = operator.operands_needed();
                            num_operands = num_operands.checked_sub(needed)
                                .ok_or(NotEnoughOperand)?;
                            num_operands += operator.operands_generated();
                            Arithm::Operator(operator)
                        }
                        Err(operator_err) => return Err(InvalidToken(operand_err, operator_err)),
                    }
                }
            };
            expression.push(arithm);
        }
        match num_operands {
            0 => Err(NotEnoughOperand),
            1 => Ok(Expression(expression)),
            _ => Err(TooManyOperands),
        }
    }
}

impl<T, O: Operate<T>> From<Vec<Arithm<T, O>>> for Expression<T, O> {
    fn from(expr: Vec<Arithm<T, O>>) -> Self {
        Expression(expr)
    }
}
<commit_msg>expression: Add clarity<commit_after>use std::convert::{From, TryFrom, TryInto};
use std::str::FromStr;
use stack::Stack;
use operate::Operate;

#[derive(Debug, Copy, Clone)]
pub enum Arithm<T, O: Operate<T>> {
    Operand(T),
    Operator(O),
}

#[derive(Debug)]
pub struct Expression<T, O: Operate<T>>(Vec<Arithm<T, O>>);

impl<T: Copy, O: Operate<T> + Copy> Expression<T, O> {
    pub fn operate(&self) -> Result<T, O::Err> {
        let mut stack = Stack::new();
        for arithm in &self.0 {
            match *arithm {
                Arithm::Operand(operand) => stack.push(operand),
                Arithm::Operator(operator) => operator.operate(&mut stack)?,
            }
        }
        Ok(stack.pop().unwrap())
    }
}

#[derive(Debug, PartialEq)]
pub enum ExprResult<A, B> {
    TooManyOperands,
    NotEnoughOperand,
    InvalidToken(A, B),
}

use self::ExprResult::*;

impl<'a, T, O> TryFrom<&'a str> for Expression<T, O>
    where T: FromStr,
          O: Operate<T> + TryFrom<&'a str>
{
    type Err = ExprResult<<T as FromStr>::Err, <O as TryFrom<&'a str>>::Err>;
    fn try_from(expr: &'a str) -> Result<Self, Self::Err> {
        let mut final_expr = Vec::new();
        let mut num_operands: usize = 0;
        for token in expr.split_whitespace() {
            let arithm = match token.parse() {
                Ok(operand) => {
                    num_operands += 1;
                    Arithm::Operand(operand)
                }
                Err(operand_err) => {
                    match TryInto::<O>::try_into(token) {
                        Ok(operator) => {
                            let needed = operator.operands_needed();
                            num_operands = num_operands.checked_sub(needed)
                                .ok_or(NotEnoughOperand)?;
                            num_operands += operator.operands_generated();
                            Arithm::Operator(operator)
                        }
                        Err(operator_err) => return Err(InvalidToken(operand_err, operator_err)),
                    }
                }
            };
            final_expr.push(arithm);
        }
        match num_operands {
            0 => Err(NotEnoughOperand),
            1 => Ok(Expression(final_expr)),
            _ => Err(TooManyOperands),
        }
    }
}

impl<T, O: Operate<T>> From<Vec<Arithm<T, O>>> for Expression<T, O> {
    fn from(expr: Vec<Arithm<T, O>>) -> Self {
        Expression(expr)
    }
}
<|endoftext|>


<commit_before>//! Unimplemented.
<commit_msg>Finish R_ext/RS.h as ext/rs<commit_after>// automatically generated by rust-bindgen
use libc::{c_void, size_t};

pub unsafe fn Calloc(n: size_t, t: size_t) -> *mut ::libc::c_void {
    R_chk_calloc(n, t)
}

pub unsafe fn Realloc(p: *mut c_void, n: size_t, t: size_t) -> *mut c_void {
    R_chk_realloc(p, n * t)
}

pub unsafe fn Free(p: *mut c_void) -> () {
    R_chk_free(p)
}
#[link(name = "R")]
extern {
    pub fn R_chk_calloc(arg1: size_t, arg2: size_t) -> *mut ::libc::c_void;
    pub fn R_chk_realloc(arg1: *mut ::libc::c_void, arg2: size_t) -> *mut ::libc::c_void;
    pub fn R_chk_free(arg1: *mut ::libc::c_void) -> ();
    pub fn call_R(arg1: *mut ::libc::c_char,
                  arg2: ::libc::c_long,
                  arg3: *mut *mut ::libc::c_void,
                  arg4: *mut *mut ::libc::c_char,
                  arg5: *mut ::libc::c_long,
                  arg6: *mut *mut ::libc::c_char,
                  arg7: ::libc::c_long,
                  arg8: *mut *mut ::libc::c_char)
                  -> ();
}
<|endoftext|>


<commit_before>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    multi_pv: usize,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    commands: Sender<search::Command>,
    reports: Receiver<search::Report>,
    started_thinking_at: SystemTime,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            multi_pv: 1,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt,
            commands: commands_tx,
            reports: reports_rx,
            started_thinking_at: SystemTime::now(),
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // We do not support re-sizing of the transposition table
            // once the engine had started, so we do nothing.
            "Hash" => (),

            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // Tells the engine to output multiple best lines.
            // the default value is `1`.)
            "MultiPV" => {
                self.multi_pv = value.parse::<usize>().ok().unwrap_or(1);
            }

            // An invalid option.
            _ => {
                self.replies.push(EngineReply::Info(vec![("string".to_string(),
                                                          format!("Invalid option \"{}\"", name))]));
            }
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.commands
                .send(search::Command::Search {
                    search_id: 0,
                    position: self.position.clone(),
                    depth: 127,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 3 {
            self.stop();
        }

        // Empty the reports queue.
        while let Ok(_) = self.reports.try_recv() {}

        self.replies.pop()
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::from_u32(0);
            let mut v = Vec::with_capacity(128);
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.move16();
        }
        if m != 0 {
            let move_type = ((m & 0b1100000000000000) >> 14) as MoveType;
            let orig_square = ((m & 0b0011111100000000) >> 8) as Square;
            let dest_square = ((m & 0b0000000011111100) >> 2) as Square;
            let promoted_piece = match m & 0b11 {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 32, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<commit_msg>quick and dirty implementation of info pv<commit_after>pub mod search;

use std::thread;
use std::sync::Arc;
use std::sync::mpsc::{channel, Sender, Receiver};
use std::time::SystemTime;
use basetypes::*;
use uci::{UciEngine, UciEngineFactory, EngineReply, OptionName, OptionDescription};
use position::Position;
use chess_move::*;
use tt::TranspositionTable;

// use rand;
// use rand::distributions::{Sample, Range};
// let mut rng = rand::thread_rng();
// let mut between = Range::new(0, 10);
// let x = between.sample(&mut rng);

const VERSION: &'static str = "0.1";

/// Implements `UciEngine` trait.
pub struct Engine {
    position: Position,
    pondering_is_allowed: bool,
    multi_pv: usize,
    is_thinking: bool,
    is_pondering: bool,
    replies: Vec<EngineReply>,
    infinite: bool,
    tt: Arc<TranspositionTable>,
    commands: Sender<search::Command>,
    reports: Receiver<search::Report>,
    started_thinking_at: SystemTime,
    curr_depth: u8,
}

impl Engine {
    /// Creates a new instance.
    ///
    /// `tt_size_mb` is the preferred size of the transposition
    /// table in Mbytes.
    pub fn new(tt_size_mb: usize) -> Engine {
        let mut tt = TranspositionTable::new();
        tt.resize(tt_size_mb);
        let tt = Arc::new(tt);
        let (commands_tx, commands_rx) = channel();
        let (reports_tx, reports_rx) = channel();
        let tt2 = tt.clone();
        thread::spawn(move || {
            search::run_deepening(tt2, commands_rx, reports_tx);
        });

        Engine {
            position: Position::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 \
                                          1")
                          .ok()
                          .unwrap(),
            pondering_is_allowed: false,
            multi_pv: 1,
            is_thinking: false,
            is_pondering: false,
            replies: vec![],
            infinite: false,
            tt: tt,
            commands: commands_tx,
            reports: reports_rx,
            started_thinking_at: SystemTime::now(),
            curr_depth: 0,
        }
    }
}

impl UciEngine for Engine {
    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            // We do not support re-sizing of the transposition table
            // once the engine had started, so we do nothing.
            "Hash" => (),

            // Tells the engine that it will be allowed to ponder.
            // This option is needed because the engine might change
            // its time management algorithm when pondering is
            // allowed.
            "Ponder" => {
                self.pondering_is_allowed = value == "true";
            }

            // Tells the engine to output multiple best lines.
            // the default value is `1`.)
            "MultiPV" => {
                self.multi_pv = value.parse::<usize>().ok().unwrap_or(1);
            }

            // An invalid option.
            _ => {
                self.replies.push(EngineReply::Info(vec![("string".to_string(),
                                                          format!("Invalid option \"{}\"", name))]));
            }
        }
    }

    fn new_game(&mut self) {
        // Clearing the transposition table would not change anything,
        // so we do nothing.
    }

    fn position(&mut self, fen: &str, moves: &mut Iterator<Item = &str>) {
        if !self.is_thinking {
            if let Ok(p) = Position::from_history(fen, moves) {
                self.position = p;
                self.tt.new_search();
            }
        }
    }

    #[allow(unused_variables)]
    fn go(&mut self,
          searchmoves: Option<Vec<String>>,
          ponder: bool,
          wtime: Option<u64>,
          btime: Option<u64>,
          winc: Option<u64>,
          binc: Option<u64>,
          movestogo: Option<u64>,
          depth: Option<u64>,
          nodes: Option<u64>,
          mate: Option<u64>,
          movetime: Option<u64>,
          infinite: bool) {
        if !self.is_thinking {
            self.commands
                .send(search::Command::Search {
                    search_id: 0,
                    position: self.position.clone(),
                    depth: 127,
                    lower_bound: -20000,
                    upper_bound: 20000,
                })
                .unwrap();
            self.is_thinking = true;
            self.is_pondering = ponder;
            self.infinite = infinite;
            self.started_thinking_at = SystemTime::now();
            self.curr_depth = 0;
        }
    }

    fn ponder_hit(&mut self) {
        if self.is_thinking && self.is_pondering {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        if self.is_thinking {
            self.commands.send(search::Command::Stop).unwrap();
            let best_move = self.get_best_move();
            self.replies.push(EngineReply::BestMove {
                best_move: best_move,
                ponder_move: None,
            });
            self.is_thinking = false;
        }
    }

    fn is_thinking(&self) -> bool {
        self.is_thinking
    }

    fn get_reply(&mut self) -> Option<EngineReply> {
        // TODO: implement real time management here.
        if self.is_thinking && !self.is_pondering && !self.infinite &&
           self.started_thinking_at.elapsed().unwrap().as_secs() > 3 {
            self.stop();
        }

        // Empty the reports queue.
        while let Ok(report) = self.reports.try_recv() {
            // let rep_type = match report {
            //     search::Report::Progress { searched_nodes, .. } => format!("progress {}", searched_nodes),
            //     search::Report::Done { .. } => "done".to_string(),
            // };
            // self.replies.push(EngineReply::Info(vec![
            //     ("string".to_string(), rep_type),
            // ]));
            if self.is_thinking {
                match report {
                    search::Report::Progress { searched_nodes, depth, .. } => {
                        if self.curr_depth < depth {
                            self.curr_depth = depth;
                            let mut p = self.position.clone();
                            let mut v = Vec::with_capacity(128);
                            let mut pv = String::from("");
                            let mut value = None;
                            for _ in 0..depth {
                                let m = match self.tt.probe(p.hash()) {
                                    Some(entry) => {
                                        if value.is_none() {
                                            value = Some(entry.value());
                                        }
                                        entry.move16()
                                    }
                                    None => 0,
                                };
                                if m != 0 {
                                    self.position.generate_moves(&mut v);
                                    while let Some(x) = v.pop() {
                                        if x.move16() == m && p.do_move(x) {
                                            pv.push_str(&x.notation());
                                            pv.push(' ');
                                            v.clear();
                                            break;
                                        }
                                    }
                                }
                            }
                            let duration = self.started_thinking_at.elapsed().unwrap();
                            let elapsed_time_milis = 1000 * duration.as_secs() +
                                                     (duration.subsec_nanos() / 1000000) as u64;
                            self.replies.push(EngineReply::Info(vec![
                            ("multipv".to_string(), "1".to_string()),
                            ("depth".to_string(), format!("{}", depth)),
                            ("score".to_string(), format!("cp {}", value.unwrap_or(666))),
                            ("nodes".to_string(), format!("{}", searched_nodes)),
                            ("time".to_string(), format!("{}", elapsed_time_milis)),
                            ("pv".to_string(), format!("{}", pv)),
                        ]));
                        }
                    }
                    _ => (),
                }
            }
        }

        if self.replies.len() > 0 {
            Some(self.replies.remove(0))
        } else {
            None
        }
    }
}

impl Engine {
    fn get_best_move(&mut self) -> String {
        let mut m = match self.tt.probe(self.position.hash()) {
            Some(entry) => entry.move16(),
            None => 0,
        };
        if m == 0 {
            // Pick the first legal move.
            let mut first_legal_move = Move::from_u32(0);
            let mut v = Vec::with_capacity(128);
            self.position.generate_moves(&mut v);
            while let Some(x) = v.pop() {
                if self.position.do_move(x) {
                    self.position.undo_move();
                    first_legal_move = x;
                    break;
                }
            }
            m = first_legal_move.move16();
        }
        if m != 0 {
            let move_type = ((m & 0b1100000000000000) >> 14) as MoveType;
            let orig_square = ((m & 0b0011111100000000) >> 8) as Square;
            let dest_square = ((m & 0b0000000011111100) >> 2) as Square;
            let promoted_piece = match m & 0b11 {
                0 => "q",
                1 => "r",
                2 => "b",
                3 => "n",
                _ => panic!("invalid promoted piece code"),
            };
            format!("{}{}{}",
                    notation(orig_square),
                    notation(dest_square),
                    if move_type == MOVE_PROMOTION {
                        promoted_piece
                    } else {
                        ""
                    })

        } else {
            "0000".to_string()
        }
    }
}

/// Implements `UciEngineFactory` trait.
pub struct EngineFactory;

impl UciEngineFactory<Engine> for EngineFactory {
    fn name(&self) -> String {
        format!("Alcibiades {}", VERSION)
    }

    fn author(&self) -> String {
        "Evgeni Pandurski".to_string()
    }

    fn options(&self) -> Vec<(OptionName, OptionDescription)> {
        vec![
            // TODO: Calculate a sane limit for the hash size.
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 2048, default: 16 }),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
            ("MultiPV".to_string(), OptionDescription::Spin { min: 1, max: 32, default: 1 }),
        ]
    }

    fn create(&self, hash_size_mb: Option<usize>) -> Engine {
        Engine::new(hash_size_mb.unwrap_or(16))
    }
}
<|endoftext|>


<commit_before>use error::RuntimeError;
use application::OsApplication;
use renderer::Renderer;
use frame::Frame;
use event::Event;

pub struct EventLoop<'a> {
   pub os_application: &'a OsApplication,
}

impl<'a> EventLoop<'a> {
   pub fn new(os_application: &'a OsApplication) -> Self {
      EventLoop {
         os_application: os_application,
      }
   }

   pub fn run(&self, renderer: &mut Renderer, width: u32, height: u32) -> Result<(), RuntimeError> {
      renderer.init(width, height);

      let mut frame = Frame::new(width, height);

      let mut quit = false;

      loop {
         let mut new_width = frame.width;
         let mut new_height = frame.height;

         for event in self.os_application.poll_events() {
            match event {
               Event::Resized(width, height) => {
                  new_width = width;
                  new_height = height;
               },

               Event::MouseMoved(x, y) => {
                  renderer.mouse_moved(x, new_height as i32 - y - 1);
               },

               Event::Quit => {
                  quit = true;
                  break
               },

               _ => {
                  self.match_more_events(event, renderer)
               }
            }
         }

         if quit {
            break
         }

         if new_width != frame.width || new_height != frame.height {
            frame.resize(new_width, new_height);
            renderer.resized(new_width, new_height);
         }

         frame.render(renderer);

         try!(self.os_application.swap_buffers());
      }

      Ok(())
   }

   #[inline]
   fn match_more_events(&self, event: Event, renderer: &mut Renderer) {
      match event {
         Event::MouseLeftButtonPressed => {
            renderer.mouse_left_button_pressed();
         },

         Event::MouseLeftButtonReleased => {
            renderer.mouse_left_button_released();
         },

         Event::MouseMiddleButtonPressed => {
            renderer.mouse_middle_button_pressed();
         },

         Event::MouseMiddleButtonReleased => {
            renderer.mouse_middle_button_released();
         },

         Event::MouseRightButtonPressed => {
            renderer.mouse_right_button_pressed();
         },

         Event::MouseRightButtonReleased => {
            renderer.mouse_right_button_released();
         },

         Event::MouseExtraButtonPressed(n) => {
            renderer.mouse_extra_button_pressed(n);
         },

         Event::MouseExtraButtonReleased(n) => {
            renderer.mouse_extra_button_released(n);
         },
      }
   }
}
<commit_msg>Fixing the event loop event matching<commit_after>use error::RuntimeError;
use application::OsApplication;
use renderer::Renderer;
use frame::Frame;
use event::Event;

pub struct EventLoop<'a> {
   pub os_application: &'a OsApplication,
}

impl<'a> EventLoop<'a> {
   pub fn new(os_application: &'a OsApplication) -> Self {
      EventLoop {
         os_application: os_application,
      }
   }

   pub fn run(&self, renderer: &mut Renderer, width: u32, height: u32) -> Result<(), RuntimeError> {
      renderer.init(width, height);

      let mut frame = Frame::new(width, height);

      let mut quit = false;

      loop {
         let mut new_width = frame.width;
         let mut new_height = frame.height;

         for event in self.os_application.poll_events() {
            match event {
               Event::Resized(width, height) => {
                  new_width = width;
                  new_height = height;
               },

               Event::MouseMoved(x, y) => {
                  renderer.mouse_moved(x, new_height as i32 - y - 1);
               },

               Event::Quit => {
                  quit = true;
                  break
               },

               _ => {
                  self.match_more_events(event, renderer)
               }
            }
         }

         if quit {
            break
         }

         if new_width != frame.width || new_height != frame.height {
            frame.resize(new_width, new_height);
            renderer.resized(new_width, new_height);
         }

         frame.render(renderer);

         try!(self.os_application.swap_buffers());
      }

      Ok(())
   }

   #[inline]
   fn match_more_events(&self, event: Event, renderer: &mut Renderer) {
      match event {
         Event::MouseLeftButtonPressed => {
            renderer.mouse_left_button_pressed();
         },

         Event::MouseLeftButtonReleased => {
            renderer.mouse_left_button_released();
         },

         Event::MouseMiddleButtonPressed => {
            renderer.mouse_middle_button_pressed();
         },

         Event::MouseMiddleButtonReleased => {
            renderer.mouse_middle_button_released();
         },

         Event::MouseRightButtonPressed => {
            renderer.mouse_right_button_pressed();
         },

         Event::MouseRightButtonReleased => {
            renderer.mouse_right_button_released();
         },

         Event::MouseExtraButtonPressed(n) => {
            renderer.mouse_extra_button_pressed(n);
         },

         Event::MouseExtraButtonReleased(n) => {
            renderer.mouse_extra_button_released(n);
         },

         _ => {
            panic!("Unhandled events");
         }
      }
   }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use core::{Vec3, Vec4, Mat3};
use geom::{Point, Point3, Ray3};

#[path = "../num_macros.rs"]
mod num_macros;

/// A plane formed from the equation: `Ax + Bx + Cx + D = 0`
///
/// # Fields
///
/// - `n`: the normal of the plane where:
///   - `n.x`: corresponds to `A` in the plane equation
///   - `n.y`: corresponds to `B` in the plane equation
///   - `n.z`: corresponds to `C` in the plane equation
/// - `d`: the distance value, corresponding to `D` in the plane equation
#[deriving(Clone, Eq)]
pub struct Plane3<T> {
    norm: Vec3<T>,
    dist: T,
}

impl<T:Clone + Float> Plane3<T> {
    /// # Arguments
    ///
    /// - `a`: the `x` component of the normal
    /// - `b`: the `y` component of the normal
    /// - `c`: the `z` component of the normal
    /// - `d`: the plane's distance value
    pub fn from_abcd(a: T, b: T, c: T, d: T) -> Plane3<T> {
        Plane3 {
            norm: Vec3::new(a, b, c),
            dist: d,
        }
    }

    /// Construct a plane from a normal vector `n` and a distance `d`
    pub fn from_nd(norm: Vec3<T>, dist: T) -> Plane3<T> {
        Plane3 { norm: norm, dist: dist }
    }

    /// Construct a plane from the components of a four-dimensional vector
    pub fn from_vec4(vec: Vec4<T>) -> Plane3<T> {
        Plane3::from_abcd(vec.x.clone(), vec.y.clone(), vec.z.clone(), vec.w.clone())
    }

    /// Compute the distance from the plane to the point
    pub fn distance(&self, pos: &Point3<T>) -> T {
        self.norm.dot(pos.as_vec()) + self.dist
    }

    /// Computes the point at which `ray` intersects the plane
    pub fn intersection_r(&self, _ray: &Ray3<T>) -> Point3<T> {
        fail!(~"not yet implemented")
    }

    /// Returns `true` if the ray intersects the plane
    pub fn intersects(&self, _ray: &Ray3<T>) -> bool {
        fail!(~"not yet implemented")
    }

    /// Returns `true` if `pos` is located behind the plane - otherwise it returns `false`
    pub fn contains(&self, pos: &Point3<T>) -> bool {
        self.distance(pos) < zero!(T)
    }
}

impl<T:Clone + Float> Plane3<T> {
    /// Constructs a plane that passes through the the three points `a`, `b` and `c`
    pub fn from_3p(a: Point3<T>,
                   b: Point3<T>,
                   c: Point3<T>) -> Option<Plane3<T>> {
        // create two vectors that run parallel to the plane
        let v0 = b.as_vec().sub_v(a.as_vec());
        let v1 = c.as_vec().sub_v(a.as_vec());
        // find the vector that is perpendicular to v1 and v2
        let mut norm = v0.cross(&v1);

        if norm.approx_eq(&Vec3::zero()) {
            None
        } else {
            // compute the normal and the distance to the plane
            norm.normalize_self();
            let dist = -a.as_vec().dot(&norm);

            Some(Plane3::from_nd(norm, dist))
        }
    }

    /// Computes the ray created from the two-plane intersection of `self` and `other`
    ///
    /// # Return value
    ///
    /// - `Some(r)`: The ray `r` where the planes intersect.
    /// - `None`: No valid intersection was found. The planes are probably parallel.
    pub fn intersection_2pl(&self, other: &Plane3<T>) -> Option<Ray3<T>> {
        let ray_dir = self.norm.cross(&other.norm);

        if ray_dir.approx_eq(&Vec3::zero::<T>()) {
            None  // the planes are parallel
        } else {
            // The end-point of the ray is at the three-plane intersection between
            // `self`, `other`, and a tempory plane positioned at the origin
            do Plane3::from_nd(ray_dir.clone(), zero!(T)).intersection_3pl(self, other).map |&ray_pos| {
                Ray3 {
                    pos: ray_pos.clone(),
                    dir: ray_dir.clone(),
                }
            }
        }
    }

    /// Computes the three-plane intersection between `self`, `other_a` and `other_b`.
    ///
    /// # Return value
    ///
    /// - `Some(p)`: The position vector `p` where the planes intersect.
    /// - `None`:    No valid intersection was found. The normals of the three
    ///              planes are probably coplanar.
    pub fn intersection_3pl(&self, other_a: &Plane3<T>, other_b: &Plane3<T>) -> Option<Point3<T>> {
        let mx = Mat3::new(self.norm.x.clone(), other_a.norm.x.clone(), other_b.norm.x.clone(),
                           self.norm.y.clone(), other_a.norm.y.clone(), other_b.norm.y.clone(),
                           self.norm.z.clone(), other_a.norm.z.clone(), other_b.norm.z.clone());
        do mx.inverse().map |m| {
            Point::from_vec(
                m.mul_v(&Vec3::new(self.dist.clone(),
                                   other_a.dist.clone(),
                                   other_b.dist.clone()))
            )
        }
    }
}

impl<T:Clone + Eq + ApproxEq<T>> ApproxEq<T> for Plane3<T> {
    #[inline]
    pub fn approx_epsilon() -> T {
        ApproxEq::approx_epsilon::<T,T>()
    }

    #[inline]
    pub fn approx_eq(&self, other: &Plane3<T>) -> bool {
        self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
    }

    #[inline]
    pub fn approx_eq_eps(&self, other: &Plane3<T>, epsilon: &T) -> bool {
        self.norm.approx_eq_eps(&other.norm, epsilon) &&
        self.dist.approx_eq_eps(&other.dist, epsilon)
    }
}

impl<T> ToStr for Plane3<T> {
    pub fn to_str(&self) -> ~str {
        fmt!("%?x + %?y + %?z + %? = 0", self.norm.x, self.norm.y, self.norm.z, self.dist)
    }
}

#[cfg(test)]
mod tests {
    use geom::plane::*;
    use geom::point::*;

    #[test]
    fn test_from_3p() {
        assert_eq!(Plane3::from_3p(Point3::new(5f, 0f,  5f),
                                   Point3::new(5f, 5f,  5f),
                                   Point3::new(5f, 0f, -1f)), Some(Plane3::from_abcd(-1f, 0f, 0f, 5f)));

        assert_eq!(Plane3::from_3p(Point3::new(0f, 5f, -5f),
                                   Point3::new(0f, 5f,  0f),
                                   Point3::new(0f, 5f,  5f)), None);     // The points are parallel
    }

    #[test]
    fn test_plane_intersection_3pl() {
        let p0 = Plane3::from_abcd(1.0,  0.0, 0.0, 1.0);
        let p1 = Plane3::from_abcd(0.0, -1.0, 0.0, 2.0);
        let p2 = Plane3::from_abcd(0.0,  0.0, 1.0, 1.0);

        assert_eq!(p0.intersection_3pl(&p1, &p2), Some(Point3::new(1.0, -2.0, 1.0)));
    }

    #[test]
    fn test_to_str() {
        assert_eq!(Plane3::from_abcd(1.0, 2.0, 3.0, 4.0).to_str(), ~"1x + 2y + 3z + 4 = 0");
    }
}
<commit_msg>Fix build error<commit_after>// Copyright 2013 The Lmath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use core::{Vec3, Vec4, Mat3};
use geom::{Point, Point3, Ray3};

#[path = "../num_macros.rs"]
mod num_macros;

/// A plane formed from the equation: `Ax + Bx + Cx + D = 0`
///
/// # Fields
///
/// - `n`: the normal of the plane where:
///   - `n.x`: corresponds to `A` in the plane equation
///   - `n.y`: corresponds to `B` in the plane equation
///   - `n.z`: corresponds to `C` in the plane equation
/// - `d`: the distance value, corresponding to `D` in the plane equation
#[deriving(Clone, Eq)]
pub struct Plane3<T> {
    norm: Vec3<T>,
    dist: T,
}

impl<T:Clone + Float> Plane3<T> {
    /// # Arguments
    ///
    /// - `a`: the `x` component of the normal
    /// - `b`: the `y` component of the normal
    /// - `c`: the `z` component of the normal
    /// - `d`: the plane's distance value
    pub fn from_abcd(a: T, b: T, c: T, d: T) -> Plane3<T> {
        Plane3 {
            norm: Vec3::new(a, b, c),
            dist: d,
        }
    }

    /// Construct a plane from a normal vector `n` and a distance `d`
    pub fn from_nd(norm: Vec3<T>, dist: T) -> Plane3<T> {
        Plane3 { norm: norm, dist: dist }
    }

    /// Construct a plane from the components of a four-dimensional vector
    pub fn from_vec4(vec: Vec4<T>) -> Plane3<T> {
        Plane3::from_abcd(vec.x.clone(), vec.y.clone(), vec.z.clone(), vec.w.clone())
    }

    /// Compute the distance from the plane to the point
    pub fn distance(&self, pos: &Point3<T>) -> T {
        self.norm.dot(pos.as_vec()) + self.dist
    }

    /// Computes the point at which `ray` intersects the plane
    pub fn intersection_r(&self, _ray: &Ray3<T>) -> Point3<T> {
        fail!(~"not yet implemented")
    }

    /// Returns `true` if the ray intersects the plane
    pub fn intersects(&self, _ray: &Ray3<T>) -> bool {
        fail!(~"not yet implemented")
    }

    /// Returns `true` if `pos` is located behind the plane - otherwise it returns `false`
    pub fn contains(&self, pos: &Point3<T>) -> bool {
        self.distance(pos) < zero!(T)
    }
}

impl<T:Clone + Float> Plane3<T> {
    /// Constructs a plane that passes through the the three points `a`, `b` and `c`
    pub fn from_3p(a: Point3<T>,
                   b: Point3<T>,
                   c: Point3<T>) -> Option<Plane3<T>> {
        // create two vectors that run parallel to the plane
        let v0 = b.as_vec().sub_v(a.as_vec());
        let v1 = c.as_vec().sub_v(a.as_vec());
        // find the vector that is perpendicular to v1 and v2
        let mut norm = v0.cross(&v1);

        if norm.approx_eq(&Vec3::zero()) {
            None
        } else {
            // compute the normal and the distance to the plane
            norm.normalize_self();
            let dist = -a.as_vec().dot(&norm);

            Some(Plane3::from_nd(norm, dist))
        }
    }

    /// Computes the ray created from the two-plane intersection of `self` and `other`
    ///
    /// # Return value
    ///
    /// - `Some(r)`: The ray `r` where the planes intersect.
    /// - `None`: No valid intersection was found. The planes are probably parallel.
    pub fn intersection_2pl(&self, other: &Plane3<T>) -> Option<Ray3<T>> {
        let ray_dir = self.norm.cross(&other.norm);

        if ray_dir.approx_eq(&Vec3::zero::<T>()) {
            None  // the planes are parallel
        } else {
            // The end-point of the ray is at the three-plane intersection between
            // `self`, `other`, and a tempory plane positioned at the origin
            do Plane3::from_nd(ray_dir.clone(), zero!(T)).intersection_3pl(self, other).map |ray_pos| {
                Ray3 {
                    pos: ray_pos.clone(),
                    dir: ray_dir.clone(),
                }
            }
        }
    }

    /// Computes the three-plane intersection between `self`, `other_a` and `other_b`.
    ///
    /// # Return value
    ///
    /// - `Some(p)`: The position vector `p` where the planes intersect.
    /// - `None`:    No valid intersection was found. The normals of the three
    ///              planes are probably coplanar.
    pub fn intersection_3pl(&self, other_a: &Plane3<T>, other_b: &Plane3<T>) -> Option<Point3<T>> {
        let mx = Mat3::new(self.norm.x.clone(), other_a.norm.x.clone(), other_b.norm.x.clone(),
                           self.norm.y.clone(), other_a.norm.y.clone(), other_b.norm.y.clone(),
                           self.norm.z.clone(), other_a.norm.z.clone(), other_b.norm.z.clone());
        do mx.inverse().map |m| {
            Point::from_vec(
                m.mul_v(&Vec3::new(self.dist.clone(),
                                   other_a.dist.clone(),
                                   other_b.dist.clone()))
            )
        }
    }
}

impl<T:Clone + Eq + ApproxEq<T>> ApproxEq<T> for Plane3<T> {
    #[inline]
    pub fn approx_epsilon() -> T {
        ApproxEq::approx_epsilon::<T,T>()
    }

    #[inline]
    pub fn approx_eq(&self, other: &Plane3<T>) -> bool {
        self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<T,T>())
    }

    #[inline]
    pub fn approx_eq_eps(&self, other: &Plane3<T>, epsilon: &T) -> bool {
        self.norm.approx_eq_eps(&other.norm, epsilon) &&
        self.dist.approx_eq_eps(&other.dist, epsilon)
    }
}

impl<T> ToStr for Plane3<T> {
    pub fn to_str(&self) -> ~str {
        fmt!("%?x + %?y + %?z + %? = 0", self.norm.x, self.norm.y, self.norm.z, self.dist)
    }
}

#[cfg(test)]
mod tests {
    use geom::plane::*;
    use geom::point::*;

    #[test]
    fn test_from_3p() {
        assert_eq!(Plane3::from_3p(Point3::new(5f, 0f,  5f),
                                   Point3::new(5f, 5f,  5f),
                                   Point3::new(5f, 0f, -1f)), Some(Plane3::from_abcd(-1f, 0f, 0f, 5f)));

        assert_eq!(Plane3::from_3p(Point3::new(0f, 5f, -5f),
                                   Point3::new(0f, 5f,  0f),
                                   Point3::new(0f, 5f,  5f)), None);     // The points are parallel
    }

    #[test]
    fn test_plane_intersection_3pl() {
        let p0 = Plane3::from_abcd(1.0,  0.0, 0.0, 1.0);
        let p1 = Plane3::from_abcd(0.0, -1.0, 0.0, 2.0);
        let p2 = Plane3::from_abcd(0.0,  0.0, 1.0, 1.0);

        assert_eq!(p0.intersection_3pl(&p1, &p2), Some(Point3::new(1.0, -2.0, 1.0)));
    }

    #[test]
    fn test_to_str() {
        assert_eq!(Plane3::from_abcd(1.0, 2.0, 3.0, 4.0).to_str(), ~"1x + 2y + 3z + 4 = 0");
    }
}
<|endoftext|>


<commit_before>//! Tests for various types of file (video, image, compressed, etc).
//!
//! Currently this is dependent on the file’s name and extension, because
//! those are the only metadata that we have access to without reading the
//! file’s contents.

use ansi_term::Style;

use fs::File;
use output::file_name::FileColours;
use output::icons::FileIcon;

#[derive(Debug, Default, PartialEq)]
pub struct FileExtensions;

impl FileExtensions {

    /// An “immediate” file is something that can be run or activated somehow
    /// in order to kick off the build of a project. It’s usually only present
    /// in directories full of source code.
    fn is_immediate(&self, file: &File) -> bool {
        file.name.to_lowercase().starts_with("readme") || file.name_is_one_of( &[
            "Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt",
            "build.gradle", "Rakefile", "Gruntfile.js",
            "Gruntfile.coffee", "BUILD", "WORKSPACE", "build.xml"
        ])
    }

    fn is_image(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
            "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw",
            "svg", "stl", "eps", "dvi", "ps", "cbr", "jpf",
            "cbz", "xpm", "ico", "cr2", "orf", "nef",
        ])
    }

    fn is_video(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "avi", "flv", "m2v", "m4v", "mkv", "mov", "mp4", "mpeg",
            "mpg", "ogm", "ogv", "vob", "wmv", "webm", "m2ts",
        ])
    }

    fn is_music(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "aac", "m4a", "mp3", "ogg", "wma", "mka", "opus",
        ])
    }

    // Lossless music, rather than any other kind of data...
    fn is_lossless(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "alac", "ape", "flac", "wav",
        ])
    }

    fn is_crypto(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "asc", "enc", "gpg", "pgp", "sig", "signature", "pfx", "p12",
        ])
    }

    fn is_document(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "djvu", "doc", "docx", "dvi", "eml", "eps", "fotd",
            "odp", "odt", "pdf", "ppt", "pptx", "rtf",
            "xls", "xlsx",
        ])
    }

    fn is_compressed(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "zip", "tar", "Z", "z", "gz", "bz2", "a", "ar", "7z",
            "iso", "dmg", "tc", "rar", "par", "tgz", "xz", "txz",
            "lzma", "deb", "rpm", "zst",
        ])
    }

    fn is_temp(&self, file: &File) -> bool {
        file.name.ends_with('~')
            || (file.name.starts_with('#') && file.name.ends_with('#'))
            || file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak", "bk" ])
    }

    fn is_compiled(&self, file: &File) -> bool {
        if file.extension_is_one_of( &[ "class", "elc", "hi", "o", "pyc" ]) {
            true
        }
        else if let Some(dir) = file.parent_dir {
            file.get_source_files().iter().any(|path| dir.contains(path))
        }
        else {
            false
        }
    }
}

impl FileColours for FileExtensions {
    fn colour_file(&self, file: &File) -> Option<Style> {
        use ansi_term::Colour::*;

        Some(match file {
            f if self.is_temp(f)        => Fixed(244).normal(),
            f if self.is_immediate(f)   => Yellow.bold().underline(),
            f if self.is_image(f)       => Fixed(133).normal(),
            f if self.is_video(f)       => Fixed(135).normal(),
            f if self.is_music(f)       => Fixed(92).normal(),
            f if self.is_lossless(f)    => Fixed(93).normal(),
            f if self.is_crypto(f)      => Fixed(109).normal(),
            f if self.is_document(f)    => Fixed(105).normal(),
            f if self.is_compressed(f)  => Red.normal(),
            f if self.is_compiled(f)    => Fixed(137).normal(),
            _                           => return None,
        })
    }
}

impl FileIcon for FileExtensions {
    fn icon_file(&self, file: &File) -> Option<char> {
        use output::icons::Icons;

        Some(match file {
            f if self.is_music(f) || self.is_lossless(f) => Icons::Audio.value(),
            f if self.is_image(f) => Icons::Image.value(),
            f if self.is_video(f) => Icons::Video.value(),
            _ => return None,
        })
    }
}
<commit_msg>Add BUILD.bazel as another Bazel file type<commit_after>//! Tests for various types of file (video, image, compressed, etc).
//!
//! Currently this is dependent on the file’s name and extension, because
//! those are the only metadata that we have access to without reading the
//! file’s contents.

use ansi_term::Style;

use fs::File;
use output::file_name::FileColours;
use output::icons::FileIcon;

#[derive(Debug, Default, PartialEq)]
pub struct FileExtensions;

impl FileExtensions {

    /// An “immediate” file is something that can be run or activated somehow
    /// in order to kick off the build of a project. It’s usually only present
    /// in directories full of source code.
    fn is_immediate(&self, file: &File) -> bool {
        file.name.to_lowercase().starts_with("readme") || file.name_is_one_of( &[
            "Makefile", "Cargo.toml", "SConstruct", "CMakeLists.txt",
            "build.gradle", "Rakefile", "Gruntfile.js",
            "Gruntfile.coffee", "BUILD", "BUILD.bazel", "WORKSPACE", "build.xml"
        ])
    }

    fn is_image(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "png", "jpeg", "jpg", "gif", "bmp", "tiff", "tif",
            "ppm", "pgm", "pbm", "pnm", "webp", "raw", "arw",
            "svg", "stl", "eps", "dvi", "ps", "cbr", "jpf",
            "cbz", "xpm", "ico", "cr2", "orf", "nef",
        ])
    }

    fn is_video(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "avi", "flv", "m2v", "m4v", "mkv", "mov", "mp4", "mpeg",
            "mpg", "ogm", "ogv", "vob", "wmv", "webm", "m2ts",
        ])
    }

    fn is_music(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "aac", "m4a", "mp3", "ogg", "wma", "mka", "opus",
        ])
    }

    // Lossless music, rather than any other kind of data...
    fn is_lossless(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "alac", "ape", "flac", "wav",
        ])
    }

    fn is_crypto(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "asc", "enc", "gpg", "pgp", "sig", "signature", "pfx", "p12",
        ])
    }

    fn is_document(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "djvu", "doc", "docx", "dvi", "eml", "eps", "fotd",
            "odp", "odt", "pdf", "ppt", "pptx", "rtf",
            "xls", "xlsx",
        ])
    }

    fn is_compressed(&self, file: &File) -> bool {
        file.extension_is_one_of( &[
            "zip", "tar", "Z", "z", "gz", "bz2", "a", "ar", "7z",
            "iso", "dmg", "tc", "rar", "par", "tgz", "xz", "txz",
            "lzma", "deb", "rpm", "zst",
        ])
    }

    fn is_temp(&self, file: &File) -> bool {
        file.name.ends_with('~')
            || (file.name.starts_with('#') && file.name.ends_with('#'))
            || file.extension_is_one_of( &[ "tmp", "swp", "swo", "swn", "bak", "bk" ])
    }

    fn is_compiled(&self, file: &File) -> bool {
        if file.extension_is_one_of( &[ "class", "elc", "hi", "o", "pyc" ]) {
            true
        }
        else if let Some(dir) = file.parent_dir {
            file.get_source_files().iter().any(|path| dir.contains(path))
        }
        else {
            false
        }
    }
}

impl FileColours for FileExtensions {
    fn colour_file(&self, file: &File) -> Option<Style> {
        use ansi_term::Colour::*;

        Some(match file {
            f if self.is_temp(f)        => Fixed(244).normal(),
            f if self.is_immediate(f)   => Yellow.bold().underline(),
            f if self.is_image(f)       => Fixed(133).normal(),
            f if self.is_video(f)       => Fixed(135).normal(),
            f if self.is_music(f)       => Fixed(92).normal(),
            f if self.is_lossless(f)    => Fixed(93).normal(),
            f if self.is_crypto(f)      => Fixed(109).normal(),
            f if self.is_document(f)    => Fixed(105).normal(),
            f if self.is_compressed(f)  => Red.normal(),
            f if self.is_compiled(f)    => Fixed(137).normal(),
            _                           => return None,
        })
    }
}

impl FileIcon for FileExtensions {
    fn icon_file(&self, file: &File) -> Option<char> {
        use output::icons::Icons;

        Some(match file {
            f if self.is_music(f) || self.is_lossless(f) => Icons::Audio.value(),
            f if self.is_image(f) => Icons::Image.value(),
            f if self.is_video(f) => Icons::Video.value(),
            _ => return None,
        })
    }
}
<|endoftext|>