<commit_before>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

#![cfg_attr(test, feature(slicing_syntax))]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;

struct Dependency<T> {
    num_prec: uint,
    succ: HashSet<T>
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> uint { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.set(dep);
            },
            Entry::Occupied(mut e) => {
                let mut p = e.get_mut();
                if !p.succ.insert(succ.clone()) { // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.set(dep);
            }
            Entry::Occupied(mut e) => {
                let s = e.get_mut();
                s.num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash + Eq + Clone> Iterator<T> for TopologicalSort<T> {
    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[uint], ts: &mut TopologicalSort<uint>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v[]);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<commit_msg>fix unused attribute warning<commit_after>//! Performs topological sorting.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results, unused_typecasts)]

use std::collections::{HashMap, HashSet};
use std::collections::hash_map::Entry;
use std::hash::Hash;

struct Dependency<T> {
    num_prec: uint,
    succ: HashSet<T>
}

impl<T: Hash + Eq> Dependency<T> {
    fn new() -> Dependency<T> { Dependency { num_prec: 0, succ: HashSet::new() } }
}

/// Performs topological sorting.
pub struct TopologicalSort<T> {
    top: HashMap<T, Dependency<T>>
}

impl<T: Hash + Eq + Clone> TopologicalSort<T> {
    /// Creates new empty `TopologicalSort`.
    ///
    /// ```rust
    /// use tsort::TopologicalSort;
    /// let mut ts = TopologicalSort::new();
    /// ts.add_dependency("hello_world.o", "hello_world");
    /// ts.add_dependency("hello_world.c", "hello_world");
    /// ts.add_dependency("stdio.h", "hello_world.o");
    /// ts.add_dependency("glibc.so", "hello_world");
    /// assert_eq!(vec!["glibc.so", "hello_world.c", "stdio.h"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world.o"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert_eq!(vec!["hello_world"],
    ///            { let mut v = ts.pop_all(); v.sort(); v });
    /// assert!(ts.pop_all().is_empty());
    /// ```
    #[inline]
    pub fn new() -> TopologicalSort<T> { TopologicalSort { top: HashMap::new() } }

    /// Returns the number of elements in the `TopologicalSort`.
    #[inline]
    pub fn len(&self) -> uint { self.top.len() }

    /// Returns true if the `TopologicalSort` contains no elements.
    #[inline]
    pub fn is_empty(&self) -> bool { self.top.is_empty() }

    /// Registers the two elements' dependency.
    ///
    /// # Arguments
    ///
    /// * `prec` - The element appears before `succ`. `prec` is depended on by `succ`.
    /// * `succ` - The element appears after `prec`. `succ` depends on `prec`.
    pub fn add_dependency(&mut self, prec: T, succ: T) {
        match self.top.entry(prec) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.succ.insert(succ.clone());
                let _ = e.set(dep);
            },
            Entry::Occupied(mut e) => {
                let mut p = e.get_mut();
                if !p.succ.insert(succ.clone()) { // Already registered
                    return
                }
            }
        }

        match self.top.entry(succ) {
            Entry::Vacant(e) => {
                let mut dep = Dependency::new();
                dep.num_prec += 1;
                let _ = e.set(dep);
            }
            Entry::Occupied(mut e) => {
                let s = e.get_mut();
                s.num_prec += 1;
            }
        }
    }

    /// Removes the item that is not depended on by any other items and returns it, or `None` if there is no such item.
    ///
    /// If `pop` returns `None` and `len` is not 0, there is cyclic dependencies.
    pub fn pop(&mut self) -> Option<T> {
        self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .next()
            .map(|(k, _)| k.clone())
            .map(|key| {
                let _ = self.remove(&key);
                key
            })
    }

    /// Removes all items that are not depended on by any other items and returns it, or empty vector if there are no such items.
    ///
    /// If `pop_all` returns an empty vector and `len` is not 0, there is cyclic dependencies.
    pub fn pop_all(&mut self) -> Vec<T> {
        let keys = self.top
            .iter()
            .filter(|&(_, v)| v.num_prec == 0)
            .map(|(k, _)| k.clone())
            .collect::<Vec<_>>();
        for k in keys.iter() {
            let _ = self.remove(k);
        }
        keys
    }

    fn remove(&mut self, prec: &T) -> Option<Dependency<T>> {
        let result = self.top.remove(prec);
        if let Some(ref p) = result {
            for s in p.succ.iter() {
                if let Some(y) = self.top.get_mut(s) {
                    y.num_prec -= 1;
                }
            }
        }
        result
    }
}

impl<T: Hash + Eq + Clone> Iterator<T> for TopologicalSort<T> {
    fn next(&mut self) -> Option<T> { self.pop() }
}

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

    #[test]
    fn iter() {
        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(1, 2);
        ts.add_dependency(2, 3);
        ts.add_dependency(3, 4);
        assert_eq!(Some(1), ts.next());
        assert_eq!(Some(2), ts.next());
        assert_eq!(Some(3), ts.next());
        assert_eq!(Some(4), ts.next());
        assert_eq!(None, ts.next());
    }

    #[test]
    fn pop_all() {
        fn check(result: &[uint], ts: &mut TopologicalSort<uint>) {
            let l = ts.len();
            let mut v = ts.pop_all();
            v.sort();
            assert_eq!(result, v);
            assert_eq!(l - result.len(), ts.len());
        }

        let mut ts = TopologicalSort::<uint>::new();
        ts.add_dependency(7, 11);
        assert_eq!(2, ts.len());
        ts.add_dependency(7, 8);
        assert_eq!(3, ts.len());
        ts.add_dependency(5, 11);
        assert_eq!(4, ts.len());
        ts.add_dependency(3, 8);
        assert_eq!(5, ts.len());
        ts.add_dependency(3, 10);
        assert_eq!(6, ts.len());
        ts.add_dependency(11, 2);
        assert_eq!(7, ts.len());
        ts.add_dependency(11, 9);
        assert_eq!(8, ts.len());
        ts.add_dependency(11, 10);
        assert_eq!(8, ts.len());
        ts.add_dependency(8, 9);
        assert_eq!(8, ts.len());

        check(&[3, 5, 7], &mut ts);
        check(&[8, 11], &mut ts);
        check(&[2, 9, 10], &mut ts);
        check(&[], &mut ts);
    }
}

<|endoftext|>


<commit_before>//! Provides an adaptive sampler which will start sampling at
//! one rate and then take more samples if it determines more
//! are necessary for the pixel. The samples generated are the
//! same as those from the Low Discrepancy sampler but the
//! number of samples taken per pixel will vary.

use std::u32;
use std::f32;
use rand::{Rng, StdRng};
use rand::distributions::{IndependentSample, Range};

use sampler::{Sampler, Region, ld};
use film::ImageSample;

/// Adaptive sampler that makes use of the (0, 2) sequence to generate
/// well distributed samples and takes `min_spp` to `max_spp` samples per pixel
pub struct Adaptive {
    region: Region,
    /// Number of samples to take per pixel
    min_spp: usize,
    max_spp: usize,
    /// Number of additional samples to take each time we decide
    /// more samples are needed
    step_size: usize,
    /// How many samples we've taken for this pixel so far
    samples_taken: usize,
    /// The cumulative moving average of the luminance for the
    /// number of samples taken so far
    avg_luminance: f32,
    scramble_range: Range<u32>,
}

impl Adaptive {
    /// Create a low discrepancy sampler to sample the image in `dim.0 * dim.1` sized blocks
    pub fn new(dim: (u32, u32), mut min_spp: usize, mut max_spp: usize) -> Adaptive {
        if !min_spp.is_power_of_two() {
            min_spp = min_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding min_spp up to {}", min_spp);
        }
        if !max_spp.is_power_of_two() {
            max_spp = max_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding max_spp up to {}", max_spp);
        }
        let step_size = ((max_spp - min_spp) / 10).next_power_of_two();
        Adaptive { region: Region::new((0, 0), dim), min_spp: min_spp, max_spp: max_spp,
                   step_size: step_size, samples_taken: 0, avg_luminance: 0.0,
                   scramble_range: Range::new(0, u32::MAX) }
    }
    /// Determine if more samples need to be taken for the pixel currently sampled with the
    /// set of samples passed. This is done by simply looking at the contrast difference
    /// between the samples. TODO: What are some better strategies for estimating
    /// if we need more samples?
    fn needs_supersampling(&mut self, samples: &[ImageSample]) -> bool {
        let max_contrast = 0.5;
        // First sampling pass, compute the initial average luminance
        if self.samples_taken == self.min_spp {
            self.avg_luminance = samples.iter().fold(0.0, |ac, s| ac + s.color.luminance())
                / samples.len() as f32;
        } else {
            // Otherwise update the average luminance to include these samples
            let prev_samples = samples.len() - self.step_size;
            self.avg_luminance = samples.iter().enumerate().skip(prev_samples)
                .fold(self.avg_luminance, |ac, (i, s)| {
                    (s.color.luminance() + (i - 1) as f32 * ac) / i as f32
                });
        }
        // What if we kept and updated the average luminance? The result of this
        // is that we re-inspect samples that we've seen before, eg after one step up of sampling
        // we look at the first min_spp samples again, but we've already computed their average
        // luminance! We should keep a moving average
        for s in samples.iter() {
            if f32::abs(s.color.luminance() - self.avg_luminance) / self.avg_luminance > max_contrast {
                return true;
            }
        }
        return false;
    }
}

