<commit_before>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use generic_array::{ArrayLength, GenericArray};
use std::io::{Result, Error, ErrorKind, Read, Write};
use std::mem::size_of;
use std::default::Default;

/// A message that can be encoded and decoded according to the LCM protocol.
pub trait Message {
    /// Encodes a message into a buffer, with the message hash at the beginning.
    fn encode_with_hash(&self) -> Result<Vec<u8>> {
        let hash = self.hash();
        let size = hash.size() + self.size();
        let mut buffer = Vec::with_capacity(size);
        hash.encode(&mut buffer)?;
        self.encode(&mut buffer)?;
        Ok(buffer)
    }

    /// Decodes a message from a buffer,
    /// and also checks that the hash at the beginning is correct.
    fn decode_with_hash(&mut self, mut buffer: &mut Read) -> Result<()>
        where Self: Sized + Default
    {

        let mut hash: i64 = 0;
        hash.decode(&mut buffer)?;
        if hash != self.hash() {
            return Err(Error::new(ErrorKind::Other, "Invalid hash"));
        }
        self.decode(buffer)
    }

    /// Returns the message hash for this type.
    /// Returns `0` for all primitive types.
    /// Generated `Lcm` types should implement this function.
    fn hash(&self) -> i64 {
        0
    }

    /// Encodes a message into a buffer.
    /// `Lcm` uses a `Vec<u8>` with its capacity set to the value returned by [`size()`].
    fn encode(&self, buffer: &mut Write) -> Result<()>;

    /// Decodes a message from a buffer.
    fn decode(&mut self, buffer: &mut Read) -> Result<()>;

    /// Returns the number of bytes this message is expected to take when encoded.
    fn size(&self) -> usize;
}

impl Message for bool {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        let value: i8 = match *self {
            true => 1,
            false => 0,
        };
        value.encode(buffer)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        let value = buffer.read_i8()?;
        *self = match value {
            0 => false,
            1 => true,
            _ => {
                return Err(Error::new(ErrorKind::InvalidData,
                                      "Booleans should be encoded as 0 or 1"))
            }
        };
        Ok(())
    }

    fn size(&self) -> usize {
        size_of::<i8>()
    }
}

impl Message for u8 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_u8(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_u8()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i8 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i8(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i8()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i16 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i16::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i16::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i32 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i32::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i32::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i64 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i64::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i64::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for f32 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_f32::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_f32::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for f64 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_f64::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_f64::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for String {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        let len: i32 = self.len() as i32 + 1;
        len.encode(buffer)?;
        for &b in self.as_bytes() {
            b.encode(buffer)?;
        }
        (0 as u8).encode(buffer)?;
        Ok(())
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        let len = buffer.read_i32::<BigEndian>()? - 1;
        let mut buf = Vec::with_capacity(len as usize);
        buf.decode(buffer)?;
        *self = String::from_utf8(buf).map_err(|e| Error::new(ErrorKind::Other, e))?;
        match buffer.read_u8() {
            Ok(0) => Ok(()),
            Ok(_) => Err(Error::new(ErrorKind::InvalidData, "Expected null terminator")),
            Err(e) => Err(e),
        }
    }

    fn size(&self) -> usize {
        size_of::<i32>() + self.len() + 1
    }
}

impl<T> Message for Vec<T>
    where T: Message + Default
{
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        for val in self.iter() {
            val.encode(buffer)?;
        }
        Ok(())
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        while self.len() != self.capacity() {
            let mut element = T::default();
            element.decode(buffer)?;
            self.push(element);
        }
        Ok(())
    }

    fn size(&self) -> usize {
        self.iter().map(Message::size).sum()
    }
}

impl<T, N> Message for GenericArray<T, N>
    where T: Message + Default,
          N: ArrayLength<T>
{
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        for val in self.iter() {
            val.encode(buffer)?;
        }
        Ok(())
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        for i in 0..self.len() {
            let mut element = T::default();
            element.decode(buffer)?;
            self[i] = element;
        }
        Ok(())
    }

    fn size(&self) -> usize {
        self.iter().map(Message::size).sum()
    }
}
<commit_msg>Modify Message trait definition.<commit_after>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use generic_array::{ArrayLength, GenericArray};
use std::io::{Result, Error, ErrorKind, Read, Write};
use std::mem::size_of;
use std::default::Default;

/// A message that can be encoded and decoded according to the LCM protocol.
pub trait Message {
    /// Encodes a message into a buffer, with the message hash at the beginning.
    fn encode_with_hash(&self) -> Result<Vec<u8>> where Self: Sized {
        let hash = Self::hash();
        let size = hash.size() + self.size();
        let mut buffer = Vec::with_capacity(size);
        hash.encode(&mut buffer)?;
        self.encode(&mut buffer)?;
        Ok(buffer)
    }

    /// Decodes a message from a buffer,
    /// and also checks that the hash at the beginning is correct.
    fn decode_with_hash(mut buffer: &mut Read) -> Result<Self>
        where Self: Sized
    {
        let hash: u64 = Message::decode(&mut buffer)?;
        if hash != Self::hash() {
            return Err(Error::new(ErrorKind::Other, "Invalid hash"));
        }
        Message::decode(buffer)
    }

    /// Returns the message hash for this type.
    /// Returns `0` for all primitive types.
    /// Generated `Lcm` types should implement this function.
    fn hash() -> u64 where Self: Sized {
        0
    }

    /// Encodes a message into a buffer.
    /// `Lcm` uses a `Vec<u8>` with its capacity set to the value returned by [`size()`].
    fn encode(&self, buffer: &mut Write) -> Result<()>;

    /// Decodes a message from a buffer.
    fn decode(buffer: &mut Read) -> Result<Self> where Self: Sized;

    /// Returns the number of bytes this message is expected to take when encoded.
    fn size(&self) -> usize;
}

impl Message for bool {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        let value: i8 = match *self {
            true => 1,
            false => 0,
        };
        value.encode(buffer)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        let value = buffer.read_i8()?;
        *self = match value {
            0 => false,
            1 => true,
            _ => {
                return Err(Error::new(ErrorKind::InvalidData,
                                      "Booleans should be encoded as 0 or 1"))
            }
        };
        Ok(())
    }

    fn size(&self) -> usize {
        size_of::<i8>()
    }
}

impl Message for u8 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_u8(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_u8()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i8 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i8(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i8()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i16 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i16::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i16::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i32 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i32::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i32::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for i64 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_i64::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_i64::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for f32 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_f32::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_f32::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for f64 {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        buffer.write_f64::<BigEndian>(*self)
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        Ok(*self = buffer.read_f64::<BigEndian>()?)
    }

    fn size(&self) -> usize {
        size_of::<Self>()
    }
}

impl Message for String {
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        let len: i32 = self.len() as i32 + 1;
        len.encode(buffer)?;
        for &b in self.as_bytes() {
            b.encode(buffer)?;
        }
        (0 as u8).encode(buffer)?;
        Ok(())
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        let len = buffer.read_i32::<BigEndian>()? - 1;
        let mut buf = Vec::with_capacity(len as usize);
        buf.decode(buffer)?;
        *self = String::from_utf8(buf).map_err(|e| Error::new(ErrorKind::Other, e))?;
        match buffer.read_u8() {
            Ok(0) => Ok(()),
            Ok(_) => Err(Error::new(ErrorKind::InvalidData, "Expected null terminator")),
            Err(e) => Err(e),
        }
    }

    fn size(&self) -> usize {
        size_of::<i32>() + self.len() + 1
    }
}

impl<T> Message for Vec<T>
    where T: Message + Default
{
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        for val in self.iter() {
            val.encode(buffer)?;
        }
        Ok(())
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        while self.len() != self.capacity() {
            let mut element = T::default();
            element.decode(buffer)?;
            self.push(element);
        }
        Ok(())
    }

    fn size(&self) -> usize {
        self.iter().map(Message::size).sum()
    }
}