impl Sampler for Adaptive {
    fn get_samples(&mut self, samples: &mut Vec<(f32, f32)>, rng: &mut StdRng) {
        samples.clear();
        if !self.has_samples() {
            return;
        }

        if self.samples_taken == 0 {
            self.samples_taken += self.min_spp;
            if samples.len() < self.min_spp {
                samples.resize(self.min_spp, (0.0, 0.0));
            }
        } else {
            self.samples_taken += self.step_size;
            if samples.len() != self.step_size {
                samples.resize(self.step_size, (0.0, 0.0));
            }
        }
        self.get_samples_2d(&mut samples[..], rng);
        for s in samples.iter_mut() {
            s.0 += self.region.current.0 as f32;
            s.1 += self.region.current.1 as f32;
        }
    }
    fn get_samples_2d(&mut self, samples: &mut [(f32, f32)], rng: &mut StdRng) {
        let scramble = (self.scramble_range.ind_sample(rng),
                        self.scramble_range.ind_sample(rng));
        ld::sample_2d(samples, scramble, self.samples_taken as u32);
        rng.shuffle(samples);
    }
    fn get_samples_1d(&mut self, samples: &mut [f32], rng: &mut StdRng) {
        let scramble = self.scramble_range.ind_sample(rng);
        ld::sample_1d(samples, scramble, self.samples_taken as u32);
        rng.shuffle(samples);
    }
    fn max_spp(&self) -> usize { self.max_spp }
    fn has_samples(&self) -> bool { self.region.current.1 != self.region.end.1 }
    fn dimensions(&self) -> (u32, u32) { self.region.dim }
    fn select_block(&mut self, start: (u32, u32)) {
        self.region.select_region(start);
    }
    fn get_region(&self) -> &Region {
        &self.region
    }
    fn report_results(&mut self, samples: &[ImageSample]) -> bool {
        // If we've hit taken the max samples per pixel or don't need to super sample
        // this pixel advance to the next one
        if self.samples_taken >= self.max_spp || !self.needs_supersampling(samples) {
            self.samples_taken = 0;
            self.region.current.0 += 1;
            if self.region.current.0 == self.region.end.0 {
                self.region.current.0 = self.region.start.0;
                self.region.current.1 += 1;
            }
            true
        } else {
            false
        }
    }
}

<commit_msg>Reducing number of steps when doing adaptive sampling<commit_after>//! Provides an adaptive sampler which will start sampling at
//! one rate and then take more samples if it determines more
//! are necessary for the pixel. The samples generated are the
//! same as those from the Low Discrepancy sampler but the
//! number of samples taken per pixel will vary.

use std::u32;
use std::f32;
use rand::{Rng, StdRng};
use rand::distributions::{IndependentSample, Range};

use sampler::{Sampler, Region, ld};
use film::ImageSample;

/// Adaptive sampler that makes use of the (0, 2) sequence to generate
/// well distributed samples and takes `min_spp` to `max_spp` samples per pixel
pub struct Adaptive {
    region: Region,
    /// Number of samples to take per pixel
    min_spp: usize,
    max_spp: usize,
    /// Number of additional samples to take each time we decide
    /// more samples are needed
    step_size: usize,
    /// How many samples we've taken for this pixel so far
    samples_taken: usize,
    /// The cumulative moving average of the luminance for the
    /// number of samples taken so far
    avg_luminance: f32,
    scramble_range: Range<u32>,
}

impl Adaptive {
    /// Create a low discrepancy sampler to sample the image in `dim.0 * dim.1` sized blocks
    pub fn new(dim: (u32, u32), mut min_spp: usize, mut max_spp: usize) -> Adaptive {
        if !min_spp.is_power_of_two() {
            min_spp = min_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding min_spp up to {}", min_spp);
        }
        if !max_spp.is_power_of_two() {
            max_spp = max_spp.next_power_of_two();
            print!("Warning: Adaptive sampler requires power of two samples per pixel, ");
            println!("rounding max_spp up to {}", max_spp);
        }
        let step_size = ((max_spp - min_spp) / 5).next_power_of_two();
        Adaptive { region: Region::new((0, 0), dim), min_spp: min_spp, max_spp: max_spp,
                   step_size: step_size, samples_taken: 0, avg_luminance: 0.0,
                   scramble_range: Range::new(0, u32::MAX) }
    }
    /// Determine if more samples need to be taken for the pixel currently sampled with the
    /// set of samples passed. This is done by simply looking at the contrast difference
    /// between the samples. TODO: What are some better strategies for estimating
    /// if we need more samples?
    fn needs_supersampling(&mut self, samples: &[ImageSample]) -> bool {
        let max_contrast = 0.5;
        // First sampling pass, compute the initial average luminance
        if self.samples_taken == self.min_spp {
            self.avg_luminance = samples.iter().fold(0.0, |ac, s| ac + s.color.luminance())
                / samples.len() as f32;
        } else {
            // Otherwise update the average luminance to include these samples
            let prev_samples = samples.len() - self.step_size;
            self.avg_luminance = samples.iter().enumerate().skip(prev_samples)
                .fold(self.avg_luminance, |ac, (i, s)| {
                    (s.color.luminance() + (i - 1) as f32 * ac) / i as f32
                });
        }
        // What if we kept and updated the average luminance? The result of this
        // is that we re-inspect samples that we've seen before, eg after one step up of sampling
        // we look at the first min_spp samples again, but we've already computed their average
        // luminance! We should keep a moving average
        for s in samples.iter() {
            if f32::abs(s.color.luminance() - self.avg_luminance) / self.avg_luminance > max_contrast {
                return true;
            }
        }
        return false;
    }
}

impl Sampler for Adaptive {
    fn get_samples(&mut self, samples: &mut Vec<(f32, f32)>, rng: &mut StdRng) {
        samples.clear();
        if !self.has_samples() {
            return;
        }

        if self.samples_taken == 0 {
            self.samples_taken += self.min_spp;
            if samples.len() < self.min_spp {
                samples.resize(self.min_spp, (0.0, 0.0));
            }
        } else {
            self.samples_taken += self.step_size;
            if samples.len() != self.step_size {
                samples.resize(self.step_size, (0.0, 0.0));
            }
        }
        self.get_samples_2d(&mut samples[..], rng);
        for s in samples.iter_mut() {
            s.0 += self.region.current.0 as f32;
            s.1 += self.region.current.1 as f32;
        }
    }
    fn get_samples_2d(&mut self, samples: &mut [(f32, f32)], rng: &mut StdRng) {
        let scramble = (self.scramble_range.ind_sample(rng),
                        self.scramble_range.ind_sample(rng));
        ld::sample_2d(samples, scramble, self.samples_taken as u32);
        rng.shuffle(samples);
    }
    fn get_samples_1d(&mut self, samples: &mut [f32], rng: &mut StdRng) {
        let scramble = self.scramble_range.ind_sample(rng);
        ld::sample_1d(samples, scramble, self.samples_taken as u32);
        rng.shuffle(samples);
    }
    fn max_spp(&self) -> usize { self.max_spp }
    fn has_samples(&self) -> bool { self.region.current.1 != self.region.end.1 }
    fn dimensions(&self) -> (u32, u32) { self.region.dim }
    fn select_block(&mut self, start: (u32, u32)) {
        self.region.select_region(start);
    }
    fn get_region(&self) -> &Region {
        &self.region
    }
    fn report_results(&mut self, samples: &[ImageSample]) -> bool {
        // If we've hit taken the max samples per pixel or don't need to super sample
        // this pixel advance to the next one
        if self.samples_taken >= self.max_spp || !self.needs_supersampling(samples) {
            self.samples_taken = 0;
            self.region.current.0 += 1;
            if self.region.current.0 == self.region.end.0 {
                self.region.current.0 = self.region.start.0;
                self.region.current.1 += 1;
            }
            true
        } else {
            false
        }
    }
}

<|endoftext|>


<commit_before>#![crate_type = "bin"]

extern crate sdl2;
extern crate sdl2_image;

use std::env;
use std::path::Path;
use sdl2_image::{self, LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

pub fn run(png: &Path) {

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();
    let _image_context = sdl2_image::init(INIT_PNG | INIT_JPG).unwrap();
    let window = video_subsystem.window("rust-sdl2 demo: Video", 800, 600)
      .position_centered()
      .build()
      .unwrap();

    let mut renderer = window.renderer().software().build().unwrap();
    let texture = renderer.load_texture(png).unwrap();

    renderer.copy(&texture, None, None);
    renderer.present();

    'mainloop: loop {
        for event in sdl_context.event_pump().unwrap().poll_iter() {
            match event {
                Event::Quit{..} |
                Event::KeyDown {keycode: Option::Some(Keycode::Escape), ..} =>
                    break 'mainloop,
                _ => {}
            }
        }
    }
}

fn main() {

    let args: Vec<_> = env::args().collect();

    if args.len() < 2 {
        println!("Usage: cargo run /path/to/image.(png|jpg)")
    } else {
        run(Path::new(&args[1]));
    }
}
<commit_msg>Fix image example<commit_after>extern crate sdl2;

use std::env;
use std::path::Path;
use sdl2::image::{LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::event::Event;
use sdl2::keyboard::Keycode;

pub fn run(png: &Path) {

    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();
    let _image_context = sdl2::image::init(INIT_PNG | INIT_JPG).unwrap();
    let window = video_subsystem.window("rust-sdl2 demo: Video", 800, 600)
      .position_centered()
      .build()
      .unwrap();

    let mut renderer = window.renderer().software().build().unwrap();
    let texture = renderer.load_texture(png).unwrap();

    renderer.copy(&texture, None, None).expect("Render failed");
    renderer.present();

    'mainloop: loop {
        for event in sdl_context.event_pump().unwrap().poll_iter() {
            match event {
                Event::Quit{..} |
                Event::KeyDown {keycode: Option::Some(Keycode::Escape), ..} =>
                    break 'mainloop,
                _ => {}
            }
        }
    }
}

fn main() {

    let args: Vec<_> = env::args().collect();

    if args.len() < 2 {
        println!("Usage: cargo run /path/to/image.(png|jpg)")
    } else {
        run(Path::new(&args[1]));
    }
}
<|endoftext|>


<commit_before>extern crate ggez;
extern crate ggez_goodies;
use ggez::conf;
use ggez::game::{Game, GameState};
use ggez::{GameResult, Context};
use ggez::graphics;
use ggez::timer;
use std::time::Duration;

use ggez_goodies::scene::*;

// First we make a structure to contain the game's state
struct MainState {
    data: i32,
}

struct SceneState1 {
    data: i32,
}

struct Scene1 {
    data: i32,
}

impl SceneState<MainState> for SceneState1 {
    fn load(&mut self) -> Box<Scene<MainState>> {
        Box::new(Scene1 { data: self.data })
    }
    fn name(&self) -> String {
        "Test state".to_string()
    }
}

impl Scene<MainState> for Scene1 {
    fn unload(&mut self) -> Box<SceneState<MainState>> {
        Box::new(SceneState1 { data: self.data })
    }
}

impl Loadable<MainState> for MainState {
    fn load(ctx: &mut ggez::Context, conf: &conf::Conf) -> GameResult<Self>
        where Self: Sized
    {
        Ok(MainState { data: 0 })
    }
    fn default_scene() -> Box<SceneState<MainState> + 'static> {
        Box::new(SceneState1 { data: 1 })
    }
}
// impl GameState for MainState {
// fn load(ctx: &mut Context, _conf: &conf::Conf) -> GameResult<MainState> {
// let font = graphics::Font::new(ctx, "DejaVuSerif.ttf", 48).unwrap();
// let text = graphics::Text::new(ctx, "Hello world!", &font).unwrap();
//
// let s = MainState { data: 1 };
// Ok(s)
// }
//
// fn update(&mut self, _ctx: &mut Context, _dt: Duration) -> GameResult<()> {
// Ok(())
// }
//
// fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
// ctx.renderer.clear();
// try!(graphics::draw(ctx, &mut self.text, None, None));
// ctx.renderer.present();
// timer::sleep_until_next_frame(ctx, 60);
// Ok(())
// }
// }
//

pub fn main() {
    let c = conf::Conf::new();
    let mut game: Game<SceneManager<MainState>> = Game::new("helloworld", c).unwrap();
    if let Err(e) = game.run() {
        println!("Error encountered: {:?}", e);
    } else {
        println!("Game exited cleanly.");
    }
}
<commit_msg>Hey, scene test works!<commit_after>extern crate ggez;
extern crate ggez_goodies;
use ggez::conf;
use ggez::game::{Game, GameState};
use ggez::{GameResult, Context};
use ggez::graphics;
use ggez::timer;
use std::time::Duration;

use ggez_goodies::scene::*;

// First we make a structure to contain the game's state
struct MainState {
    font: graphics::Font,
}

struct SceneState1 {
    time_unloaded: f64,
}

struct Scene1 {
    current_time: f64,
}

impl SceneState<MainState> for SceneState1 {
    fn load(&mut self) -> Box<Scene<MainState>> {
        Box::new(Scene1 { current_time: 0.0 })
    }
    fn name(&self) -> String {
        "Test state".to_string()
    }
}

impl Scene<MainState> for Scene1 {
    fn unload(&mut self) -> Box<SceneState<MainState>> {
        Box::new(SceneState1 { time_unloaded: 0.0 })
    }

    fn update(&mut self,
              _ctx: &mut ggez::Context,
              _dt: Duration,
              _state: &mut MainState)
              -> GameResult<()> {
        Ok(())
    }

    fn draw(&mut self, ctx: &mut ggez::Context, state: &mut MainState) -> GameResult<()> {
        ctx.renderer.clear();
        let text = &mut graphics::Text::new(ctx, "Hello world!", &state.font)?;
        try!(graphics::draw(ctx, text, None, None));
        ctx.renderer.present();
        timer::sleep_until_next_frame(ctx, 60);
        Ok(())
    }
}

impl Loadable<MainState> for MainState {
    fn load(ctx: &mut ggez::Context, conf: &conf::Conf) -> GameResult<Self>
        where Self: Sized
    {
        let font = graphics::Font::new(ctx, "DejaVuSerif.ttf", 48)?;
        Ok(MainState { font: font })
    }
    fn default_scene() -> Box<SceneState<MainState> + 'static> {
        Box::new(SceneState1 { time_unloaded: 0.0 })
    }
}