impl<T, N> Message for GenericArray<T, N>
    where T: Message + Default,
          N: ArrayLength<T>
{
    fn encode(&self, buffer: &mut Write) -> Result<()> {
        for val in self.iter() {
            val.encode(buffer)?;
        }
        Ok(())
    }

    fn decode(&mut self, buffer: &mut Read) -> Result<()> {
        for i in 0..self.len() {
            let mut element = T::default();
            element.decode(buffer)?;
            self[i] = element;
        }
        Ok(())
    }

    fn size(&self) -> usize {
        self.iter().map(Message::size).sum()
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io::BufReader;
use std::io::prelude::*; // I'm honestly not sure what this is but all the examples I found online included it
use std::fs::File;
use std::path::Path;
use rand::{Rng, thread_rng, ThreadRng};

const NOUN_FORMAT_CHAR: u8 = b'%';
const ADJECTIVE_FORMAT_CHAR: u8 = b'#';
const ADVERB_FORMAT_CHAR: u8 = b'@';

mod phrase;
use self::phrase::Phrase;
// Phrase is just a wrapper around a String with a method to load a Vec of them from a file

pub struct Template_manager {
    // this is a struct that handles all of the actual text generation
    // we use Vec<Phrase> so we can use Rng.choose()
    templates: Vec<Phrase>,
    nouns: Vec<Phrase>,
    adjectives: Vec<Phrase>,
    adverbs: Vec<Phrase>,
}

impl Template_manager {
    pub fn new<P0, P1, P2, P3>(template_path: P0, noun_path: P1, adj_path: P2, adv_path: P3) -> Template_manager
        where P0: AsRef<Path>, P1: AsRef<Path>, P2: AsRef<Path>, P3: AsRef<Path>
        // given paths to all of the lists of stuff, create a new Template_manager
    {
        Template_manager {
            templates: Phrase::load_from_file(template_path),
            nouns: Phrase::load_from_file(noun_path),
            adjectives: Phrase::load_from_file(adj_path),
            adverbs: Phrase::load_from_file(adv_path),
        }
    }

    fn get_noun_phrase(&self, mut rng: &mut ThreadRng) -> Vec<u8> {
        // we juggle Vec<u8>s around here because they're easy to iterate through and replace bytes
        // this method and its friends get_adjective_phrase and get_adverb_phrase choose a random phrase from the Vec<Phrase>s
        if let Some(ref noun_phrase) = rng.choose(&self.nouns) {
            noun_phrase.text.clone().into_bytes()
        } else {
            panic!("couldn't get a noun phrase")
        }
    }

    fn get_adjective_phrase(&self, mut rng: &mut ThreadRng) -> Vec<u8> {
        if let Some(ref adj_phrase) = rng.choose(&self.adjectives) {
            adj_phrase.text.clone().into_bytes()
        } else {
            panic!("couldn't get an adjective phrase")
        }
    }

    fn get_adverb_phrase(&self, mut rng: &mut ThreadRng) -> Vec<u8> {
        if let Some(ref adv_phrase) = rng.choose(&self.adverbs) {
            adv_phrase.text.clone().into_bytes()
        } else {
            panic!("couldn't get an adjective phrase")
        }
    }

    fn format_phrase(&self, phrase: Vec<u8>, mut rng: &mut ThreadRng) -> Vec<u8> {
        // this method iterates through a Vec<u8> and replaces any of the FORMAT_CHARs with a phrase
        // it's recursive so that adjectives can be things like "%-driven"
        let mut new_bytes: Vec<u8> = Vec::new();
        for byte in phrase.iter() {
            if *byte == NOUN_FORMAT_CHAR {
                for noun_byte in self.format_phrase(self.get_noun_phrase(&mut rng), &mut rng).iter() {
                    new_bytes.push(*noun_byte);
                }
            } else if *byte == ADJECTIVE_FORMAT_CHAR {
                for adj_byte in self.format_phrase(self.get_adjective_phrase(&mut rng), &mut rng).iter() {
                    new_bytes.push(*adj_byte);
                }
            } else if *byte == ADVERB_FORMAT_CHAR {
                for adv_byte in self.format_phrase(self.get_adjective_phrase(&mut rng), &mut rng).iter() {
                    new_bytes.push(*adv_byte);
                }
            } else {
                new_bytes.push(*byte);
            }
        }
        new_bytes
    }

    pub fn make_formatted_quote(&self, mut rng: &mut ThreadRng) -> String {
        // this is the big wrapper method that main.rs/main() calls
        // it returns a fully formatted phrase that can be tweeted
        // note: I can't figure out how to have the Template_handler own rng
        // because getting a random value mutates the rng
        // so instead it's owned by main() and these methods just pass refs to it back and forth
        if let Some(ref template) = rng.choose(&self.templates) {
            String::from_utf8(self.format_phrase(template.text.clone().into_bytes(), &mut rng)).unwrap()
        } else {
            panic!("couldn't get a template")
        }
    }
}
<commit_msg>fixed adverb<commit_after>extern crate rand;

use std::io::BufReader;
use std::io::prelude::*; // I'm honestly not sure what this is but all the examples I found online included it
use std::fs::File;
use std::path::Path;
use rand::{Rng, thread_rng, ThreadRng};

const NOUN_FORMAT_CHAR: u8 = b'%';
const ADJECTIVE_FORMAT_CHAR: u8 = b'#';
const ADVERB_FORMAT_CHAR: u8 = b'@';

mod phrase;
use self::phrase::Phrase;
// Phrase is just a wrapper around a String with a method to load a Vec of them from a file

pub struct Template_manager {
    // this is a struct that handles all of the actual text generation
    // we use Vec<Phrase> so we can use Rng.choose()
    templates: Vec<Phrase>,
    nouns: Vec<Phrase>,
    adjectives: Vec<Phrase>,
    adverbs: Vec<Phrase>,
}

impl Template_manager {
    pub fn new<P0, P1, P2, P3>(template_path: P0, noun_path: P1, adj_path: P2, adv_path: P3) -> Template_manager
        where P0: AsRef<Path>, P1: AsRef<Path>, P2: AsRef<Path>, P3: AsRef<Path>
        // given paths to all of the lists of stuff, create a new Template_manager
    {
        Template_manager {
            templates: Phrase::load_from_file(template_path),
            nouns: Phrase::load_from_file(noun_path),
            adjectives: Phrase::load_from_file(adj_path),
            adverbs: Phrase::load_from_file(adv_path),
        }
    }

    fn get_noun_phrase(&self, mut rng: &mut ThreadRng) -> Vec<u8> {
        // we juggle Vec<u8>s around here because they're easy to iterate through and replace bytes
        // this method and its friends get_adjective_phrase and get_adverb_phrase choose a random phrase from the Vec<Phrase>s
        if let Some(ref noun_phrase) = rng.choose(&self.nouns) {
            noun_phrase.text.clone().into_bytes()
        } else {
            panic!("couldn't get a noun phrase")
        }
    }

    fn get_adjective_phrase(&self, mut rng: &mut ThreadRng) -> Vec<u8> {
        if let Some(ref adj_phrase) = rng.choose(&self.adjectives) {
            adj_phrase.text.clone().into_bytes()
        } else {
            panic!("couldn't get an adjective phrase")
        }
    }

    fn get_adverb_phrase(&self, mut rng: &mut ThreadRng) -> Vec<u8> {
        if let Some(ref adv_phrase) = rng.choose(&self.adverbs) {
            adv_phrase.text.clone().into_bytes()
        } else {
            panic!("couldn't get an adjective phrase")
        }
    }

    fn format_phrase(&self, phrase: Vec<u8>, mut rng: &mut ThreadRng) -> Vec<u8> {
        // this method iterates through a Vec<u8> and replaces any of the FORMAT_CHARs with a phrase
        // it's recursive so that adjectives can be things like "%-driven"
        let mut new_bytes: Vec<u8> = Vec::new();
        for byte in phrase.iter() {
            if *byte == NOUN_FORMAT_CHAR {
                for noun_byte in self.format_phrase(self.get_noun_phrase(&mut rng), &mut rng).iter() {
                    new_bytes.push(*noun_byte);
                }
            } else if *byte == ADJECTIVE_FORMAT_CHAR {
                for adj_byte in self.format_phrase(self.get_adjective_phrase(&mut rng), &mut rng).iter() {
                    new_bytes.push(*adj_byte);
                }
            } else if *byte == ADVERB_FORMAT_CHAR {
                for adv_byte in self.format_phrase(self.get_adverb_phrase(&mut rng), &mut rng).iter() {
                    new_bytes.push(*adv_byte);
                }
            } else {
                new_bytes.push(*byte);
            }
        }
        new_bytes
    }

    pub fn make_formatted_quote(&self, mut rng: &mut ThreadRng) -> String {
        // this is the big wrapper method that main.rs/main() calls
        // it returns a fully formatted phrase that can be tweeted
        // note: I can't figure out how to have the Template_handler own rng
        // because getting a random value mutates the rng
        // so instead it's owned by main() and these methods just pass refs to it back and forth
        if let Some(ref template) = rng.choose(&self.templates) {
            String::from_utf8(self.format_phrase(template.text.clone().into_bytes(), &mut rng)).unwrap()
        } else {
            panic!("couldn't get a template")
        }
    }
}
<|endoftext|>


<commit_before>use cgmath::Point2;
use game::constants::{TERRAIN_OBJECTS, TILES_PCS_H, TILES_PCS_W};
use game::get_rand_from_range;
use graphics::coords_to_tile_offset;
use pathfinding::{directed::astar::astar, utils::absdiff};
use shaders::Position;

fn neighbours<'c>(curr_pos: &'c Point2<i32>, impassable_tiles: &[[usize; 2]], neighbour_tiles: &'c mut Vec<Point2<i32>>) -> Vec<&'c Point2<i32>> {
  neighbour_tiles.push(Point2::new(curr_pos.x - 1, curr_pos.y));
  neighbour_tiles.push(Point2::new(curr_pos.x - 1, curr_pos.y - 1));
  neighbour_tiles.push(Point2::new(curr_pos.x, curr_pos.y - 1));
  neighbour_tiles.push(Point2::new(curr_pos.x + 1, curr_pos.y));
  neighbour_tiles.push(Point2::new(curr_pos.x + 1, curr_pos.y + 1));
  neighbour_tiles.push(Point2::new(curr_pos.x, curr_pos.y + 1));
  neighbour_tiles.push(Point2::new(curr_pos.x - 1, curr_pos.y + 1));
  neighbour_tiles.push(Point2::new(curr_pos.x + 1, curr_pos.y - 1));

  neighbour_tiles.iter()
            .filter(|ref e| e.x >= 0 && e.x < TILES_PCS_W as i32 && e.y >= 0 && e.y < TILES_PCS_H as i32)
            .filter(|ref e| !impassable_tiles.contains(&[e.x as usize, e.y as usize]))
            .collect()
}

fn tiles(p: &Point2<i32>, impassable_tiles: &[[usize; 2]]) -> Vec<(Point2<i32>, i32)> {
  neighbours(&Point2::new(p.x as i32, p.y as i32), &impassable_tiles, &mut vec![]).iter()
                                                                                .map(|p| (Point2::new(p.x, p.y), 1))
                                                                                .collect()
}

fn find_next_best_endpoint<'c>(end_point: &'c Point2<i32>, impassable_tiles: &[[usize; 2]], neighbour_tiles: &'c mut Vec<Point2<i32>>) -> &'c Point2<i32> {
  if impassable_tiles.iter().any(|e| e[0] == end_point.x as usize && e[1] == end_point.y as usize) {
    neighbours(&end_point, &impassable_tiles, neighbour_tiles)[0]
  } else {
    &end_point
  }
}

pub fn calc_route(start_point: Position, end_point: Position, impassable_tiles: &[[usize; 2]]) -> Option<(Vec<Point2<i32>>, i32)> {
  let mut neighbour_tiles = vec![];
  let end_point_with_offset = &coords_to_tile_offset(end_point);

  let start = coords_to_tile_offset(start_point);
  let end = find_next_best_endpoint(end_point_with_offset, &impassable_tiles, &mut neighbour_tiles);

  astar(&start,
        |p: &Point2<i32>| tiles(p, &impassable_tiles),
        |p: &Point2<i32>| absdiff(p.x, end.x) + absdiff(p.y, end.y),
        |p: &Point2<i32>| p.x == end.x && p.y == end.y)
}

pub fn calc_next_movement(start_point: Position, end_point: Position) -> i32 {
  let next_step: Point2<i32> = calc_route(start_point, end_point, &TERRAIN_OBJECTS)
    .map_or_else(|| Point2::new(0 as i32, 0 as i32),
                 |(route, _)| {
                   if route.len() > 1 {
                     Point2::new(route[1].x as i32, route[1].y as i32)
                   } else {
                     Point2::new(route[0].x as i32, route[0].y as i32)
                   }
                 });

  let start = coords_to_tile_offset(start_point);
  let diff: (i32, i32) = (next_step.x - start.x, next_step.y - start.y);

  match diff {
    (1, 0) => 315,
    (1, 1) => 270,
    (0, 1) => 225,
    (-1, 1) => 180,
    (-1, 0) => 135,
    (-1, -1) => 90,
    (0, -1) => 45,
    (1, -1) => 0,
    _ => get_rand_from_range(0, 359),
  }
}
<commit_msg>Remove some explicit type casts and "new" calls from path finding logic<commit_after>use cgmath::Point2;
use game::constants::{TERRAIN_OBJECTS, TILES_PCS_H, TILES_PCS_W};
use game::get_rand_from_range;
use graphics::coords_to_tile_offset;
use pathfinding::{directed::astar::astar, utils::absdiff};
use shaders::Position;

fn neighbours<'c>(curr_pos: &'c Point2<i32>, impassable_tiles: &[[usize; 2]], neighbour_tiles: &'c mut Vec<Point2<i32>>) -> Vec<&'c Point2<i32>> {
  neighbour_tiles.push(Point2::new(curr_pos.x - 1, curr_pos.y));
  neighbour_tiles.push(Point2::new(curr_pos.x - 1, curr_pos.y - 1));
  neighbour_tiles.push(Point2::new(curr_pos.x, curr_pos.y - 1));
  neighbour_tiles.push(Point2::new(curr_pos.x + 1, curr_pos.y));
  neighbour_tiles.push(Point2::new(curr_pos.x + 1, curr_pos.y + 1));
  neighbour_tiles.push(Point2::new(curr_pos.x, curr_pos.y + 1));
  neighbour_tiles.push(Point2::new(curr_pos.x - 1, curr_pos.y + 1));
  neighbour_tiles.push(Point2::new(curr_pos.x + 1, curr_pos.y - 1));

  neighbour_tiles.iter()
            .filter(|ref e| e.x >= 0 && e.x < TILES_PCS_W as i32 && e.y >= 0 && e.y < TILES_PCS_H as i32)
            .filter(|ref e| !impassable_tiles.contains(&[e.x as usize, e.y as usize]))
            .collect()
}

fn tiles<'c>(p: &'c Point2<i32>, impassable_tiles: &[[usize; 2]]) -> Vec<(Point2<i32>, i32)> {
  neighbours(&p, &impassable_tiles, &mut vec![]).iter()
                                                                                .map(|p| (**p, 1))
                                                                                .collect()
}

fn find_next_best_endpoint<'c>(end_point: &'c Point2<i32>, impassable_tiles: &[[usize; 2]], neighbour_tiles: &'c mut Vec<Point2<i32>>) -> &'c Point2<i32> {
  if impassable_tiles.iter().any(|e| e[0] == end_point.x as usize && e[1] == end_point.y as usize) {
    neighbours(&end_point, &impassable_tiles, neighbour_tiles)[0]
  } else {
    &end_point
  }
}

pub fn calc_route(start_point: Position, end_point: Position, impassable_tiles: &[[usize; 2]]) -> Option<(Vec<Point2<i32>>, i32)> {
  let mut neighbour_tiles = vec![];
  let end_point_with_offset = coords_to_tile_offset(end_point);

  let start = coords_to_tile_offset(start_point);
  let end = find_next_best_endpoint(&end_point_with_offset, &impassable_tiles, &mut neighbour_tiles);

  astar(&start,
        |p: &Point2<i32>| tiles(p, &impassable_tiles),
        |p: &Point2<i32>| absdiff(p.x, end.x) + absdiff(p.y, end.y),
        |p: &Point2<i32>| p.x == end.x && p.y == end.y)
}

pub fn calc_next_movement(start_point: Position, end_point: Position) -> i32 {
  let next_step: Point2<i32> = calc_route(start_point, end_point, &TERRAIN_OBJECTS)
    .map_or_else(|| Point2::new(0, 0),
                 |(route, _)| {
                   if route.len() > 1 {
                     Point2::new(route[1].x, route[1].y)
                   } else {
                     Point2::new(route[0].x, route[0].y)
                   }
                 });

  let start = coords_to_tile_offset(start_point);
  let diff: (i32, i32) = (next_step.x - start.x, next_step.y - start.y);

  match diff {
    (1, 0) => 315,
    (1, 1) => 270,
    (0, 1) => 225,
    (-1, 1) => 180,
    (-1, 0) => 135,
    (-1, -1) => 90,
    (0, -1) => 45,
    (1, -1) => 0,
    _ => get_rand_from_range(0, 359),
  }
}
<|endoftext|>


<commit_before>// Testing the display of Mutex and MutexGuard in cdb.

// cdb-only
// min-cdb-version: 10.0.21287.1005
// compile-flags:-g
// FIXME: Failed on update to 10.0.22000.1
// ignore-windows

// === CDB TESTS ==================================================================================
//
// cdb-command:g
//
// cdb-command:dx m,d
// cdb-check:m,d              [Type: std::sync::mutex::Mutex<i32>]
// cdb-check:    [...] inner            [Type: std::sys_common::mutex::MovableMutex]
// cdb-check:    [...] poison           [Type: std::sync::poison::Flag]
// cdb-check:    [...] data             [Type: core::cell::UnsafeCell<i32>]

//
// cdb-command:dx m.data,d
// cdb-check:m.data,d         [Type: core::cell::UnsafeCell<i32>]
// cdb-check:    [...] value            : 0 [Type: int]

//
// cdb-command:dx lock,d
// cdb-check:lock,d           : Ok [Type: enum$<core::result::Result<std::sync::mutex::MutexGuard<i32>, enum$<std::sync::poison::TryLockError<std::sync::mutex::MutexGuard<i32> >, 0, 1, Poisoned> > >]
// cdb-check:    [...] variant$         : Ok (0) [Type: core::result::Result]
// cdb-check:    [...] __0              [Type: std::sync::mutex::MutexGuard<i32>]

use std::sync::Mutex;

#[allow(unused_variables)]
fn main()
{
    let m = Mutex::new(0);
    let lock = m.try_lock();
    zzz(); // #break
}

fn zzz() {}
<commit_msg>Re-enable the `src/test/debuginfo/mutex.rs` test on Windows<commit_after>// Testing the display of Mutex and MutexGuard in cdb.

// cdb-only
// min-cdb-version: 10.0.21287.1005
// compile-flags:-g

// === CDB TESTS ==================================================================================
//
// cdb-command:g
//
// cdb-command:dx m,d
// cdb-check:m,d              [Type: std::sync::mutex::Mutex<i32>]
// cdb-check:    [...] inner            [Type: std::sys_common::mutex::MovableMutex]
// cdb-check:    [...] poison           [Type: std::sync::poison::Flag]
// cdb-check:    [...] data             : 0 [Type: core::cell::UnsafeCell<i32>]

//
// cdb-command:dx m.data,d
// cdb-check:m.data,d         : 0 [Type: core::cell::UnsafeCell<i32>]
// cdb-check:    [<Raw View>]     [Type: core::cell::UnsafeCell<i32>]

//
// cdb-command:dx lock,d
// cdb-check:lock,d           : Ok [Type: enum$<core::result::Result<std::sync::mutex::MutexGuard<i32>,enum$<std::sync::poison::TryLockError<std::sync::mutex::MutexGuard<i32> >, 0, 1, Poisoned> > >]
// cdb-check:    [variant]        : Ok
// cdb-check:    [...] __0              [Type: std::sync::mutex::MutexGuard<i32>]

use std::sync::Mutex;

#[allow(unused_variables)]
fn main()
{
    let m = Mutex::new(0);
    let lock = m.try_lock();
    zzz(); // #break
}

fn zzz() {}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

extern crate glib;
use glib::prelude::*;
extern crate gio;
use gio::prelude::*;

extern crate gstreamer as gst;
use gst::prelude::*;

extern crate gtk;
use gtk::prelude::*;

use std::cell::RefCell;
use std::env;

fn create_pipeline() -> (
    gst::Pipeline,
    gst::Pad,
    gst::Pad,
    gst::Element,
    gst::Element,
    gtk::Widget,
) {
    let pipeline = gst::Pipeline::new(None);

    let video_src = gst::ElementFactory::make("videotestsrc", None).unwrap();
    video_src.set_property("is-live", &true).unwrap();
    video_src.set_property_from_str("pattern", "ball");

    let timeoverlay = gst::ElementFactory::make("timeoverlay", None).unwrap();
    timeoverlay
        .set_property("font-desc", &"Monospace 20")
        .unwrap();

    let video_tee = gst::ElementFactory::make("tee", None).unwrap();
    let video_queue1 = gst::ElementFactory::make("queue", None).unwrap();
    let video_queue2 = gst::ElementFactory::make("queue", None).unwrap();

    let video_convert1 = gst::ElementFactory::make("videoconvert", None).unwrap();
    let video_convert2 = gst::ElementFactory::make("videoconvert", None).unwrap();

    let (video_sink, video_widget) =
        if let Some(gtkglsink) = gst::ElementFactory::make("gtkglsink", None) {
            let glsinkbin = gst::ElementFactory::make("glsinkbin", None).unwrap();
            glsinkbin.set_property("sink", &gtkglsink).unwrap();

            let widget = gtkglsink.get_property("widget").unwrap();
            (glsinkbin, widget.get::<gtk::Widget>().unwrap())
        } else {
            let sink = gst::ElementFactory::make("gtksink", None).unwrap();
            let widget = sink.get_property("widget").unwrap();
            (sink, widget.get::<gtk::Widget>().unwrap())
        };

    let video_enc = gst::ElementFactory::make("x264enc", None).unwrap();
    video_enc.set_property("rc-lookahead", &10i32).unwrap();
    video_enc.set_property("key-int-max", &30u32).unwrap();
    let video_parse = gst::ElementFactory::make("h264parse", None).unwrap();

    let audio_src = gst::ElementFactory::make("audiotestsrc", None).unwrap();
    audio_src.set_property("is-live", &true).unwrap();
    audio_src.set_property_from_str("wave", "ticks");

    let audio_tee = gst::ElementFactory::make("tee", None).unwrap();
    let audio_queue1 = gst::ElementFactory::make("queue", None).unwrap();
    let audio_queue2 = gst::ElementFactory::make("queue", None).unwrap();

    let audio_convert1 = gst::ElementFactory::make("audioconvert", None).unwrap();
    let audio_convert2 = gst::ElementFactory::make("audioconvert", None).unwrap();

    let audio_sink = gst::ElementFactory::make("autoaudiosink", None).unwrap();

    let audio_enc = gst::ElementFactory::make("lamemp3enc", None).unwrap();
    let audio_parse = gst::ElementFactory::make("mpegaudioparse", None).unwrap();

    let togglerecord = gst::ElementFactory::make("togglerecord", None).unwrap();

    let mux_queue1 = gst::ElementFactory::make("queue", None).unwrap();
    let mux_queue2 = gst::ElementFactory::make("queue", None).unwrap();

    let mux = gst::ElementFactory::make("mp4mux", None).unwrap();

    let file_sink = gst::ElementFactory::make("filesink", None).unwrap();
    file_sink
        .set_property("location", &"recording.mp4")
        .unwrap();
    file_sink.set_property("async", &false).unwrap();
    file_sink.set_property("sync", &false).unwrap();

    pipeline
        .add_many(&[
            &video_src,
            &timeoverlay,
            &video_tee,
            &video_queue1,
            &video_queue2,
            &video_convert1,
            &video_convert2,
            &video_sink,
            &video_enc,
            &video_parse,
            &audio_src,
            &audio_tee,
            &audio_queue1,
            &audio_queue2,
            &audio_convert1,
            &audio_convert2,
            &audio_sink,
            &audio_enc,
            &audio_parse,
            &togglerecord,
            &mux_queue1,
            &mux_queue2,
            &mux,
            &file_sink,
        ])
        .unwrap();

    gst::Element::link_many(&[
        &video_src,
        &timeoverlay,
        &video_tee,
        &video_queue1,
        &video_convert1,
        &video_sink,
    ])
    .unwrap();

    gst::Element::link_many(&[
        &video_tee,
        &video_queue2,
        &video_convert2,
        &video_enc,
        &video_parse,
    ])
    .unwrap();

    video_parse
        .link_pads(Some("src"), &togglerecord, Some("sink"))
        .unwrap();
    togglerecord
        .link_pads(Some("src"), &mux_queue1, Some("sink"))
        .unwrap();
    mux_queue1
        .link_pads(Some("src"), &mux, Some("video_%u"))
        .unwrap();

    gst::Element::link_many(&[
        &audio_src,
        &audio_tee,
        &audio_queue1,
        &audio_convert1,
        &audio_sink,
    ])
    .unwrap();

    gst::Element::link_many(&[
        &audio_tee,
        &audio_queue2,
        &audio_convert2,
        &audio_enc,
        &audio_parse,
    ])
    .unwrap();

    audio_parse
        .link_pads(Some("src"), &togglerecord, Some("sink_0"))
        .unwrap();
    togglerecord
        .link_pads(Some("src_0"), &mux_queue2, Some("sink"))
        .unwrap();
    mux_queue2
        .link_pads(Some("src"), &mux, Some("audio_%u"))
        .unwrap();

    gst::Element::link_many(&[&mux, &file_sink]).unwrap();

    (
        pipeline,
        video_queue2.get_static_pad("sink").unwrap(),
        audio_queue2.get_static_pad("sink").unwrap(),
        togglerecord,
        video_sink,
        video_widget,
    )
}

fn create_ui(app: &gtk::Application) {
    let (pipeline, video_pad, audio_pad, togglerecord, video_sink, video_widget) =
        create_pipeline();

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    window.set_default_size(320, 240);
    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
    vbox.pack_start(&video_widget, true, true, 0);

    let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    let position_label = gtk::Label::new(Some("Position: 00:00:00"));
    hbox.pack_start(&position_label, true, true, 5);
    let recorded_duration_label = gtk::Label::new(Some("Recorded: 00:00:00"));
    hbox.pack_start(&recorded_duration_label, true, true, 5);
    vbox.pack_start(&hbox, false, false, 5);

    let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    let record_button = gtk::Button::new_with_label("Record");
    hbox.pack_start(&record_button, true, true, 5);
    let finish_button = gtk::Button::new_with_label("Finish");
    hbox.pack_start(&finish_button, true, true, 5);
    vbox.pack_start(&hbox, false, false, 5);

    window.add(&vbox);
    window.show_all();

    app.add_window(&window);

    let video_sink_weak = video_sink.downgrade();
    let togglerecord_weak = togglerecord.downgrade();
    let timeout_id = gtk::timeout_add(100, move || {
        let video_sink = match video_sink_weak.upgrade() {
            Some(video_sink) => video_sink,
            None => return glib::Continue(true),
        };

        let togglerecord = match togglerecord_weak.upgrade() {
            Some(togglerecord) => togglerecord,
            None => return glib::Continue(true),
        };

        let position = video_sink
            .query_position::<gst::ClockTime>()
            .unwrap_or_else(|| 0.into());
        position_label.set_text(&format!("Position: {:.1}", position));

        let recording_duration = togglerecord
            .get_static_pad("src")
            .unwrap()
            .query_position::<gst::ClockTime>()
            .unwrap_or_else(|| 0.into());
        recorded_duration_label.set_text(&format!("Recorded: {:.1}", recording_duration));

        glib::Continue(true)
    });

    let togglerecord_weak = togglerecord.downgrade();
    record_button.connect_clicked(move |button| {
        let togglerecord = match togglerecord_weak.upgrade() {
            Some(togglerecord) => togglerecord,
            None => return,
        };

        let recording = !togglerecord
            .get_property("record")
            .unwrap()
            .get::<bool>()
            .unwrap();
        togglerecord.set_property("record", &recording).unwrap();

        button.set_label(if recording { "Stop" } else { "Record" });
    });

    let record_button_weak = record_button.downgrade();
    finish_button.connect_clicked(move |button| {
        let record_button = match record_button_weak.upgrade() {
            Some(record_button) => record_button,
            None => return,
        };

        record_button.set_sensitive(false);
        button.set_sensitive(false);

        video_pad.send_event(gst::Event::new_eos().build());
        audio_pad.send_event(gst::Event::new_eos().build());
    });

    let app_weak = app.downgrade();
    window.connect_delete_event(move |_, _| {
        let app = match app_weak.upgrade() {
            Some(app) => app,
            None => return Inhibit(false),
        };

        app.quit();
        Inhibit(false)
    });

    let bus = pipeline.get_bus().unwrap();
    let app_weak = glib::SendWeakRef::from(app.downgrade());
    bus.add_watch(move |_, msg| {
        use gst::MessageView;

        let app = match app_weak.upgrade() {
            Some(app) => app,
            None => return glib::Continue(false),
        };

        match msg.view() {
            MessageView::Eos(..) => app.quit(),
            MessageView::Error(err) => {
                println!(
                    "Error from {:?}: {} ({:?})",
                    msg.get_src().map(|s| s.get_path_string()),
                    err.get_error(),
                    err.get_debug()
                );
                app.quit();
            }
            _ => (),
        };

        glib::Continue(true)
    });

    pipeline.set_state(gst::State::Playing).unwrap();

    // Pipeline reference is owned by the closure below, so will be
    // destroyed once the app is destroyed
    let timeout_id = RefCell::new(Some(timeout_id));
    app.connect_shutdown(move |_| {
        pipeline.set_state(gst::State::Null).unwrap();

        bus.remove_watch().unwrap();

        if let Some(timeout_id) = timeout_id.borrow_mut().take() {
            glib::source_remove(timeout_id);
        }
    });
}

fn main() {
    gst::init().unwrap();
    gtk::init().unwrap();

    #[cfg(debug_assertions)]
    {
        use std::path::Path;

        let mut path = Path::new("target/debug");
        if !path.exists() {
            path = Path::new("../target/debug");
        }

        gst::Registry::get().scan_path(path);
    }
    #[cfg(not(debug_assertions))]
    {
        use std::path::Path;

        let mut path = Path::new("target/release");
        if !path.exists() {
            path = Path::new("../target/release");
        }

        gst::Registry::get().scan_path(path);
    }

    let app = gtk::Application::new(None, gio::ApplicationFlags::FLAGS_NONE).unwrap();

    app.connect_activate(create_ui);
    let args = env::args().collect::<Vec<_>>();
    app.run(&args);
}
<commit_msg>togglerecord: Register plugin as a static plugin in the example<commit_after>// Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 51 Franklin Street, Suite 500,
// Boston, MA 02110-1335, USA.

extern crate glib;
use glib::prelude::*;
extern crate gio;
use gio::prelude::*;

extern crate gstreamer as gst;
use gst::prelude::*;

extern crate gsttogglerecord;

extern crate gtk;
use gtk::prelude::*;
use std::cell::RefCell;
use std::env;

fn create_pipeline() -> (
    gst::Pipeline,
    gst::Pad,
    gst::Pad,
    gst::Element,
    gst::Element,
    gtk::Widget,
) {
    let pipeline = gst::Pipeline::new(None);

    let video_src = gst::ElementFactory::make("videotestsrc", None).unwrap();
    video_src.set_property("is-live", &true).unwrap();
    video_src.set_property_from_str("pattern", "ball");

    let timeoverlay = gst::ElementFactory::make("timeoverlay", None).unwrap();
    timeoverlay
        .set_property("font-desc", &"Monospace 20")
        .unwrap();

    let video_tee = gst::ElementFactory::make("tee", None).unwrap();
    let video_queue1 = gst::ElementFactory::make("queue", None).unwrap();
    let video_queue2 = gst::ElementFactory::make("queue", None).unwrap();

    let video_convert1 = gst::ElementFactory::make("videoconvert", None).unwrap();
    let video_convert2 = gst::ElementFactory::make("videoconvert", None).unwrap();

    let (video_sink, video_widget) =
        if let Some(gtkglsink) = gst::ElementFactory::make("gtkglsink", None) {
            let glsinkbin = gst::ElementFactory::make("glsinkbin", None).unwrap();
            glsinkbin.set_property("sink", &gtkglsink).unwrap();

            let widget = gtkglsink.get_property("widget").unwrap();
            (glsinkbin, widget.get::<gtk::Widget>().unwrap())
        } else {
            let sink = gst::ElementFactory::make("gtksink", None).unwrap();
            let widget = sink.get_property("widget").unwrap();
            (sink, widget.get::<gtk::Widget>().unwrap())
        };

    let video_enc = gst::ElementFactory::make("x264enc", None).unwrap();
    video_enc.set_property("rc-lookahead", &10i32).unwrap();
    video_enc.set_property("key-int-max", &30u32).unwrap();
    let video_parse = gst::ElementFactory::make("h264parse", None).unwrap();

    let audio_src = gst::ElementFactory::make("audiotestsrc", None).unwrap();
    audio_src.set_property("is-live", &true).unwrap();
    audio_src.set_property_from_str("wave", "ticks");

    let audio_tee = gst::ElementFactory::make("tee", None).unwrap();
    let audio_queue1 = gst::ElementFactory::make("queue", None).unwrap();
    let audio_queue2 = gst::ElementFactory::make("queue", None).unwrap();

    let audio_convert1 = gst::ElementFactory::make("audioconvert", None).unwrap();
    let audio_convert2 = gst::ElementFactory::make("audioconvert", None).unwrap();

    let audio_sink = gst::ElementFactory::make("autoaudiosink", None).unwrap();

    let audio_enc = gst::ElementFactory::make("lamemp3enc", None).unwrap();
    let audio_parse = gst::ElementFactory::make("mpegaudioparse", None).unwrap();

    let togglerecord = gst::ElementFactory::make("togglerecord", None).unwrap();

    let mux_queue1 = gst::ElementFactory::make("queue", None).unwrap();
    let mux_queue2 = gst::ElementFactory::make("queue", None).unwrap();

    let mux = gst::ElementFactory::make("mp4mux", None).unwrap();

    let file_sink = gst::ElementFactory::make("filesink", None).unwrap();
    file_sink
        .set_property("location", &"recording.mp4")
        .unwrap();
    file_sink.set_property("async", &false).unwrap();
    file_sink.set_property("sync", &false).unwrap();

    pipeline
        .add_many(&[
            &video_src,
            &timeoverlay,
            &video_tee,
            &video_queue1,
            &video_queue2,
            &video_convert1,
            &video_convert2,
            &video_sink,
            &video_enc,
            &video_parse,
            &audio_src,
            &audio_tee,
            &audio_queue1,
            &audio_queue2,
            &audio_convert1,
            &audio_convert2,
            &audio_sink,
            &audio_enc,
            &audio_parse,
            &togglerecord,
            &mux_queue1,
            &mux_queue2,
            &mux,
            &file_sink,
        ])
        .unwrap();

    gst::Element::link_many(&[
        &video_src,
        &timeoverlay,
        &video_tee,
        &video_queue1,
        &video_convert1,
        &video_sink,
    ])
    .unwrap();

    gst::Element::link_many(&[
        &video_tee,
        &video_queue2,
        &video_convert2,
        &video_enc,
        &video_parse,
    ])
    .unwrap();

    video_parse
        .link_pads(Some("src"), &togglerecord, Some("sink"))
        .unwrap();
    togglerecord
        .link_pads(Some("src"), &mux_queue1, Some("sink"))
        .unwrap();
    mux_queue1
        .link_pads(Some("src"), &mux, Some("video_%u"))
        .unwrap();

    gst::Element::link_many(&[
        &audio_src,
        &audio_tee,
        &audio_queue1,
        &audio_convert1,
        &audio_sink,
    ])
    .unwrap();

    gst::Element::link_many(&[
        &audio_tee,
        &audio_queue2,
        &audio_convert2,
        &audio_enc,
        &audio_parse,
    ])
    .unwrap();

    audio_parse
        .link_pads(Some("src"), &togglerecord, Some("sink_0"))
        .unwrap();
    togglerecord
        .link_pads(Some("src_0"), &mux_queue2, Some("sink"))
        .unwrap();
    mux_queue2
        .link_pads(Some("src"), &mux, Some("audio_%u"))
        .unwrap();

    gst::Element::link_many(&[&mux, &file_sink]).unwrap();

    (
        pipeline,
        video_queue2.get_static_pad("sink").unwrap(),
        audio_queue2.get_static_pad("sink").unwrap(),
        togglerecord,
        video_sink,
        video_widget,
    )
}

fn create_ui(app: &gtk::Application) {
    let (pipeline, video_pad, audio_pad, togglerecord, video_sink, video_widget) =
        create_pipeline();

    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    window.set_default_size(320, 240);
    let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
    vbox.pack_start(&video_widget, true, true, 0);

    let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    let position_label = gtk::Label::new(Some("Position: 00:00:00"));
    hbox.pack_start(&position_label, true, true, 5);
    let recorded_duration_label = gtk::Label::new(Some("Recorded: 00:00:00"));
    hbox.pack_start(&recorded_duration_label, true, true, 5);
    vbox.pack_start(&hbox, false, false, 5);

    let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 0);
    let record_button = gtk::Button::new_with_label("Record");
    hbox.pack_start(&record_button, true, true, 5);
    let finish_button = gtk::Button::new_with_label("Finish");
    hbox.pack_start(&finish_button, true, true, 5);
    vbox.pack_start(&hbox, false, false, 5);

    window.add(&vbox);
    window.show_all();

    app.add_window(&window);

    let video_sink_weak = video_sink.downgrade();
    let togglerecord_weak = togglerecord.downgrade();
    let timeout_id = gtk::timeout_add(100, move || {
        let video_sink = match video_sink_weak.upgrade() {
            Some(video_sink) => video_sink,
            None => return glib::Continue(true),
        };

        let togglerecord = match togglerecord_weak.upgrade() {
            Some(togglerecord) => togglerecord,
            None => return glib::Continue(true),
        };

        let position = video_sink
            .query_position::<gst::ClockTime>()
            .unwrap_or_else(|| 0.into());
        position_label.set_text(&format!("Position: {:.1}", position));

        let recording_duration = togglerecord
            .get_static_pad("src")
            .unwrap()
            .query_position::<gst::ClockTime>()
            .unwrap_or_else(|| 0.into());
        recorded_duration_label.set_text(&format!("Recorded: {:.1}", recording_duration));

        glib::Continue(true)
    });

    let togglerecord_weak = togglerecord.downgrade();
    record_button.connect_clicked(move |button| {
        let togglerecord = match togglerecord_weak.upgrade() {
            Some(togglerecord) => togglerecord,
            None => return,
        };

        let recording = !togglerecord
            .get_property("record")
            .unwrap()
            .get::<bool>()
            .unwrap();
        togglerecord.set_property("record", &recording).unwrap();

        button.set_label(if recording { "Stop" } else { "Record" });
    });

    let record_button_weak = record_button.downgrade();
    finish_button.connect_clicked(move |button| {
        let record_button = match record_button_weak.upgrade() {
            Some(record_button) => record_button,
            None => return,
        };

        record_button.set_sensitive(false);
        button.set_sensitive(false);

        video_pad.send_event(gst::Event::new_eos().build());
        audio_pad.send_event(gst::Event::new_eos().build());
    });

    let app_weak = app.downgrade();
    window.connect_delete_event(move |_, _| {
        let app = match app_weak.upgrade() {
            Some(app) => app,
            None => return Inhibit(false),
        };

        app.quit();
        Inhibit(false)
    });

    let bus = pipeline.get_bus().unwrap();
    let app_weak = glib::SendWeakRef::from(app.downgrade());
    bus.add_watch(move |_, msg| {
        use gst::MessageView;

        let app = match app_weak.upgrade() {
            Some(app) => app,
            None => return glib::Continue(false),
        };

        match msg.view() {
            MessageView::Eos(..) => app.quit(),
            MessageView::Error(err) => {
                println!(
                    "Error from {:?}: {} ({:?})",
                    msg.get_src().map(|s| s.get_path_string()),
                    err.get_error(),
                    err.get_debug()
                );
                app.quit();
            }
            _ => (),
        };

        glib::Continue(true)
    });

    pipeline.set_state(gst::State::Playing).unwrap();

    // Pipeline reference is owned by the closure below, so will be
    // destroyed once the app is destroyed
    let timeout_id = RefCell::new(Some(timeout_id));
    app.connect_shutdown(move |_| {
        pipeline.set_state(gst::State::Null).unwrap();

        bus.remove_watch().unwrap();

        if let Some(timeout_id) = timeout_id.borrow_mut().take() {
            glib::source_remove(timeout_id);
        }
    });
}