pub fn main() {
    let c = conf::Conf::new();
    let mut game: Game<SceneManager<MainState>> = Game::new("scenetest", c).unwrap();
    if let Err(e) = game.run() {
        println!("Error encountered: {:?}", e);
    } else {
        println!("Game exited cleanly.");
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use fnv::{FnvHashMap, FnvHashSet};
use graphql_syntax::*;
use interner::StringKey;

pub struct ReachableAst {
    /// The definitions that need to be compiled, includes the project
    /// definitions plus the fragment definitions in the base definitions
    /// reachable from the project definitions.
    pub definitions: Vec<ExecutableDefinition>,
    /// The fragment names added from the base definitions.
    pub base_fragment_names: FnvHashSet<StringKey>,
}

pub fn get_reachable_ast(
    project_definitions: Vec<ExecutableDefinition>,
    base_definitions: Vec<ExecutableDefinition>,
) -> Result<ReachableAst, String> {
    if base_definitions.is_empty() {
        return Ok(ReachableAst {
            definitions: project_definitions,
            base_fragment_names: FnvHashSet::default(),
        });
    }

    let mut reachable_base_asts = FnvHashSet::default();
    let mut base_definitions_map = FnvHashMap::default();

    // Preprocess all base fragment definitions
    // Skipping operations because project definitions can't reference base operations
    for base_definition in base_definitions {
        match &base_definition {
            ExecutableDefinition::Fragment(fragment) => {
                let name = fragment.name.value;
                if base_definitions_map.insert(name, base_definition).is_some() {
                    return Err(format!("duplicate definition of {:?}", name));
                }
            }
            ExecutableDefinition::Operation(_) => {}
        }
    }

    let mut result = project_definitions.clone();

    // Find references from project definitions -> base definitions
    for definition in project_definitions {
        let selections = match definition {
            ExecutableDefinition::Operation(definition) => definition.selections,
            ExecutableDefinition::Fragment(definition) => definition.selections,
        };
        visit_selections(
            &base_definitions_map,
            &mut reachable_base_asts,
            &selections,
            false,
        )?
    }

    for key in &reachable_base_asts {
        let value = base_definitions_map.remove(key).unwrap();
        result.push(value);
    }

    Ok(ReachableAst {
        definitions: result,
        base_fragment_names: reachable_base_asts,
    })
}

fn visit_selections(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    selections: &List<Selection>,
    is_base: bool,
) -> Result<(), String> {
    for selection in &selections.items {
        match selection {
            graphql_syntax::Selection::FragmentSpread(selection) => {
                if is_base || base_definitions_map.contains_key(&selection.name.value) {
                    traverse_base_ast_definition(
                        base_definitions_map,
                        reachable_base_asts,
                        selection.name.value,
                    )?
                }
            }
            graphql_syntax::Selection::LinkedField(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            )?,
            graphql_syntax::Selection::InlineFragment(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            )?,
            _ => {}
        }
    }
    Ok(())
}

fn traverse_base_ast_definition(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    key: StringKey,
) -> Result<(), String> {
    if reachable_base_asts.contains(&key) {
        return Ok(());
    }
    let definition = base_definitions_map.get(&key);
    match definition {
        None => {
            return Err(format!("Missing fragment definition: {}", key));
        }
        Some(definition) => {
            reachable_base_asts.insert(key);
            let selections = match definition {
                ExecutableDefinition::Operation(definition) => &definition.selections,
                ExecutableDefinition::Fragment(definition) => &definition.selections,
            };
            visit_selections(base_definitions_map, reachable_base_asts, selections, true)?
        }
    }
    Ok(())
}
<commit_msg>avoid catch all in visitor<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use fnv::{FnvHashMap, FnvHashSet};
use graphql_syntax::*;
use interner::StringKey;

pub struct ReachableAst {
    /// The definitions that need to be compiled, includes the project
    /// definitions plus the fragment definitions in the base definitions
    /// reachable from the project definitions.
    pub definitions: Vec<ExecutableDefinition>,
    /// The fragment names added from the base definitions.
    pub base_fragment_names: FnvHashSet<StringKey>,
}

pub fn get_reachable_ast(
    project_definitions: Vec<ExecutableDefinition>,
    base_definitions: Vec<ExecutableDefinition>,
) -> Result<ReachableAst, String> {
    if base_definitions.is_empty() {
        return Ok(ReachableAst {
            definitions: project_definitions,
            base_fragment_names: FnvHashSet::default(),
        });
    }

    let mut reachable_base_asts = FnvHashSet::default();
    let mut base_definitions_map = FnvHashMap::default();

    // Preprocess all base fragment definitions
    // Skipping operations because project definitions can't reference base operations
    for base_definition in base_definitions {
        match &base_definition {
            ExecutableDefinition::Fragment(fragment) => {
                let name = fragment.name.value;
                if base_definitions_map.insert(name, base_definition).is_some() {
                    return Err(format!("duplicate definition of {:?}", name));
                }
            }
            ExecutableDefinition::Operation(_) => {}
        }
    }

    let mut result = project_definitions.clone();

    // Find references from project definitions -> base definitions
    for definition in project_definitions {
        let selections = match definition {
            ExecutableDefinition::Operation(definition) => definition.selections,
            ExecutableDefinition::Fragment(definition) => definition.selections,
        };
        visit_selections(
            &base_definitions_map,
            &mut reachable_base_asts,
            &selections,
            false,
        )?
    }

    for key in &reachable_base_asts {
        let value = base_definitions_map.remove(key).unwrap();
        result.push(value);
    }

    Ok(ReachableAst {
        definitions: result,
        base_fragment_names: reachable_base_asts,
    })
}

fn visit_selections(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    selections: &List<Selection>,
    is_base: bool,
) -> Result<(), String> {
    for selection in &selections.items {
        match selection {
            Selection::FragmentSpread(selection) => {
                if is_base || base_definitions_map.contains_key(&selection.name.value) {
                    traverse_base_ast_definition(
                        base_definitions_map,
                        reachable_base_asts,
                        selection.name.value,
                    )?
                }
            }
            Selection::LinkedField(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            )?,
            Selection::InlineFragment(selection) => visit_selections(
                base_definitions_map,
                reachable_base_asts,
                &selection.selections,
                is_base,
            )?,
            Selection::ScalarField(_) => {}
        }
    }
    Ok(())
}

fn traverse_base_ast_definition(
    base_definitions_map: &FnvHashMap<StringKey, ExecutableDefinition>,
    reachable_base_asts: &mut FnvHashSet<StringKey>,
    key: StringKey,
) -> Result<(), String> {
    if reachable_base_asts.contains(&key) {
        return Ok(());
    }
    let definition = base_definitions_map.get(&key);
    match definition {
        None => {
            return Err(format!("Missing fragment definition: {}", key));
        }
        Some(definition) => {
            reachable_base_asts.insert(key);
            let selections = match definition {
                ExecutableDefinition::Operation(definition) => &definition.selections,
                ExecutableDefinition::Fragment(definition) => &definition.selections,
            };
            visit_selections(base_definitions_map, reachable_base_asts, selections, true)?
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use quote::Tokens;
use syn::{Ident, MacroInput};

use attributes::to_metadata_impl;
use string::to_dash_name;

/// Expand the required traits for the derive Commands attribute.
pub fn expand_commands_enum(mut ast: MacroInput) -> Tokens {
    let name = &ast.ident;
    let (metadata_impl, variant_info) = to_metadata_impl(name, &mut ast.body);
    let variant_values = variant_info.names.iter()
        .zip(&variant_info.has_argument)
        .map(|(variant_name, &has_argument)| {
            let ident = Ident::new(variant_name.as_ref());
            let arg_ident = Ident::new("argument");
            if has_argument {
                quote! {
                    #name::#ident(#arg_ident.to_string())
                }
            }
            else {
                quote! {
                    #name::#ident
                }
            }
        });
    let variant_names: Vec<_> = variant_info.names.iter()
        .map(|name| to_dash_name(&name))
        .collect();
    let variant_names = &variant_names;
    let variant_has_argument = &variant_info.has_argument;
    quote! {
        impl ::mg_settings::EnumFromStr for #name {
            fn create(variant: &str, argument: &str) -> ::std::result::Result<#name, String> {
                match variant {
                    #(#variant_names => Ok(#variant_values),)*
                    _ => Err(format!("unknown command {}", variant)),
                }
            }

            fn has_argument(variant: &str) -> ::std::result::Result<bool, String> {
                match variant {
                    #(#variant_names => Ok(#variant_has_argument),)*
                    _ => Err(format!("unknown command {}", variant)),
                }
            }
        }

        #metadata_impl
    }
}
<commit_msg>Fixed clippy warning.<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

use quote::Tokens;
use syn::{Ident, MacroInput};

use attributes::to_metadata_impl;
use string::to_dash_name;

/// Expand the required traits for the derive Commands attribute.
pub fn expand_commands_enum(mut ast: MacroInput) -> Tokens {
    let name = &ast.ident;
    let (metadata_impl, variant_info) = to_metadata_impl(name, &mut ast.body);
    let variant_values = variant_info.names.iter()
        .zip(&variant_info.has_argument)
        .map(|(variant_name, &has_argument)| {
            let ident = Ident::new(variant_name.as_ref());
            let arg_ident = Ident::new("argument");
            if has_argument {
                quote! {
                    #name::#ident(#arg_ident.to_string())
                }
            }
            else {
                quote! {
                    #name::#ident
                }
            }
        });
    let variant_names: Vec<_> = variant_info.names.iter()
        .map(|name| to_dash_name(&name))
        .collect();
    let variant_names = &variant_names;
    let mut variant_names_with_argument = vec![];
    let mut variant_names_without_argument = vec![];
    for (name, &has_argument) in variant_names.iter().zip(variant_info.has_argument.iter()) {
        if has_argument {
            variant_names_with_argument.push(name);
        }
        else {
            variant_names_without_argument.push(name);
        }
    }
    let fn_has_argument = quote!{
        fn has_argument(variant: &str) -> ::std::result::Result<bool, String> {
            match variant {
                #(#variant_names_with_argument)|* => Ok(true),
                #(#variant_names_without_argument)|* => Ok(false),
                _ => Err(format!("unknown command {}", variant)),
            }
        }
    };
    quote! {
        impl ::mg_settings::EnumFromStr for #name {
            fn create(variant: &str, argument: &str) -> ::std::result::Result<#name, String> {
                match variant {
                    #(#variant_names => Ok(#variant_values),)*
                    _ => Err(format!("unknown command {}", variant)),
                }
            }

            #fn_has_argument
        }

        #metadata_impl
    }
}
<|endoftext|>


<commit_before>extern crate translator;

fn main()
{
	let args = std::env::args();
	if args.len() < 2
	{
		println!("Usage:");
		println!("{} <text to translate>", args.take(1).last().unwrap());
		return;
	}

	let text = args.skip(1).fold(String::new(), |result, param| result + " " + &param).trim_left().to_string();

	let translator = translator::Translator::new();
	println!("{}", translator.translate(&text));
}
<commit_msg>unwrap_or<commit_after>extern crate translator;

fn main()
{
	let args = std::env::args();
	if args.len() < 2
	{
		println!("Usage:");
		println!("{} <text to translate>", args.take(1).last().unwrap_or("transliterator".to_string()));
		return;
	}

	let text = args.skip(1).fold(String::new(), |result, param| result + " " + &param).trim_left().to_string();

	let translator = translator::Translator::new();
	println!("{}", translator.translate(&text));
}
<|endoftext|>


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

use syn::{parse_quote, punctuated::Punctuated, FnArg, ReturnType, Token, Type, TypePath};

/// Mod to handle stripping paths off the front of types.

fn unqualify_type_path(mut typ: TypePath) -> TypePath {
    if typ.path.segments.len() > 1 {
        // If we've still got more than one
        // path segment then this is referring to a type within
        // C++ namespaces. Strip them off for now, until cxx supports
        // nested mods within a cxx::bridge.
        // This is 'safe' because earlier code will already have
        // failed with 'DuplicateType' if we had several types called
        // the same thing.
        let last_seg = typ.path.segments.last().unwrap();
        typ.path.segments = parse_quote!(
            #last_seg
        );
    }
    typ
}

fn unqualify_type(typ: Type) -> Type {
    match typ {
        Type::Path(typ) => Type::Path(unqualify_type_path(typ)),
        Type::Reference(mut typeref) => {
            typeref.elem = unqualify_boxed_type(typeref.elem);
            Type::Reference(typeref)
        }
        _ => typ,
    }
}

fn unqualify_boxed_type(typ: Box<Type>) -> Box<Type> {
    Box::new(unqualify_type(*typ))
}

pub(crate) fn unqualify_ret_type(ret_type: ReturnType) -> ReturnType {
    match ret_type {
        ReturnType::Type(tok, boxed_type) => {
            ReturnType::Type(tok, unqualify_boxed_type(boxed_type))
        }
        _ => ret_type,
    }
}

pub(crate) fn unqualify_params(
    params: Punctuated<FnArg, Token![,]>,
) -> Punctuated<FnArg, Token![,]> {
    params
        .into_iter()
        .map(|p| match p {
            FnArg::Typed(mut pt) => {
                pt.ty = unqualify_boxed_type(pt.ty);
                FnArg::Typed(pt)
            }
            _ => p,
        })
        .collect()
}
<commit_msg>Unqualify type arguments.<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use syn::{
    parse_quote, punctuated::Punctuated, FnArg, GenericArgument, PathArguments, PathSegment,
    ReturnType, Token, Type, TypePath,
};

/// Mod to handle stripping paths off the front of types.

fn unqualify_type_path(typ: TypePath) -> TypePath {
    // If we've still got more than one
    // path segment then this is referring to a type within
    // C++ namespaces. Strip them off for now, until cxx supports
    // nested mods within a cxx::bridge.
    // This is 'safe' because earlier code will already have
    // failed with 'DuplicateType' if we had several types called
    // the same thing.
    let last_seg = typ.path.segments.into_iter().last().unwrap();
    let ident = &last_seg.ident;
    let args = match last_seg.arguments {
        PathArguments::AngleBracketed(mut ab) => {
            ab.args = unqualify_punctuated(ab.args);
            PathArguments::AngleBracketed(ab)
        }
        _ => last_seg.arguments.clone(),
    };
    let last_seg: PathSegment = parse_quote!( #ident #args );
    parse_quote!(
        #last_seg
    )
}

fn unqualify_punctuated<P>(pun: Punctuated<GenericArgument, P>) -> Punctuated<GenericArgument, P>
where
    P: Default,
{
    let mut new_pun = Punctuated::new();
    for arg in pun.into_iter() {
        new_pun.push(match arg {
            GenericArgument::Type(t) => GenericArgument::Type(unqualify_type(t)),
            _ => arg,
        });
    }
    new_pun
}

fn unqualify_type(typ: Type) -> Type {
    match typ {
        Type::Path(typ) => Type::Path(unqualify_type_path(typ)),
        Type::Reference(mut typeref) => {
            typeref.elem = unqualify_boxed_type(typeref.elem);
            Type::Reference(typeref)
        }
        _ => typ,
    }
}

fn unqualify_boxed_type(typ: Box<Type>) -> Box<Type> {
    Box::new(unqualify_type(*typ))
}

pub(crate) fn unqualify_ret_type(ret_type: ReturnType) -> ReturnType {
    match ret_type {
        ReturnType::Type(tok, boxed_type) => {
            ReturnType::Type(tok, unqualify_boxed_type(boxed_type))
        }
        _ => ret_type,
    }
}

pub(crate) fn unqualify_params(
    params: Punctuated<FnArg, Token![,]>,
) -> Punctuated<FnArg, Token![,]> {
    params
        .into_iter()
        .map(|p| match p {
            FnArg::Typed(mut pt) => {
                pt.ty = unqualify_boxed_type(pt.ty);
                FnArg::Typed(pt)
            }
            _ => p,
        })
        .collect()
}
<|endoftext|>


<commit_before>
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

// Number of permutations summing to value N
fn find_permutation_sums(values: &[i32], target: i32) -> i32 {

	let indent = 21-values.len();
	//print!("{spacer:>0width$}", spacer=" ", width=indent);
	//println!("{:?} : {}", values, target);

	let mut permutations = 0;
	for i in 0..values.len() {
		let remaining_target = target - values[i];
		if remaining_target < 0 {
			// Current value is too big
			continue;
		} else if remaining_target == 0 {
			// Number is just the right size. Don't check extra values.
			permutations +=1;
			continue;
		} else if i < values.len() - 1 {
			// Check this value plus the sum from remaining values
			let subslice = &values[i+1..values.len()];
			permutations += find_permutation_sums(subslice, remaining_target);
		}
	}
	permutations
}

fn main() {
	let path = Path::new("day17.txt");
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    let reader = BufReader::new(file);
	let mut values: Vec<i32> = reader.lines().map(|so| so.unwrap())
							  .map(|s| s.parse::<i32>().unwrap())
							  .collect();

	values.sort_by(|a, b| b.cmp(a));	// Reverse sort
    println!("{:?}", values);
	let num_permutations_150 = find_permutation_sums(&values[..], 150);
	println!("Number of values summing to 150 is {}", num_permutations_150);

	let test_values = vec![20, 15, 10, 5, 5];
	//println!("{:?}", test_values);
	let num_permutations_25 = find_permutation_sums(&test_values[..], 25);
	//println!("Number of values summing to 25 is {}", num_permutations_25);
	assert_eq!(num_permutations_25, 4);

}
<commit_msg>Added day 17, part 2.<commit_after>
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

// Number of permutations summing to value N
// Values: container sizes
// target: remaining eggnog to be stored
// prior_used: containers used prior to this call
// hist: histogram of container counts
fn find_permutation_sums(values: &[i32], target: i32, prior_used: usize, hist: &mut Vec<i32>) {

	//let indent = 21-values.len();
	//print!("{spacer:>0width$}", spacer=" ", width=indent);
	//println!("{:?} : {}", values, target);

	for i in 0..values.len() {
		let remaining_target = target - values[i];
		if remaining_target < 0 {
			// Current value is too big
			continue;
		} else if remaining_target == 0 {
			// Number is just the right size. Don't check extra values.
			hist[prior_used + 1] += 1; // Record number of containers used
			continue;
		} else if i < values.len() - 1 {
			// Check this value plus the sum from remaining values
			let subslice = &values[i+1..values.len()];
			find_permutation_sums(subslice, remaining_target, prior_used + 1, hist);
		}
	}
}

fn main() {

	{
		let test_values = vec![20, 15, 10, 5, 5];
		let mut hist = vec![0; test_values.len()];
		//println!("{:?}", test_values);
		find_permutation_sums(&test_values[..], 25, 0, &mut hist);
		let num_permutations_25 = hist.iter().fold(0, |sum, x| sum + x);
		//println!("{:?}", hist);
		//println!("Number of test values summing to 25 is {}", num_permutations_25);
		assert_eq!(num_permutations_25, 4);
	}

	let path = Path::new("day17.txt");
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    let reader = BufReader::new(file);
	let mut values: Vec<i32> = reader.lines().map(|so| so.unwrap())
							  .map(|s| s.parse::<i32>().unwrap())
							  .collect();

	values.sort_by(|a, b| b.cmp(a));	// Reverse sort
    println!("Input values: {:?}", values);

	let mut histogram = vec![0; values.len()];
	find_permutation_sums(&values[..], 150, 0, &mut histogram);
	let num_permutations_150 = histogram.iter().fold(0, |sum, x| sum + x);
	assert_eq!(num_permutations_150, 4372);
	println!("Part 1: Number of permutations summing to 150 is {}", num_permutations_150);
	println!("Part 2: histogram {:?}", histogram);
	assert_eq!(histogram[4], 4);

}
<|endoftext|>


<commit_before>
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

// Register constant table
#[derive(Copy,Clone,Debug)]
enum Registers {
    RegA = 0,
    RegB = 1,
}

#[derive(Copy,Clone,Debug)]
enum Command {
    HLF, /* hlf r sets register r to half its current value, then continues with the next instruction. */
    TPL, /* tpl r sets register r to triple its current value, then continues with the next instruction. */
    INC, // inc r increments register r, adding 1 to it, then continues with the next instruction.
    JMP, /* jmp offset is a jump; it continues with the instruction offset away relative to itself. */
    JIE, // jie r, offset is like jmp, but only jumps if register r is even ("jump if even").
    JIO, // jio r, offset is like jmp, but only jumps if register r is 1 ("jump if one", not odd).
}
impl Command {
    fn parse(text: &str) -> Command {
        match text {
            "hlf" => Command::HLF,
            "tpl" => Command::TPL,
            "inc" => Command::INC,
            "jmp" => Command::JMP,
            "jie" => Command::JIE,
            "jio" => Command::JIO,
            _ => panic!("Unknown command {}", text),
        }
    }
}

fn parse_arg_value(text: &str) -> i32 {
    match text {
        "a" | "a," => Registers::RegA as i32,
        "b" | "b," => Registers::RegB as i32,
        _ => {
            match text.parse::<i32>() {
                Ok(num) => num,
                Err(_) => panic!("Unknown argument string {}", text),
            }
        }
    }
}

#[derive(Copy,Clone,Debug)]
struct Instruction {
    command: Command,
    arg_1: i32,
    arg_2: i32,
}

fn read_program_from_file(filename: &str) -> Vec<Instruction> {
    let path = Path::new(filename);
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let file = match File::open(&path) {
        // The `description` method of `io::Error` returns a string that describes the error
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    let reader = BufReader::new(file);
    let lines = reader.lines();

    let mut program: Vec<Instruction> = Vec::new();
    for line in lines {
        let string = line.unwrap();
        let tokens: Vec<&str> = string.split_whitespace().collect();

        //println!("{}", &string);
        let command = Command::parse(tokens[0]);
        let arg_1 = parse_arg_value(tokens[1]);
        let arg_2 = if tokens.len() > 2 {parse_arg_value(tokens[2]) } else {0};

        program.push(Instruction {
            command: command,
            arg_1: arg_1,
            arg_2: arg_2,
        });
    }

    program
}

#[derive(Copy,Clone,Debug)]
struct ProgramState {
    registers: [u32; 2],
    pc: i32, // Program counter
}

fn is_even(num: i32) -> bool {
    num % 2 == 0
}

fn process_instruction( mut state: ProgramState, instruction: Instruction) -> ProgramState {
    // hlf r sets register r to half its current value, then continues with the next instruction.
    // tpl r sets register r to triple its current value, then continues with the next instruction.
    // inc r increments register r, adding 1 to it, then continues with the next instruction.
    // jmp offset is a jump; it continues with the instruction offset away relative to itself.
    // jie r, offset is like jmp, but only jumps if register r is even ("jump if even").
    // jio r, offset is like jmp, but only jumps if register r is 1 ("jump if one", not odd).
    let Instruction{command, arg_1, arg_2} = instruction;
    match command {
        Command::HLF => {
            state.registers[arg_1 as usize] = state.registers[arg_1 as usize] / 2;
            state.pc += 1;
        },
        Command::TPL => {
            state.registers[arg_1 as usize] = state.registers[arg_1 as usize] * 3;
            state.pc += 1;
        },
        Command::INC => {
            state.registers[arg_1 as usize] += 1;
            state.pc += 1;
        },
        Command::JMP => {
            state.pc += arg_1;
        },
        Command::JIE => {
            let reg_value = state.registers[arg_1 as usize] as i32;
            if is_even(reg_value) {
                state.pc += arg_2;
            } else {
                state.pc += 1;
            }
        },
        Command::JIO => {
            let reg_value = state.registers[arg_1 as usize];
            if reg_value == 1 {
                state.pc += arg_2;
            } else {
                state.pc += 1;
            }
        },
    }
    state
}

fn main() {
    let program = read_program_from_file("day23.txt");
    //let program = read_program_from_file("day23_test.txt");
    //println!("{:?}", program);

    let mut state = ProgramState {
        registers: [0; 2],
        pc: 0,
    };

    // Loop until program counter indexes out of the program.
    while state.pc >= 0 && state.pc < program.len() as i32 {

        let instruction = program[state.pc as usize];
        //println!("State: {:?}", &state);
        //println!("Instruction {:?}", &instruction);
        state = process_instruction(state, instruction);
        //println!("PC = {}", state.pc);
    }

    // Check value of register B
    //let reg_a_val = state.registers[Registers::RegA as usize];
    let reg_b_val = state.registers[Registers::RegB as usize];
    println!("Final state is {:?}", state);
    assert_eq!(reg_b_val, 307);
}
<commit_msg>Day 23, part 2.<commit_after>
use std::error::Error;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
use std::path::Path;

// Register constant table
#[derive(Copy,Clone,Debug)]
enum Registers {
    RegA = 0,
    RegB = 1,
}

#[derive(Copy,Clone,Debug)]
enum Command {
    HLF, /* hlf r sets register r to half its current value, then continues with the next instruction. */
    TPL, /* tpl r sets register r to triple its current value, then continues with the next instruction. */
    INC, // inc r increments register r, adding 1 to it, then continues with the next instruction.
    JMP, /* jmp offset is a jump; it continues with the instruction offset away relative to itself. */
    JIE, // jie r, offset is like jmp, but only jumps if register r is even ("jump if even").
    JIO, // jio r, offset is like jmp, but only jumps if register r is 1 ("jump if one", not odd).
}
impl Command {
    fn parse(text: &str) -> Command {
        match text {
            "hlf" => Command::HLF,
            "tpl" => Command::TPL,
            "inc" => Command::INC,
            "jmp" => Command::JMP,
            "jie" => Command::JIE,
            "jio" => Command::JIO,
            _ => panic!("Unknown command {}", text),
        }
    }
}

fn parse_arg_value(text: &str) -> i32 {
    match text {
        "a" | "a," => Registers::RegA as i32,
        "b" | "b," => Registers::RegB as i32,
        _ => {
            match text.parse::<i32>() {
                Ok(num) => num,
                Err(_) => panic!("Unknown argument string {}", text),
            }
        }
    }
}

#[derive(Copy,Clone,Debug)]
struct Instruction {
    command: Command,
    arg_1: i32,
    arg_2: i32,
}

fn read_program_from_file(filename: &str) -> Vec<Instruction> {
    let path = Path::new(filename);
    let display = path.display();

    // Open the path in read-only mode, returns `io::Result<File>`
    let file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", display, Error::description(&why)),
        Ok(file) => file,
    };

    let reader = BufReader::new(file);
    let lines = reader.lines();

    let mut program: Vec<Instruction> = Vec::new();
    for line in lines {
        let string = line.unwrap();
        let tokens: Vec<&str> = string.split_whitespace().collect();
        let command = Command::parse(tokens[0]);
        let arg_1 = parse_arg_value(tokens[1]);
        let arg_2 = if tokens.len() > 2 {
            parse_arg_value(tokens[2])
        } else {
            0
        };

        program.push(Instruction {
            command: command,
            arg_1: arg_1,
            arg_2: arg_2,
        });
    }

    program
}

#[derive(Copy,Clone,Debug)]
struct ProgramState {
    registers: [u32; 2],
    pc: i32, // Program counter
}

fn is_even(num: i32) -> bool {
    num % 2 == 0
}

fn process_instruction(mut state: ProgramState, instruction: Instruction) -> ProgramState {
    // hlf r sets register r to half its current value, then continues with the next instruction.
    // tpl r sets register r to triple its current value, then continues with the next instruction.
    // inc r increments register r, adding 1 to it, then continues with the next instruction.
    // jmp offset is a jump; it continues with the instruction offset away relative to itself.
    // jie r, offset is like jmp, but only jumps if register r is even ("jump if even").
    // jio r, offset is like jmp, but only jumps if register r is 1 ("jump if one", not odd).
    let Instruction { command, arg_1, arg_2 } = instruction;
    match command {
        Command::HLF => {
            state.registers[arg_1 as usize] = state.registers[arg_1 as usize] / 2;
            state.pc += 1;
        }
        Command::TPL => {
            state.registers[arg_1 as usize] = state.registers[arg_1 as usize] * 3;
            state.pc += 1;
        }
        Command::INC => {
            state.registers[arg_1 as usize] += 1;
            state.pc += 1;
        }
        Command::JMP => {
            state.pc += arg_1;
        }
        Command::JIE => {
            let reg_value = state.registers[arg_1 as usize] as i32;
            if is_even(reg_value) {
                state.pc += arg_2;
            } else {
                state.pc += 1;
            }
        }
        Command::JIO => {
            let reg_value = state.registers[arg_1 as usize];
            if reg_value == 1 {
                state.pc += arg_2;
            } else {
                state.pc += 1;
            }
        }
    }
    state
}

fn main() {
    let program = read_program_from_file("day23.txt");

    let mut state = ProgramState {
        registers: [0; 2],
        pc: 0,
    };

    // Loop until program counter indexes out of the program.
    while state.pc >= 0 && state.pc < program.len() as i32 {
        let instruction = program[state.pc as usize];
        state = process_instruction(state, instruction);
    }

    // Check value of register B
    let reg_b_val = state.registers[Registers::RegB as usize];
    println!("Part 1: final state is {:?}", state);
    assert_eq!(reg_b_val, 307);

    // **********
    // Now try with register A starting with value 1.
    state = ProgramState {
        registers: [1, 0],
        pc: 0,
    };

    // Loop until program counter indexes out of the program.
    while state.pc >= 0 && state.pc < program.len() as i32 {
        let instruction = program[state.pc as usize];
        state = process_instruction(state, instruction);
    }

    // Check value of register B
    let reg_b_val = state.registers[Registers::RegB as usize];
    println!("Part 2: final state is {:?}", state);
    assert_eq!(reg_b_val, 160);
}
<|endoftext|>


<commit_before>/// Breadth First Search
pub mod bfs {

    use hex2d::Coordinate;
    use hex2d;

    use std::hash;
    use std::collections::VecDeque;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry::{Occupied,Vacant};

    struct Visited<I = i32>
        where I : hex2d::Integer
        {
            prev : Coordinate<I>,
            dist : u32,
        }

    /// Breadth First Search
    ///
    /// Use BFS to find closest (in walk steps) Coordinates that satisfy `is_dest` and can be
    /// reached with a walk through coordinates for which `can_pass` returns true.
    pub struct Traverser<FCanPass, FIsDest, I = i32> where
        I : hex2d::Integer,
        I : hash::Hash,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {
        visited : HashMap<Coordinate<I>, Visited<I>>,
        to_traverse : VecDeque<Coordinate<I>>,
        can_pass : FCanPass,
        is_dest : FIsDest,
        start : Coordinate<I>,
    }

    impl<FCanPass, FIsDest, I> Traverser<FCanPass, FIsDest, I> where
        I : hex2d::Integer,
        I : hash::Hash,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {

        /// Create a Traverser instance with initial conditions
        pub fn new(can_pass : FCanPass, is_dest : FIsDest, start: Coordinate<I>) -> Traverser<FCanPass, FIsDest, I> {
            let mut to_traverse = VecDeque::new();
            to_traverse.push_back(start);

            let mut visited = HashMap::new();
            visited.insert(start, Visited{prev: start, dist: 0});

            Traverser {
                visited: visited,
                to_traverse: to_traverse,
                can_pass: can_pass,
                is_dest: is_dest,
                start: start,
            }
        }

        /// Find next closest coordinate.
        ///
        /// Can be called multiple times, each time returning next coordinate
        pub fn find(&mut self) -> Option<Coordinate<I>> {

            loop {
                let pos = match self.to_traverse.pop_front() {
                    None => return None,
                    Some(coord) => coord,
                };

                // Traverse before returning, so `find` can be call subsequently
                // for more than just first answer
                if (self.can_pass)(pos) {

                    let &Visited{dist, ..} = self.visited.get(&pos).expect("BFS: Should have been visited already");

                    let dist = dist + 1;

                    for &npos in pos.neighbors().iter() {
                        match self.visited.entry(npos) {
                            Occupied(_) => { /* already visited */ }
                            Vacant(entry) => {
                                entry.insert(Visited{prev: pos, dist: dist});
                                self.to_traverse.push_back(npos);
                            }
                        }
                    }
                }

                if (self.is_dest)(pos) {
                    return Some(pos);
                }
            }
        }

        /// Return neighbor Coordinate to `pos` that is one step closer to
        /// `start` from initial conditions.
        ///
        /// Useful for finding whole path to a Coordinate returned by `find`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace(&self, pos : Coordinate<I>) -> Option<Coordinate<I>> {
            self.visited.get(&pos).map(|entry| entry.prev)
        }

        /// Perform a recursive `backtrace` walk to find a neighbor of `start` that leads to the
        /// Coordinate returned by `find()`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace_last(&self, mut pos : Coordinate<I>) -> Option<Coordinate<I>> {
            loop {
                pos = match self.visited.get(&pos) {
                    None => return None,
                    Some(entry) => {
                        if entry.prev == self.start {
                            return Some(pos);
                        } else {
                            entry.prev
                        }
                    }
                }
            }
        }
    }
}

/// Very tricky, but (hopefully) good enough, recursive LoS algorithm
pub mod los {
    use hex2d;
    use hex2d::Angle::{Left,Right};

    use hex2d::Direction;
    use hex2d::Coordinate;

    fn los_rec<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        start_dir : Direction,
        main_dir : Direction,
        dir : Option<Direction>,
        pdir : Option<Direction>,
    ) where
        I : hex2d::Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {

            let mut light = light;
            let opaq = opaqueness(pos);

            if opaq >= light {
                return;
            } else {
                light = light - opaq;
            }

            visible(pos, light);

            let neighbors = match (dir, pdir) {
                (Some(dir), Some(pdir)) => {
                    if dir == pdir {
                        vec!(dir)
                    } else {
                        vec!(dir, pdir)
                    }
                },
                (Some(dir), None) => {
                    if main_dir == dir {
                        vec!(dir, dir + Left, dir + Right)
                    } else {
                        vec!(dir, main_dir)
                    }
                },
                _ => {
                    vec!(main_dir, main_dir + Left, main_dir + Right)
                }
            };

            for &d in neighbors.iter() {
                let npos = pos + d;
                match dir {
                    Some(_) => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, npos, start_dir, d, Some(d), dir),
                    None => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, npos, start_dir, main_dir, Some(d), dir),
                }
            }
        }

    /// Starting from `pos` in direction `dir`, call `visible` for each visible Coordinate.
    ///
    /// Use `light` as starting range of the LoS. For each visible Coordinate, the value returned
    /// by `opaqueness` will be subtracted from `light` to check if the LoS should finish due to
    /// "lack of visibility". `opaqueness` should typically return 1 for fully transparent
    /// Coordinates, and anything bigger than initial `light` for fully opaque Coordinates.
    pub fn los<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        dirs : &[Direction],
    ) where
        I : hex2d::Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            for dir in dirs.iter() {
                los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, pos, *dir, *dir, None, None);
            }
        }
}