fn main() {
    gst::init().unwrap();
    gtk::init().unwrap();

    gsttogglerecord::plugin_register_static().expect("Failed to register togglerecord plugin");

    let app = gtk::Application::new(None, gio::ApplicationFlags::FLAGS_NONE).unwrap();

    app.connect_activate(create_ui);
    let args = env::args().collect::<Vec<_>>();
    app.run(&args);
}
<|endoftext|>


<commit_before>//! Facilities for implementing chess engines.

pub mod time_manager;

use std::collections::VecDeque;
use std::ops::Deref;
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use std::cmp::min;
use std::io;
use uci::*;
use search::*;
use self::time_manager::*;

/// Serves UCI commands until a "quit" command is received.
///
/// The current thread will block until the UCI session is closed.
///
/// Returns `Err` if the handshake was unsuccessful, or if an IO error
/// occurred.
pub fn run_server<S: SearchExecutor<ReportData = Vec<Variation>>>() -> io::Result<()> {
    run_engine::<Engine<S>>()
}

/// The chess starting position in Forsyth–Edwards notation (FEN).
const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

/// The version of the program.
const VERSION: &'static str = "0.1";

/// The name of the program.
const NAME: &'static str = "Alcibiades";

/// The author of the program.
const AUTHOR: &'static str = "Evgeni Pandurski";

/// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManager), // Stop when the time manager says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(u64), // Stop when the given number of nodes has been searched.
    Depth(Depth), // Stop when the given search depth has been completed.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
struct Engine<S: SearchExecutor<ReportData = Vec<Variation>>> {
    tt: Arc<S::HashTable>,
    position: S::SearchNode,
    searcher: S,

    // The starting time of the current/last search.
    started_at: SystemTime,

    // The status of the current/last search.
    status: SearchStatus,

    // Tells the engine when it must stop thinking and play the best
    // move it has found.
    play_when: PlayWhen,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // `true` if the engine is thinking in pondering mode at the moment.
    is_pondering: bool,

    // A queue for the messages send by the engine to the GUI.
    queue: VecDeque<EngineReply>,

    // Helps the engine decide when to send periodic progress reports.
    silent_since: SystemTime,
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> UciEngine for Engine<S> {
    fn name() -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author() -> String {
        AUTHOR.to_string()
    }

    fn options() -> Vec<(String, OptionDescription)> {
        // Add up all suported options.
        let mut options = vec![
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 64 * 1024, default: 16 }),
            ("Clear Hash".to_string(), OptionDescription::Button),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ];
        options.extend(S::options());

        // Remove duplicated options.
        options.sort_by(|a, b| a.0.cmp(&b.0));
        let mut options_dedup = vec![];
        let mut prev_name = String::from("");
        for o in options.drain(..) {
            if o.0 == prev_name {
                continue;
            }
            prev_name = o.0.clone();
            options_dedup.push(o);
        }
        options_dedup
    }

    fn new(tt_size_mb: Option<usize>) -> Engine<S> {
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        Engine {
            tt: tt.clone(),
            position: S::SearchNode::from_history(START_FEN, &mut vec![].into_iter()).ok().unwrap(),
            searcher: S::new(tt),
            started_at: SystemTime::now(),
            status: SearchStatus {
                done: true,
                depth: 0,
                searched_nodes: 0,
                duration_millis: 0,
                nps: 0,
            },
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
            is_pondering: false,
            queue: VecDeque::new(),
            silent_since: SystemTime::now(),
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                // TODO: Can we remove this?
                self.pondering_is_allowed = value == "true";
            }
            "Hash" => {
                // We do not support re-sizing of the transposition
                // table once the engine has been started.
                return;
            }
            "Clear Hash" => {
                self.tt.clear();
            }
            _ => (),
        }
        S::set_option(name, value);
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

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

    fn go(&mut self, params: GoParams) {
        // Note: We ignore the "mate" field.
        //
        // TODO: What should we do with "mate"?
        let GoParams { searchmoves,
                       ponder,
                       wtime,
                       btime,
                       winc,
                       binc,
                       movestogo,
                       depth,
                       nodes,
                       movetime,
                       infinite,
                       .. } = params;

        self.terminate();
        self.tt.new_search();
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(min(depth.unwrap(), DEPTH_MAX as u64) as Depth)
        } else {
            PlayWhen::TimeManagement(TimeManager::new(self.position.board().to_move,
                                                      self.pondering_is_allowed,
                                                      wtime,
                                                      btime,
                                                      winc,
                                                      binc,
                                                      movestogo))
        };
        self.silent_since = SystemTime::now();
        self.start(searchmoves);
    }

    fn ponder_hit(&mut self) {
        if self.status.done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.terminate();
        self.queue_best_move();
    }

    fn wait_for_reply(&mut self, duration: Duration) -> Option<EngineReply> {
        if self.queue.is_empty() {
            let done = self.status.done;

            // Wait for `search_thread` to do some work, and hopefully
            // update its status. (We must do this even when the
            // search is done -- in that case the next line will just
            // yield the CPU to another process.)
            self.wait_status_update(duration);

            if !done {
                let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } =
                    &self.status;

                // Check if we must play now.
                if !self.is_pondering &&
                   match self.play_when {
                    PlayWhen::TimeManagement(ref tm) => done || tm.must_play(),
                    PlayWhen::MoveTime(t) => done || duration_millis >= t,
                    PlayWhen::Nodes(n) => done || searched_nodes >= n,
                    PlayWhen::Depth(d) => done || depth >= d,
                    PlayWhen::Never => false,
                } {
                    self.stop();
                }
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.terminate();
    }
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> Engine<S> {
    /// Adds a progress report message to the queue.
    fn queue_progress_report(&mut self) {
        let SearchStatus { ref depth, ref searched_nodes, ref nps, .. } = self.status;
        self.queue.push_back(EngineReply::Info(vec![
            InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
            InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
            InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
        ]));
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current (multi)PV to the queue.
    fn queue_variations(&mut self, variations: &Vec<Variation>) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, ref nps, .. } =
            self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
                InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
                InfoItem { info_type: "multipv".to_string(), data: format!("{}", i + 1) },
                InfoItem { info_type: "score".to_string(), data: format!("cp {}{}", value, bound_suffix) },
                InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
                InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
                InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
                InfoItem { info_type: "pv".to_string(), data: moves_string },
            ]));
        }
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current best move to the queue.
    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position, 2);
        let best_move = if let Some(m) = pv.moves.get(0) {
            m.notation()
        } else {
            // If the PV is empty, pick the first legal move.
            self.position.legal_moves().get(0).map_or("0000".to_string(), |m| m.notation())
        };
        self.queue.push_back(EngineReply::BestMove {
            best_move: best_move,
            ponder_move: pv.moves.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }

    /// Terminates the currently running search (if any), starts a new
    /// search, updates the status.
    fn start(&mut self, mut searchmoves: Vec<String>) {
        // Validate `searchmoves`.
        let mut moves = vec![];
        let legal_moves = self.position.legal_moves();
        if !searchmoves.is_empty() {
            searchmoves.sort();
            for m in legal_moves.iter() {
                if searchmoves.binary_search(&m.notation()).is_ok() {
                    moves.push(*m);
                }
            }
        };
        let searchmoves = if moves.is_empty() {
            legal_moves
        } else {
            moves
        };

        // Terminate the currently running search.
        self.terminate();

        // Update the status.
        self.status = SearchStatus {
            done: false,
            depth: 0,
            searched_nodes: 0,
            duration_millis: 0,
            ..self.status
        };

        // Start a new search.
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: DEPTH_MAX,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
        });
    }

    /// Terminates the currently running search (if any), updates the
    /// status.
    fn terminate(&mut self) {
        self.searcher.terminate_search();
        while !self.status.done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    /// Waits for a search status update, timing out after a specified
    /// duration or earlier.
    fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(r)
        }
    }

    /// A helper method. It updates the current status according to
    /// the received report message.
    fn process_report(&mut self, report: SearchReport<Vec<Variation>>) {
        // Register the search status with the time manager.
        if let PlayWhen::TimeManagement(ref mut tm) = self.play_when {
            tm.update_status(&report);
        }

        let duration = self.started_at.elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        self.status.depth = report.depth;
        self.status.done = report.done;

        // Send the (multi)PV if available.
        if !report.data.is_empty() {
            self.queue_variations(&report.data);
        }

        // Send a progress report periodically.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_report();
        }
    }
}

/// Contains information about the current progress of a search.
struct SearchStatus {
    pub done: bool,
    pub depth: Depth,
    pub searched_nodes: u64,

    /// The duration of the search in milliseconds.
    pub duration_millis: u64,

    /// Average number of analyzed nodes per second.
    pub nps: u64,
}
<commit_msg>remove stupid comments<commit_after>//! Facilities for implementing chess engines.

pub mod time_manager;

use std::collections::VecDeque;
use std::ops::Deref;
use std::sync::Arc;
use std::time::{SystemTime, Duration};
use std::cmp::min;
use std::io;
use uci::*;
use search::*;
use self::time_manager::*;

const NAME: &'static str = "Alcibiades";
const AUTHOR: &'static str = "Evgeni Pandurski";
const VERSION: &'static str = "0.1";
const START_FEN: &'static str = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w QKqk - 0 1";

/// Serves UCI commands until a "quit" command is received.
///
/// The current thread will block until the UCI session is closed.
///
/// Returns `Err` if the handshake was unsuccessful, or if an IO error
/// occurred.
pub fn run_server<S: SearchExecutor<ReportData = Vec<Variation>>>() -> io::Result<()> {
    run_engine::<Engine<S>>()
}

/// Represents a condition for terminating the search.
enum PlayWhen {
    TimeManagement(TimeManager), // Stop when the time manager says.
    MoveTime(u64), // Stop after the given number of milliseconds.
    Nodes(u64), // Stop when the given number of nodes has been searched.
    Depth(Depth), // Stop when the given search depth has been completed.
    Never, // An infinite search.
}