/// Combination of tricky Los with straight line checking
pub mod los2 {
    use hex2d;
    use hex2d::Angle::{Left, Right, Forward};
    use hex2d::Direction;
    use hex2d::Coordinate;
    use num::{FromPrimitive};
    use std::collections::HashSet;
    use std::hash;
    use std::ops::{Add};

    fn los_rec<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        start : Coordinate<I>,
        pos : Coordinate<I>,
        dir : Direction,
        visited : &mut HashSet<Coordinate<I>>,
    ) where
        I : hex2d::Integer,
        I : hash::Hash+Eq,
        for <'a> &'a I: Add<&'a I, Output = I>,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            if visited.contains(&pos) {
                return;
            } else {
                visited.insert(pos);
            }

            let mut opaq_sum1 : I = FromPrimitive::from_i8(0).unwrap();
            let mut last1 = start;

            let mut opaq_sum2 : I = FromPrimitive::from_i8(0).unwrap();
            let mut last2 = start;

            let mut directly_visible = false;
            for &(c1, c2) in start.line_to_with_edge_detection(pos).iter() {
                if opaq_sum1 < light {
                    let opaq1 = opaqueness(c1);
                    opaq_sum1 = opaq_sum1 + opaq1;
                    last1 = c1;
                }

                if opaq_sum2 < light {
                    let opaq2 = opaqueness(c2);
                    opaq_sum2 = opaq_sum2 + opaq2;
                    last2 = c2;
                }
            };

            if last1 == pos {
                visible(pos, light - opaq_sum1);
                directly_visible = true;
            } else if  last2 == pos {
                visible(pos, light - opaq_sum2);
                directly_visible = true;
            }

            if !directly_visible {

                let dir_to = start.direction_to_cw(pos).unwrap_or(dir);
                let neighbors = vec!(Left, Right);
                for npos in neighbors.iter()
                    .map(|&rd| dir_to + rd)
                        .map(|dir| pos + dir) {

                            let mut opaq_sum1 : I = FromPrimitive::from_i8(0).unwrap();
                            let mut last1 = start;

                            let mut opaq_sum2 : I = FromPrimitive::from_i8(0).unwrap();
                            let mut last2 = start;

                            for &(c1, c2) in start.line_to_with_edge_detection(npos).iter() {
                                if opaq_sum1 < light {
                                    let opaq1 = opaqueness(c1);
                                    opaq_sum1 = opaq_sum1 + opaq1;
                                    last1 = c1;
                                }

                                if opaq_sum2 < light {
                                    let opaq2 = opaqueness(c2);
                                    opaq_sum2 = opaq_sum2 + opaq2;
                                    last2 = c2;
                                }
                            };

                            if last1 == npos {
                                visible(pos, light - opaq_sum1);
                            } else if last2 == npos {
                                visible(pos, light - opaq_sum2);
                            }
                        }
                return;
            }

            let neighbors = vec!(Forward, Left, Right);

            for &a in neighbors.iter() {
                let npos = pos + (dir + a);
                los_rec::<FOpaqueness, FVisible, I>(
                    opaqueness, visible, light, start, npos, dir, visited
                    );
            }
        }

    /// Starting from `pos` in direction `dir`, call `visible` for each visible Coordinate.
    ///
    /// Use `light` as starting range of the LoS. For each visible Coordinate, the value returned
    /// by `opaqueness` will be subtracted from `light` to check if the LoS should finish due to
    /// "lack of visibility". `opaqueness` should typically return 1 for fully transparent
    /// Coordinates, and anything bigger than initial `light` for fully opaque Coordinates.
    pub fn los<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        dirs : &[Direction],
    ) where
        I : hex2d::Integer,
        I : hash::Hash,
        for <'a> &'a I: Add<&'a I, Output = I>,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            for dir in dirs.iter() {
                let mut visited = HashSet::new();
                los_rec::<FOpaqueness, FVisible, I>(
                    opaqueness, visible, light, pos, pos, *dir, &mut visited
                    );
            }
        }
}
<commit_msg>Improve a los2 algorithm.<commit_after>/// Breadth First Search
pub mod bfs {