/// Implements `UciEngine` trait.
struct Engine<S: SearchExecutor<ReportData = Vec<Variation>>> {
    tt: Arc<S::HashTable>,
    position: S::SearchNode,
    searcher: S,

    // The starting time of the current/last search.
    started_at: SystemTime,

    // The status of the current/last search.
    status: SearchStatus,

    // Tells the engine when it must stop thinking and play the best
    // move it has found.
    play_when: PlayWhen,

    // Tells the engine if it will be allowed to ponder. This option
    // is needed because the engine might change its time management
    // algorithm when pondering is allowed.
    pondering_is_allowed: bool,

    // Whether the engine is thinking in pondering mode at the moment.
    is_pondering: bool,

    // A queue for the messages send to the GUI.
    queue: VecDeque<EngineReply>,

    // Helps the engine decide when to send periodic progress reports.
    silent_since: SystemTime,
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> UciEngine for Engine<S> {
    fn name() -> String {
        format!("{} {}", NAME, VERSION)
    }

    fn author() -> String {
        AUTHOR.to_string()
    }

    fn options() -> Vec<(String, OptionDescription)> {
        // Add up all suported options.
        let mut options = vec![
            ("Hash".to_string(), OptionDescription::Spin { min: 1, max: 64 * 1024, default: 16 }),
            ("Clear Hash".to_string(), OptionDescription::Button),
            ("Ponder".to_string(), OptionDescription::Check { default: false }),
        ];
        options.extend(S::options());

        // Remove duplicated options.
        options.sort_by(|a, b| a.0.cmp(&b.0));
        let mut options_dedup = vec![];
        let mut prev_name = String::from("");
        for o in options.drain(..) {
            if o.0 == prev_name {
                continue;
            }
            prev_name = o.0.clone();
            options_dedup.push(o);
        }
        options_dedup
    }

    fn new(tt_size_mb: Option<usize>) -> Engine<S> {
        let tt = Arc::new(S::HashTable::new(tt_size_mb));
        Engine {
            tt: tt.clone(),
            position: S::SearchNode::from_history(START_FEN, &mut vec![].into_iter()).ok().unwrap(),
            searcher: S::new(tt),
            started_at: SystemTime::now(),
            status: SearchStatus {
                done: true,
                depth: 0,
                searched_nodes: 0,
                duration_millis: 0,
                nps: 0,
            },
            play_when: PlayWhen::Never,
            pondering_is_allowed: false,
            is_pondering: false,
            queue: VecDeque::new(),
            silent_since: SystemTime::now(),
        }
    }

    fn set_option(&mut self, name: &str, value: &str) {
        match name {
            "Ponder" => {
                // TODO: Can we remove this?
                self.pondering_is_allowed = value == "true";
            }
            "Hash" => {
                // We do not support re-sizing of the transposition
                // table once the engine has been started.
                return;
            }
            "Clear Hash" => {
                self.tt.clear();
            }
            _ => (),
        }
        S::set_option(name, value);
    }

    fn new_game(&mut self) {
        self.tt.clear();
    }

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

    fn go(&mut self, params: GoParams) {
        // Note: We ignore the "mate" field.
        //
        // TODO: What should we do with "mate"?
        let GoParams { searchmoves,
                       ponder,
                       wtime,
                       btime,
                       winc,
                       binc,
                       movestogo,
                       depth,
                       nodes,
                       movetime,
                       infinite,
                       .. } = params;

        self.terminate();
        self.tt.new_search();
        self.is_pondering = ponder;
        self.play_when = if infinite {
            PlayWhen::Never
        } else if movetime.is_some() {
            PlayWhen::MoveTime(movetime.unwrap())
        } else if nodes.is_some() {
            PlayWhen::Nodes(nodes.unwrap())
        } else if depth.is_some() {
            PlayWhen::Depth(min(depth.unwrap(), DEPTH_MAX as u64) as Depth)
        } else {
            PlayWhen::TimeManagement(TimeManager::new(self.position.board().to_move,
                                                      self.pondering_is_allowed,
                                                      wtime,
                                                      btime,
                                                      winc,
                                                      binc,
                                                      movestogo))
        };
        self.silent_since = SystemTime::now();
        self.start(searchmoves);
    }

    fn ponder_hit(&mut self) {
        if self.status.done {
            self.queue_best_move();
        } else {
            self.is_pondering = false;
        }
    }

    fn stop(&mut self) {
        self.terminate();
        self.queue_best_move();
    }

    fn wait_for_reply(&mut self, duration: Duration) -> Option<EngineReply> {
        if self.queue.is_empty() {
            let done = self.status.done;

            // Wait for `search_thread` to do some work, and hopefully
            // update its status. (We must do this even when the
            // search is done -- in that case the next line will just
            // yield the CPU to another process.)
            self.wait_status_update(duration);

            if !done {
                let &SearchStatus { done, depth, searched_nodes, duration_millis, .. } =
                    &self.status;

                // Check if we must play now.
                if !self.is_pondering &&
                   match self.play_when {
                    PlayWhen::TimeManagement(ref tm) => done || tm.must_play(),
                    PlayWhen::MoveTime(t) => done || duration_millis >= t,
                    PlayWhen::Nodes(n) => done || searched_nodes >= n,
                    PlayWhen::Depth(d) => done || depth >= d,
                    PlayWhen::Never => false,
                } {
                    self.stop();
                }
            }
        }

        self.queue.pop_front()
    }

    fn exit(&mut self) {
        self.terminate();
    }
}

impl<S: SearchExecutor<ReportData = Vec<Variation>>> Engine<S> {
    /// Adds a progress report message to the queue.
    fn queue_progress_report(&mut self) {
        let SearchStatus { ref depth, ref searched_nodes, ref nps, .. } = self.status;
        self.queue.push_back(EngineReply::Info(vec![
            InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
            InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
            InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
        ]));
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current (multi)PV to the queue.
    fn queue_pv(&mut self, variations: &Vec<Variation>) {
        let SearchStatus { ref depth, ref searched_nodes, ref duration_millis, ref nps, .. } =
            self.status;
        for (i, &Variation { ref moves, value, bound }) in variations.iter().enumerate() {
            let bound_suffix = match bound {
                BOUND_EXACT => "",
                BOUND_UPPER => " upperbound",
                BOUND_LOWER => " lowerbound",
                _ => panic!("unexpected bound type"),
            };
            let mut moves_string = String::new();
            for m in moves {
                moves_string.push_str(&m.notation());
                moves_string.push(' ');
            }
            self.queue.push_back(EngineReply::Info(vec![
                InfoItem { info_type: "depth".to_string(), data: format!("{}", depth) },
                InfoItem { info_type: "multipv".to_string(), data: format!("{}", i + 1) },
                InfoItem { info_type: "score".to_string(), data: format!("cp {}{}", value, bound_suffix) },
                InfoItem { info_type: "time".to_string(), data: format!("{}", duration_millis) },
                InfoItem { info_type: "nodes".to_string(), data: format!("{}", searched_nodes) },
                InfoItem { info_type: "nps".to_string(), data: format!("{}", nps) },
                InfoItem { info_type: "pv".to_string(), data: moves_string },
            ]));
        }
        self.silent_since = SystemTime::now();
    }

    /// Adds a message containing the current best move to the queue.
    fn queue_best_move(&mut self) {
        let pv = extract_pv(self.tt.deref(), &self.position, 2);
        let best_move = if let Some(m) = pv.moves.get(0) {
            m.notation()
        } else {
            // If the PV is empty, pick the first legal move.
            self.position.legal_moves().get(0).map_or("0000".to_string(), |m| m.notation())
        };
        self.queue.push_back(EngineReply::BestMove {
            best_move: best_move,
            ponder_move: pv.moves.get(1).map(|m| m.notation()),
        });
        self.silent_since = SystemTime::now();
    }

    fn start(&mut self, mut searchmoves: Vec<String>) {
        // Validate `searchmoves`.
        let mut moves = vec![];
        let legal_moves = self.position.legal_moves();
        if !searchmoves.is_empty() {
            searchmoves.sort();
            for m in legal_moves.iter() {
                if searchmoves.binary_search(&m.notation()).is_ok() {
                    moves.push(*m);
                }
            }
        };
        let searchmoves = if moves.is_empty() {
            legal_moves
        } else {
            moves
        };

        // Start a new search.
        self.terminate();
        self.status = SearchStatus {
            done: false,
            depth: 0,
            searched_nodes: 0,
            duration_millis: 0,
            ..self.status
        };
        self.searcher.start_search(SearchParams {
            search_id: 0,
            position: self.position.clone(),
            depth: DEPTH_MAX,
            lower_bound: VALUE_MIN,
            upper_bound: VALUE_MAX,
            searchmoves: searchmoves,
        });
    }

    fn terminate(&mut self) {
        self.searcher.terminate_search();
        while !self.status.done {
            self.wait_status_update(Duration::from_millis(1000));
        }
    }

    fn wait_status_update(&mut self, duration: Duration) {
        self.searcher.wait_report(duration);
        while let Ok(r) = self.searcher.try_recv_report() {
            self.process_report(r)
        }
    }

    fn process_report(&mut self, report: SearchReport<Vec<Variation>>) {
        // Update the search status.
        let duration = self.started_at.elapsed().unwrap();
        self.status.duration_millis = 1000 * duration.as_secs() +
                                      (duration.subsec_nanos() / 1000000) as u64;
        self.status.searched_nodes = report.searched_nodes;
        self.status.nps = 1000 * (self.status.nps + self.status.searched_nodes) /
                          (1000 + self.status.duration_millis);
        self.status.depth = report.depth;
        self.status.done = report.done;

        // Inform the time manager.
        if let PlayWhen::TimeManagement(ref mut tm) = self.play_when {
            tm.update_status(&report);
        }

        // If available, send the PV.
        if !report.data.is_empty() {
            self.queue_pv(&report.data);
        }

        // If nothing has been sent for a while, send a progress report.
        if self.silent_since.elapsed().unwrap().as_secs() > 10 {
            self.queue_progress_report();
        }
    }
}

/// Contains information about the current progress of a search.
struct SearchStatus {
    pub done: bool,
    pub depth: Depth,
    pub searched_nodes: u64,