    use hex2d::Coordinate;
    use hex2d;

    use std::hash;
    use std::collections::VecDeque;
    use std::collections::HashMap;
    use std::collections::hash_map::Entry::{Occupied,Vacant};

    struct Visited<I = i32>
        where I : hex2d::Integer
        {
            prev : Coordinate<I>,
            dist : u32,
        }

    /// Breadth First Search
    ///
    /// Use BFS to find closest (in walk steps) Coordinates that satisfy `is_dest` and can be
    /// reached with a walk through coordinates for which `can_pass` returns true.
    pub struct Traverser<FCanPass, FIsDest, I = i32> where
        I : hex2d::Integer,
        I : hash::Hash,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {
        visited : HashMap<Coordinate<I>, Visited<I>>,
        to_traverse : VecDeque<Coordinate<I>>,
        can_pass : FCanPass,
        is_dest : FIsDest,
        start : Coordinate<I>,
    }

    impl<FCanPass, FIsDest, I> Traverser<FCanPass, FIsDest, I> where
        I : hex2d::Integer,
        I : hash::Hash,
        FCanPass : Fn(Coordinate<I>) -> bool,
        FIsDest : Fn(Coordinate<I>) -> bool
    {

        /// Create a Traverser instance with initial conditions
        pub fn new(can_pass : FCanPass, is_dest : FIsDest, start: Coordinate<I>) -> Traverser<FCanPass, FIsDest, I> {
            let mut to_traverse = VecDeque::new();
            to_traverse.push_back(start);

            let mut visited = HashMap::new();
            visited.insert(start, Visited{prev: start, dist: 0});

            Traverser {
                visited: visited,
                to_traverse: to_traverse,
                can_pass: can_pass,
                is_dest: is_dest,
                start: start,
            }
        }

        /// Find next closest coordinate.
        ///
        /// Can be called multiple times, each time returning next coordinate
        pub fn find(&mut self) -> Option<Coordinate<I>> {

            loop {
                let pos = match self.to_traverse.pop_front() {
                    None => return None,
                    Some(coord) => coord,
                };

                // Traverse before returning, so `find` can be call subsequently
                // for more than just first answer
                if (self.can_pass)(pos) {

                    let &Visited{dist, ..} = self.visited.get(&pos).expect("BFS: Should have been visited already");

                    let dist = dist + 1;

                    for &npos in pos.neighbors().iter() {
                        match self.visited.entry(npos) {
                            Occupied(_) => { /* already visited */ }
                            Vacant(entry) => {
                                entry.insert(Visited{prev: pos, dist: dist});
                                self.to_traverse.push_back(npos);
                            }
                        }
                    }
                }

                if (self.is_dest)(pos) {
                    return Some(pos);
                }
            }
        }

        /// Return neighbor Coordinate to `pos` that is one step closer to
        /// `start` from initial conditions.
        ///
        /// Useful for finding whole path to a Coordinate returned by `find`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace(&self, pos : Coordinate<I>) -> Option<Coordinate<I>> {
            self.visited.get(&pos).map(|entry| entry.prev)
        }