    /// The duration of the search in milliseconds.
    pub duration_millis: u64,

    /// Average number of analyzed nodes per second.
    pub nps: u64,
}
<|endoftext|>


<commit_before>use raytracer::animator::CameraKeyframe;
use raytracer::Renderer;
use scene::{Camera, Scene};
use std::sync::Arc;
use vec3::Vec3;

pub struct Animator {
    pub fps: f64,
    pub animate_from: f64, // Number of frames is rounded down to nearest frame
    pub animate_to: f64,
    pub starting_frame_number: uint, // For filename
    pub renderer: Renderer
}

// TODO: Non-linear interpolation
// TODO: Improve keyframes (sort/order them as we don't need dynamic keyframe insertion)
impl Animator {
    // TODO: make this a Surface iterator so both single frame and animation
    // process flows are similar
    pub fn animate(&self, camera: Camera, shared_scene: Arc<Scene>, filename: &str) {
        let animate_start = ::time::get_time();
        let length = self.animate_to - self.animate_from;
        let total_frames = (self.fps * length).floor() as uint;

        let (tx, rx) = sync_channel(1);
        tx.send(1i);

        for frame_number in range(0, total_frames) {
            let time = self.animate_from + frame_number as f64 / self.fps;
            let lerped_camera = Animator::lerp_camera(&camera, time);
            let frame_data = self.renderer.render(lerped_camera, shared_scene.clone());

            let file_frame_number = self.starting_frame_number + frame_number;
            let shared_name = format!("{}{:06u}.ppm", filename, file_frame_number);
            let child_tx = tx.clone();

            rx.recv();
            spawn(proc() {
                ::util::export::to_ppm(frame_data, shared_name.as_slice());
                child_tx.send(2i);
            });

            ::util::print_progress("*** Frame", animate_start, frame_number + 1 as uint, total_frames);
            println!("");
        }

        rx.recv();
    }

    fn get_neighbour_keyframes(keyframes: Vec<CameraKeyframe>, time: f64)
                               -> (CameraKeyframe, CameraKeyframe, f64) {

        if keyframes.len() <= 1 {
            fail!("Not enough keyframes to interpolate: got: {} expected: >= 2", keyframes.len());
        }

        // Get the two keyframes inbetween current time
        let mut first = &keyframes[0];
        let mut second = &keyframes[1];

        for keyframe in keyframes.iter() {
            if keyframe.time <= time && time - keyframe.time >= first.time - time {
                first = keyframe;
            }

            if keyframe.time > time &&
               (keyframe.time - time < second.time - time || second.time < time) {
                second = keyframe;
            }
        }

        let keyframe_length = second.time - first.time;
        let alpha = (time - first.time) / keyframe_length;

        (first.clone(), second.clone(), alpha)
    }

    fn lerp_camera(camera: &Camera, time: f64) -> Camera {
        let keyframes = match camera.keyframes.clone() {
            Some(k) => k,
            None => fail!("Cannot lerp a camera with no keyframes!")
        };

        let (first, second, alpha) = Animator::get_neighbour_keyframes(keyframes, time);

        let lerped_position = Vec3::lerp(&first.position, &second.position, alpha);
        let lerped_look_at  = Vec3::lerp(&first.look_at, &second.look_at, alpha);
        let lerped_up       = Vec3::lerp(&first.up, &second.up, alpha);

        let mut lerped_camera = Camera::new(
            lerped_position,
            lerped_look_at,
            lerped_up,
            camera.fov_deg,
            camera.image_width,
            camera.image_height,
        );

        lerped_camera.keyframes = camera.keyframes.clone();
        lerped_camera
    }
}
<commit_msg>Upgrade ghetto semaphore in Animator to a real one<commit_after>use raytracer::animator::CameraKeyframe;
use raytracer::Renderer;
use scene::{Camera, Scene};
use std::sync::{Arc, Semaphore};
use vec3::Vec3;

pub struct Animator {
    pub fps: f64,
    pub animate_from: f64, // Number of frames is rounded down to nearest frame
    pub animate_to: f64,
    pub starting_frame_number: uint, // For filename
    pub renderer: Renderer
}

// TODO: Non-linear interpolation
// TODO: Improve keyframes (sort/order them as we don't need dynamic keyframe insertion)
impl Animator {
    // TODO: make this a Surface iterator so both single frame and animation
    // process flows are similar
    pub fn animate(&self, camera: Camera, shared_scene: Arc<Scene>, filename: &str) {
        let animate_start = ::time::get_time();
        let length = self.animate_to - self.animate_from;
        let total_frames = (self.fps * length).floor() as uint;

        let sema = Arc::new(Semaphore::new(::std::os::num_cpus() as int));

        for frame_number in range(0, total_frames) {
            let time = self.animate_from + frame_number as f64 / self.fps;
            let lerped_camera = Animator::lerp_camera(&camera, time);
            let frame_data = self.renderer.render(lerped_camera, shared_scene.clone());

            let file_frame_number = self.starting_frame_number + frame_number;
            let shared_name = format!("{}{:06u}.ppm", filename, file_frame_number);

            let child_sema = sema.clone();
            sema.acquire();
            spawn(proc() {
                ::util::export::to_ppm(frame_data, shared_name.as_slice());
                child_sema.release();
            });

            ::util::print_progress("*** Frame", animate_start, frame_number + 1 as uint, total_frames);
            println!("");
        }

        sema.acquire();
    }