        /// Perform a recursive `backtrace` walk to find a neighbor of `start` that leads to the
        /// Coordinate returned by `find()`.
        ///
        /// Returns `None` for Coordinates that were not yet visited.
        /// Returns `start` for `start` (from initial conditions)
        pub fn backtrace_last(&self, mut pos : Coordinate<I>) -> Option<Coordinate<I>> {
            loop {
                pos = match self.visited.get(&pos) {
                    None => return None,
                    Some(entry) => {
                        if entry.prev == self.start {
                            return Some(pos);
                        } else {
                            entry.prev
                        }
                    }
                }
            }
        }
    }
}

/// Very tricky, but (hopefully) good enough, recursive LoS algorithm
pub mod los {
    use hex2d;
    use hex2d::Angle::{Left,Right};

    use hex2d::Direction;
    use hex2d::Coordinate;

    fn los_rec<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        start_dir : Direction,
        main_dir : Direction,
        dir : Option<Direction>,
        pdir : Option<Direction>,
    ) where
        I : hex2d::Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {

            let mut light = light;
            let opaq = opaqueness(pos);

            if opaq >= light {
                return;
            } else {
                light = light - opaq;
            }

            visible(pos, light);

            let neighbors = match (dir, pdir) {
                (Some(dir), Some(pdir)) => {
                    if dir == pdir {
                        vec!(dir)
                    } else {
                        vec!(dir, pdir)
                    }
                },
                (Some(dir), None) => {
                    if main_dir == dir {
                        vec!(dir, dir + Left, dir + Right)
                    } else {
                        vec!(dir, main_dir)
                    }
                },
                _ => {
                    vec!(main_dir, main_dir + Left, main_dir + Right)
                }
            };

            for &d in neighbors.iter() {
                let npos = pos + d;
                match dir {
                    Some(_) => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, npos, start_dir, d, Some(d), dir),
                    None => los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, npos, start_dir, main_dir, Some(d), dir),
                }
            }
        }

    /// Starting from `pos` in direction `dir`, call `visible` for each visible Coordinate.
    ///
    /// Use `light` as starting range of the LoS. For each visible Coordinate, the value returned
    /// by `opaqueness` will be subtracted from `light` to check if the LoS should finish due to
    /// "lack of visibility". `opaqueness` should typically return 1 for fully transparent
    /// Coordinates, and anything bigger than initial `light` for fully opaque Coordinates.
    pub fn los<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        dirs : &[Direction],
    ) where
        I : hex2d::Integer,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            for dir in dirs.iter() {
                los_rec::<FOpaqueness, FVisible, I>(opaqueness, visible, light, pos, *dir, *dir, None, None);
            }
        }
}

/// Combination of tricky Los with straight line checking
pub mod los2 {
    use hex2d;
    use hex2d::Angle::{Left, Right, Forward};
    use hex2d::Direction;
    use hex2d::Coordinate;
    use num::{FromPrimitive};
    use std::collections::HashSet;
    use std::hash;
    use std::ops::{Add};
    use std::cmp;

    fn los_check_line<FOpaqueness, I=u32>(
        opaqueness : &FOpaqueness,
        light: I,
        start : Coordinate<I>,
        pos : Coordinate<I>,
        dir : Direction,
        ) -> (bool, I)
        where
        I : hex2d::Integer,
        I : hash::Hash+Eq,
        for <'a> &'a I: Add<&'a I, Output = I>,
        FOpaqueness : Fn(Coordinate<I>) -> I,
    {

        let mut opaq_sum1 : I = FromPrimitive::from_i8(0).unwrap();
        let mut last1 = start;

        let mut opaq_sum2 : I = FromPrimitive::from_i8(0).unwrap();
        let mut last2 = start;

        for &(c1, c2) in start.line_to_with_edge_detection(pos).iter() {
            if opaq_sum1 < light {
                let opaq1 = opaqueness(c1);
                opaq_sum1 = opaq_sum1 + opaq1;
                last1 = c1;
            }

            if opaq_sum2 < light {
                let opaq2 = opaqueness(c2);
                opaq_sum2 = opaq_sum2 + opaq2;
                last2 = c2;
            }
        };

        match (last1 == pos, last2 == pos) {
            (true, true) => (true, light - cmp::min(opaq_sum1, opaq_sum2)),
            (true, false) => (true, light - opaq_sum1),
            (false, true) => (true, light - opaq_sum2),
            (false, false) => (false, light - light),
        }
    }

    fn los_rec<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        start : Coordinate<I>,
        pos : Coordinate<I>,
        dir : Direction,
        visited : &mut HashSet<Coordinate<I>>,
    ) where
        I : hex2d::Integer,
        I : hash::Hash+Eq,
        for <'a> &'a I: Add<&'a I, Output = I>,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            if visited.contains(&pos) {
                return;
            } else {
                visited.insert(pos);
            }

            let (directly_visible, v_light) = los_check_line(
                opaqueness,
                light,
                start,
                pos,
                dir);

            if directly_visible {
                visible(pos, v_light);
            } else {
                let dir_to = start.direction_to_cw(pos).unwrap_or(dir);
                let neighbors = vec!(Left, Right);
                for npos in neighbors.iter()
                    .map(|&rd| dir_to + rd)
                        .map(|dir| pos + dir) {

                            let (side_visible, v_light) = los_check_line(
                                opaqueness,
                                light,
                                start,
                                npos,
                                dir);

                            if side_visible {
                                visible(pos, v_light);
                            }
                        }
                return;
            }

            let neighbors = vec!(Forward, Left, Right);

            for &a in neighbors.iter() {
                let npos = pos + (dir + a);
                los_rec::<FOpaqueness, FVisible, I>(
                    opaqueness, visible, light, start, npos, dir, visited
                    );
            }
        }

    /// Starting from `pos` in direction `dir`, call `visible` for each visible Coordinate.
    ///
    /// Use `light` as starting range of the LoS. For each visible Coordinate, the value returned
    /// by `opaqueness` will be subtracted from `light` to check if the LoS should finish due to
    /// "lack of visibility". `opaqueness` should typically return 1 for fully transparent
    /// Coordinates, and anything bigger than initial `light` for fully opaque Coordinates.
    pub fn los<FOpaqueness, FVisible, I=i32>(
        opaqueness : &FOpaqueness,
        visible : &mut FVisible,
        light: I,
        pos : Coordinate<I>,
        dirs : &[Direction],
    ) where
        I : hex2d::Integer,
        I : hash::Hash,
        for <'a> &'a I: Add<&'a I, Output = I>,
        FOpaqueness : Fn(Coordinate<I>) -> I,
        FVisible : FnMut(Coordinate<I>, I)
        {
            for dir in dirs.iter() {
                let mut visited = HashSet::new();
                los_rec::<FOpaqueness, FVisible, I>(
                    opaqueness, visible, light, pos, pos, *dir, &mut visited
                    );
            }
        }
}
<|endoftext|>