    fn get_neighbour_keyframes(keyframes: Vec<CameraKeyframe>, time: f64)
                               -> (CameraKeyframe, CameraKeyframe, f64) {

        if keyframes.len() <= 1 {
            fail!("Not enough keyframes to interpolate: got: {} expected: >= 2", keyframes.len());
        }

        // Get the two keyframes inbetween current time
        let mut first = &keyframes[0];
        let mut second = &keyframes[1];

        for keyframe in keyframes.iter() {
            if keyframe.time <= time && time - keyframe.time >= first.time - time {
                first = keyframe;
            }

            if keyframe.time > time &&
               (keyframe.time - time < second.time - time || second.time < time) {
                second = keyframe;
            }
        }

        let keyframe_length = second.time - first.time;
        let alpha = (time - first.time) / keyframe_length;

        (first.clone(), second.clone(), alpha)
    }

    fn lerp_camera(camera: &Camera, time: f64) -> Camera {
        let keyframes = match camera.keyframes.clone() {
            Some(k) => k,
            None => fail!("Cannot lerp a camera with no keyframes!")
        };

        let (first, second, alpha) = Animator::get_neighbour_keyframes(keyframes, time);

        let lerped_position = Vec3::lerp(&first.position, &second.position, alpha);
        let lerped_look_at  = Vec3::lerp(&first.look_at, &second.look_at, alpha);
        let lerped_up       = Vec3::lerp(&first.up, &second.up, alpha);

        let mut lerped_camera = Camera::new(
            lerped_position,
            lerped_look_at,
            lerped_up,
            camera.fov_deg,
            camera.image_width,
            camera.image_height,
        );

        lerped_camera.keyframes = camera.keyframes.clone();
        lerped_camera
    }
}
<|endoftext|>


<commit_before>use std::path::{Path, PathBuf};
use std::vec::Vec;
use error::IndentexError;

const INDENTEX_GLOB: &'static str = "*.inden.tex";

pub fn walk_indentex_files<T: AsRef<Path>>(rootdir: T) -> Result<Vec<PathBuf>, IndentexError> {
    use ignore::WalkBuilder;
    use ignore::types::TypesBuilder;

    // Create a type matcher
    let mut tb = TypesBuilder::new();
    tb.add("indentex", INDENTEX_GLOB).unwrap();
    tb.select("indentex");
    let matcher = tb.build().unwrap();

    // Walk the path
    let mut files: Vec<PathBuf> = Vec::new();
    for res in WalkBuilder::new(rootdir.as_ref()).types(matcher).build() {
        let item = res?;
        if item.file_type().unwrap().is_file() {
            files.push(item.path().to_path_buf());
        }
    }

    Ok(files)
}

#[inline]
fn is_indentex_file<T: AsRef<Path>>(filepath: T) -> bool {
    use globset::Glob;

    let glob = Glob::new(INDENTEX_GLOB).unwrap().compile_matcher();
    glob.is_match(filepath.as_ref())
}

/// Rename an `*.inden.tex` file into `*_inden.tex`
pub fn rename_indentex_file<T: AsRef<Path>>(old_path: T) -> Result<PathBuf, IndentexError> {
    if !is_indentex_file(old_path.as_ref()) {
        return Err(IndentexError::InvalidExtension);
    }

    let mut new_pathbuf = old_path.as_ref().to_path_buf();
    // Strip both extensions, first `.tex` and then `.inden`
    // We assume that the file `old_path` is a valid indentex file,
    // i.e. it has the
    new_pathbuf.set_extension("");
    new_pathbuf.set_extension("");
    // Get the full filename (i.e. with all dots etc. if there are any)
    let mut new_name = new_pathbuf.file_name().unwrap().to_os_string();
    new_name.push("_indentex.tex");
    new_pathbuf.pop();
    new_pathbuf.push(new_name);

    Ok(new_pathbuf)
}

/// Read a file line by line, right-trim lines and _copy_ them into a vec of strings
pub fn read_and_trim_lines<T: AsRef<Path>>(path: T) -> Result<Vec<String>, IndentexError> {
    use std::fs::File;
    use std::io::{BufReader, BufRead};

    if !is_indentex_file(path.as_ref()) {
        return Err(IndentexError::InvalidExtension);
    }

    let file = File::open(path.as_ref())?;
    let buf = BufReader::new(file);

    buf.lines().map(|r| Ok(r?.trim_right().to_string())).collect()
}

pub fn write_to_file<T, U>(path: T, data: U) -> Result<(), IndentexError>
    where T: AsRef<Path>,
          U: AsRef<str>
{

    use std::fs::File;
    use std::io::{BufWriter, Write};

    let file = File::create(path.as_ref())?;
    let mut buf = BufWriter::new(file);
    buf.write(data.as_ref().as_bytes())?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};

    #[test]
    fn is_indentex_file() {
        use super::is_indentex_file;

        assert!(!is_indentex_file(Path::new("foo")));
        assert!(!is_indentex_file(Path::new("foo.tex")));
        assert!(!is_indentex_file(Path::new("foo_inden.tex")));

        assert!(is_indentex_file(Path::new("foo.inden.tex")));
        assert!(is_indentex_file(Path::new("foo.bar.inden.tex")));
    }

    #[test]
    fn rename_indentex_file() {
        use super::rename_indentex_file;

        assert_eq!(rename_indentex_file(Path::new("./foo.inden.tex")).unwrap(),
                   PathBuf::from("./foo_indentex.tex"));
        assert_eq!(rename_indentex_file(Path::new("./foo.bar.inden.tex")).unwrap(),
                   PathBuf::from("./foo.bar_indentex.tex"));
        assert_eq!(rename_indentex_file(Path::new("./.foo.bar.inden.tex")).unwrap(),
                   PathBuf::from("./.foo.bar_indentex.tex"));
        assert_eq!(rename_indentex_file(Path::new("foo.inden.tex")).unwrap(),
                   PathBuf::from("foo_indentex.tex"));
        assert!(rename_indentex_file(Path::new("foo.bar.tex")).is_err())
    }
}
<commit_msg>Fixed unused io write amount<commit_after>use std::path::{Path, PathBuf};
use std::vec::Vec;
use error::IndentexError;

const INDENTEX_GLOB: &'static str = "*.inden.tex";

pub fn walk_indentex_files<T: AsRef<Path>>(rootdir: T) -> Result<Vec<PathBuf>, IndentexError> {
    use ignore::WalkBuilder;
    use ignore::types::TypesBuilder;

    // Create a type matcher
    let mut tb = TypesBuilder::new();
    tb.add("indentex", INDENTEX_GLOB).unwrap();
    tb.select("indentex");
    let matcher = tb.build().unwrap();

    // Walk the path
    let mut files: Vec<PathBuf> = Vec::new();
    for res in WalkBuilder::new(rootdir.as_ref()).types(matcher).build() {
        let item = res?;
        if item.file_type().unwrap().is_file() {
            files.push(item.path().to_path_buf());
        }
    }

    Ok(files)
}

#[inline]
fn is_indentex_file<T: AsRef<Path>>(filepath: T) -> bool {
    use globset::Glob;

    let glob = Glob::new(INDENTEX_GLOB).unwrap().compile_matcher();
    glob.is_match(filepath.as_ref())
}

/// Rename an `*.inden.tex` file into `*_inden.tex`
pub fn rename_indentex_file<T: AsRef<Path>>(old_path: T) -> Result<PathBuf, IndentexError> {
    if !is_indentex_file(old_path.as_ref()) {
        return Err(IndentexError::InvalidExtension);
    }

    let mut new_pathbuf = old_path.as_ref().to_path_buf();
    // Strip both extensions, first `.tex` and then `.inden`
    // We assume that the file `old_path` is a valid indentex file,
    // i.e. it has the
    new_pathbuf.set_extension("");
    new_pathbuf.set_extension("");
    // Get the full filename (i.e. with all dots etc. if there are any)
    let mut new_name = new_pathbuf.file_name().unwrap().to_os_string();
    new_name.push("_indentex.tex");
    new_pathbuf.pop();
    new_pathbuf.push(new_name);

    Ok(new_pathbuf)
}

/// Read a file line by line, right-trim lines and _copy_ them into a vec of strings
pub fn read_and_trim_lines<T: AsRef<Path>>(path: T) -> Result<Vec<String>, IndentexError> {
    use std::fs::File;
    use std::io::{BufReader, BufRead};

    if !is_indentex_file(path.as_ref()) {
        return Err(IndentexError::InvalidExtension);
    }

    let file = File::open(path.as_ref())?;
    let buf = BufReader::new(file);

    buf.lines().map(|r| Ok(r?.trim_right().to_string())).collect()
}

pub fn write_to_file<T, U>(path: T, data: U) -> Result<(), IndentexError>
    where T: AsRef<Path>,
          U: AsRef<str>
{

    use std::fs::File;
    use std::io::{BufWriter, Write};

    let file = File::create(path.as_ref())?;
    let mut buf = BufWriter::new(file);
    buf.write_all(data.as_ref().as_bytes())?;

    Ok(())
}

#[cfg(test)]
mod tests {
    use std::path::{Path, PathBuf};

    #[test]
    fn is_indentex_file() {
        use super::is_indentex_file;

        assert!(!is_indentex_file(Path::new("foo")));
        assert!(!is_indentex_file(Path::new("foo.tex")));
        assert!(!is_indentex_file(Path::new("foo_inden.tex")));

        assert!(is_indentex_file(Path::new("foo.inden.tex")));
        assert!(is_indentex_file(Path::new("foo.bar.inden.tex")));
    }

    #[test]
    fn rename_indentex_file() {
        use super::rename_indentex_file;

        assert_eq!(rename_indentex_file(Path::new("./foo.inden.tex")).unwrap(),
                   PathBuf::from("./foo_indentex.tex"));
        assert_eq!(rename_indentex_file(Path::new("./foo.bar.inden.tex")).unwrap(),
                   PathBuf::from("./foo.bar_indentex.tex"));
        assert_eq!(rename_indentex_file(Path::new("./.foo.bar.inden.tex")).unwrap(),
                   PathBuf::from("./.foo.bar_indentex.tex"));
        assert_eq!(rename_indentex_file(Path::new("foo.inden.tex")).unwrap(),
                   PathBuf::from("foo_indentex.tex"));
        assert!(rename_indentex_file(Path::new("foo.bar.tex")).is_err())
    }
}
<|endoftext|>