<commit_before>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// 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.

#![feature(duration_span)]

extern crate argparse;
extern crate num;

use num::{Num, Zero, One, Signed};
use std::iter::FromIterator;
use std::cmp::Ordering;

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn min_dx(x: &[f64]) -> f64 {
    // https://doc.rust-lang.org/std/primitive.slice.html#method.windows
    let mdx = x.windows(2) // iterator for adjacent pairs of a slice
               .map(|w| w[1]-w[0]) // i.e. [x[0], x[1]], [x[1], x[2]] ...
               .fold(std::f64::MAX, |x1, x2| x1.min(x2)); // `fold` to find `min`
    mdx
}

#[test]
fn test_min_dx() {

    fn sub<T: Num + Copy>(lhs: &[T], rhs: &[T]) -> Vec<T> {
        Vec::from_iter (lhs.iter().zip(rhs.iter()) .map(|(&x,&y)| x - y ) )
    }

    // 1. prepare non-equidistant vector `x`
    let base_dx = std::f64::consts::FRAC_PI_4; // 0.785398
    let mut x = Vec::from_iter ((1..7) .map(|idx| ((idx as f64).sin() * base_dx).cos().abs() ) );

    x.sort_by(|&x, &y|
        if      x < y { Ordering::Less }
        else if x > y { Ordering::Greater }
        else { Ordering::Equal } );

    let delta_x = sub(&x, &[0.7295467223444416, 0.7556433468867207, 0.7894463883160331,
                            0.8284895327495356, 0.9760168013869176, 0.9938640428738624]);

    let inf_norm = delta_x .iter() .fold(delta_x[0].abs(), |x1, x2| (x1).max((*x2).abs()));

    assert!(inf_norm < 1e-10, "inf_norm");

    // classical way
    let mut min_dx1 = std::f64::MAX;
    for i in 0 .. x.len()-1 {
        min_dx1 = min_dx1.min(x[i+1]-x[i]);
    }

    // functional way
    let min_dx2 = min_dx(&x);
    let abs_delta = (min_dx1 - min_dx2).abs();
    println!("abs_delta : {} min_dx1 : {} min_dx2 : {} x : {:?}", abs_delta, min_dx1, min_dx2, x);
    assert!(abs_delta < 1e-10, "min_dx");
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>,
                  fp_way: bool)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic+2]=u[ncells+1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic+2]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie+1];
        }

        // conservative difference
        if !fp_way {
            for ic in ifirst .. ilast {
                u[ic] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
            }
        } else {
            let dfdx = Vec::from_iter( flux.windows(2)
                                    .zip( x.windows(2) )
                                           .map(|(f,x)|
                                            (f[1] - f[0]) / (x[1] - x[0]) ) );
            for ic in ifirst .. ilast {
                u[ic] -= dfdx[ic];
            }
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+2;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    let mindx = min_dx(&x);
    let dt = cfl*mindx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u, true);
        }
    });
    println!("elapsed time: {}s.", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<commit_msg>fix indices for scl.<commit_after>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// 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.

#![feature(duration_span)]

extern crate argparse;
extern crate num;

use num::{Num, Zero, One, Signed};
use std::iter::FromIterator;
use std::cmp::Ordering;

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn min_dx(x: &[f64]) -> f64 {
    // https://doc.rust-lang.org/std/primitive.slice.html#method.windows
    let mdx = x.windows(2) // iterator for adjacent pairs of a slice
               .map(|w| w[1]-w[0]) // i.e. [x[0], x[1]], [x[1], x[2]] ...
               .fold(std::f64::MAX, |x1, x2| x1.min(x2)); // `fold` to find `min`
    mdx
}

#[test]
fn test_min_dx() {

    fn sub<T: Num + Copy>(lhs: &[T], rhs: &[T]) -> Vec<T> {
        Vec::from_iter (lhs.iter().zip(rhs.iter()) .map(|(&x,&y)| x - y ) )
    }

    // 1. prepare non-equidistant vector `x`
    let base_dx = std::f64::consts::FRAC_PI_4; // 0.785398
    let mut x = Vec::from_iter ((1..7) .map(|idx| ((idx as f64).sin() * base_dx).cos().abs() ) );

    x.sort_by(|&x, &y|
        if      x < y { Ordering::Less }
        else if x > y { Ordering::Greater }
        else { Ordering::Equal } );

    let delta_x = sub(&x, &[0.7295467223444416, 0.7556433468867207, 0.7894463883160331,
                            0.8284895327495356, 0.9760168013869176, 0.9938640428738624]);

    let inf_norm = delta_x .iter() .fold(delta_x[0].abs(), |x1, x2| (x1).max((*x2).abs()));

    assert!(inf_norm < 1e-10, "inf_norm");

    // classical way
    let mut min_dx1 = std::f64::MAX;
    for i in 0 .. x.len()-1 {
        min_dx1 = min_dx1.min(x[i+1]-x[i]);
    }

    // functional way
    let min_dx2 = min_dx(&x);
    let abs_delta = (min_dx1 - min_dx2).abs();
    println!("abs_delta : {} min_dx1 : {} min_dx2 : {} x : {:?}", abs_delta, min_dx1, min_dx2, x);
    assert!(abs_delta < 1e-10, "min_dx");
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>,
                  fp_way: bool)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic+2]=u[ncells+1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic+2]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie+1];
        }

        // conservative difference
        if !fp_way {
            for ic in ifirst .. ilast {
                u[ic+2] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
            }
        } else {
            let dfdx = Vec::from_iter( flux.windows(2)
                                    .zip( x.windows(2) )
                                           .map(|(f,x)|
                                            (f[1] - f[0]) / (x[1] - x[0]) ) );
            for ic in ifirst .. ilast {
                u[ic+2] -= dfdx[ic];
            }
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+2;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    let mindx = min_dx(&x);
    let dt = cfl*mindx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u, true);
        }
    });
    println!("elapsed time: {}s.", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<|endoftext|>


<commit_before>//! User input.

use std::io::{self, Read, Write};
use std::ops;

use event::{self, Event, Key};
use raw::IntoRawMode;

/// An iterator over input keys.
pub struct Keys<R> {
    iter: Events<R>,
}

impl<R: Read> Iterator for Keys<R> {
    type Item = Result<Key, io::Error>;

    fn next(&mut self) -> Option<Result<Key, io::Error>> {
        loop {
            match self.iter.next() {
                Some(Ok(Event::Key(k))) => return Some(Ok(k)),
                Some(Ok(_)) => continue,
                e @ Some(Err(_)) => e,
                None => return None,
            };
        }
    }
}

/// An iterator over input events.
pub struct Events<R> {
    source: R,
    leftover: Option<u8>,
}

impl<R: Read> Iterator for Events<R> {
    type Item = Result<Event, io::Error>;

    fn next(&mut self) -> Option<Result<Event, io::Error>> {
        let mut source = &mut self.source;

        if let Some(c) = self.leftover {
            // we have a leftover byte, use it
            self.leftover = None;
            return Some(parse_event(c, &mut source.bytes()));
        }

        // Here we read two bytes at a time. We need to distinguish between single ESC key presses,
        // and escape sequences (which start with ESC or a x1B byte). The idea is that if this is
        // an escape sequence, we will read multiple bytes (the first byte being ESC) but if this
        // is a single ESC keypress, we will only read a single byte.
        let mut buf = [0u8; 2];
        let res = match source.read(&mut buf) {
            Ok(0) => return None,
            Ok(1) => {
                match buf[0] {
                    b'\x1B' => Ok(Event::Key(Key::Esc)),
                    c => parse_event(c, &mut source.bytes()),
                }
            }
            Ok(2) => {
                let mut option_iter = &mut Some(buf[1]).into_iter();
                let result = {
                    let mut iter = option_iter.map(|c| Ok(c)).chain(source.bytes());
                    parse_event(buf[0], &mut iter)
                };
                // If the option_iter wasn't consumed, keep the byte for later.
                self.leftover = option_iter.next();
                result
            }
            Ok(_) => unreachable!(),
            Err(e) => Err(e),
        };

        Some(res)
    }
}

fn parse_event<I>(item: u8, iter: &mut I) -> Result<Event, io::Error>
    where I: Iterator<Item = Result<u8, io::Error>>
{
    let mut buf = vec![item];
    let result = {
        let mut iter = iter.inspect(|byte| if let &Ok(byte) = byte {
                                        buf.push(byte);
                                    });
        event::parse_event(item, &mut iter)
    };
    result.or(Ok(Event::Unsupported(buf)))
}

/// Extension to `Read` trait.
pub trait TermRead {
    /// An iterator over input events.
    fn events(self) -> Events<Self> where Self: Sized;

    /// An iterator over key inputs.
    fn keys(self) -> Keys<Self> where Self: Sized;

    /// Read a line.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_line(&mut self) -> io::Result<Option<String>>;

    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> {
        let _raw = try!(writer.into_raw_mode());
        self.read_line()
    }
}

impl<R: Read> TermRead for R {
    fn events(self) -> Events<Self> {
        Events {
            source: self,
            leftover: None,
        }
    }
    fn keys(self) -> Keys<Self> {
        Keys { iter: self.events() }
    }

    fn read_line(&mut self) -> io::Result<Option<String>> {
        let mut buf = Vec::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(e) => return Err(e),
                Ok(0) | Ok(3) | Ok(4) => return Ok(None),
                Ok(0x7f) => {
                    buf.pop();
                }
                Ok(b'\n') | Ok(b'\r') => break,
                Ok(c) => buf.push(c),
            }
        }

        let string = try!(String::from_utf8(buf)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)));
        Ok(Some(string))
    }
}

/// A sequence of escape codes to enable terminal mouse support.
const ENTER_MOUSE_SEQUENCE: &'static str = csi!("?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h");

/// A sequence of escape codes to disable terminal mouse support.
const EXIT_MOUSE_SEQUENCE: &'static str = csi!("?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l");

/// A terminal with added mouse support.
///
/// This can be obtained through the `From` implementations.
pub struct MouseTerminal<W: Write> {
    term: W,
}

impl<W: Write> From<W> for MouseTerminal<W> {
    fn from(mut from: W) -> MouseTerminal<W> {
        from.write_all(ENTER_MOUSE_SEQUENCE.as_bytes()).unwrap();

        MouseTerminal { term: from }
    }
}

impl<W: Write> Drop for MouseTerminal<W> {
    fn drop(&mut self) {
        self.term.write_all(EXIT_MOUSE_SEQUENCE.as_bytes()).unwrap();
    }
}

impl<W: Write> ops::Deref for MouseTerminal<W> {
    type Target = W;

    fn deref(&self) -> &W {
        &self.term
    }
}

impl<W: Write> ops::DerefMut for MouseTerminal<W> {
    fn deref_mut(&mut self) -> &mut W {
        &mut self.term
    }
}

impl<W: Write> Write for MouseTerminal<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.term.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.term.flush()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io;
    use event::{Key, Event, MouseEvent, MouseButton};

    #[test]
    fn test_keys() {
        let mut i = b"\x1Bayo\x7F\x1B[D".keys();

        assert_eq!(i.next().unwrap().unwrap(), Key::Alt('a'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('y'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('o'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Backspace);
        assert_eq!(i.next().unwrap().unwrap(), Key::Left);
        assert!(i.next().is_none());
    }

    #[test]
    fn test_events() {
        let mut i =
            b"\x1B[\x00bc\x7F\x1B[D\
                    \x1B[M\x00\x22\x24\x1B[<0;2;4;M\x1B[32;2;4M\x1B[<0;2;4;m\x1B[35;2;4Mb"
                    .events();

        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Unsupported(vec![0x1B, b'[', 0x00]));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('b')));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('c')));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Backspace));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Left));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Press(MouseButton::WheelUp, 2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Release(2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Release(2, 4)));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('b')));
        assert!(i.next().is_none());
    }

    #[test]
    fn test_function_keys() {
        let mut st = b"\x1BOP\x1BOQ\x1BOR\x1BOS".keys();
        for i in 1..5 {
            assert_eq!(st.next().unwrap().unwrap(), Key::F(i));
        }

        let mut st = b"\x1B[11~\x1B[12~\x1B[13~\x1B[14~\x1B[15~\
        \x1B[17~\x1B[18~\x1B[19~\x1B[20~\x1B[21~\x1B[23~\x1B[24~"
                .keys();
        for i in 1..13 {
            assert_eq!(st.next().unwrap().unwrap(), Key::F(i));
        }
    }

    #[test]
    fn test_special_keys() {
        let mut st = b"\x1B[2~\x1B[H\x1B[7~\x1B[5~\x1B[3~\x1B[F\x1B[8~\x1B[6~".keys();
        assert_eq!(st.next().unwrap().unwrap(), Key::Insert);
        assert_eq!(st.next().unwrap().unwrap(), Key::Home);
        assert_eq!(st.next().unwrap().unwrap(), Key::Home);
        assert_eq!(st.next().unwrap().unwrap(), Key::PageUp);
        assert_eq!(st.next().unwrap().unwrap(), Key::Delete);
        assert_eq!(st.next().unwrap().unwrap(), Key::End);
        assert_eq!(st.next().unwrap().unwrap(), Key::End);
        assert_eq!(st.next().unwrap().unwrap(), Key::PageDown);
        assert!(st.next().is_none());
    }

    #[test]
    fn test_esc_key() {
        let mut st = b"\x1B".keys();
        assert_eq!(st.next().unwrap().unwrap(), Key::Esc);
        assert!(st.next().is_none());
    }

    fn line_match(a: &str, b: Option<&str>) {
        let mut sink = io::sink();

        let line = a.as_bytes().read_line().unwrap();
        let pass = a.as_bytes().read_passwd(&mut sink).unwrap();

        // godammit rustc

        assert_eq!(line, pass);

        if let Some(l) = line {
            assert_eq!(Some(l.as_str()), b);
        } else {
            assert!(b.is_none());
        }
    }

    #[test]
    fn test_read() {
        let test1 = "this is the first test";
        let test2 = "this is the second test";

        line_match(test1, Some(test1));
        line_match(test2, Some(test2));
    }

    #[test]
    fn test_backspace() {
        line_match("this is the\x7f first\x7f\x7f test",
                   Some("this is th fir test"));
        line_match("this is the seco\x7fnd test\x7f",
                   Some("this is the secnd tes"));
    }

    #[test]
    fn test_end() {
        line_match("abc\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ",
                   Some("abc"));
        line_match("hello\rhttps://www.youtube.com/watch?v=yPYZpwSpKmA",
                   Some("hello"));
    }

    #[test]
    fn test_abort() {
        line_match("abc\x03https://www.youtube.com/watch?v=dQw4w9WgXcQ", None);
        line_match("hello\x04https://www.youtube.com/watch?v=yPYZpwSpKmA", None);
    }

}
<commit_msg>Add EventsAndRaw iter and implement it for Read<commit_after>//! User input.

use std::io::{self, Read, Write};
use std::ops;

use event::{self, Event, Key};
use raw::IntoRawMode;

/// An iterator over input keys.
pub struct Keys<R> {
    iter: Events<R>,
}

impl<R: Read> Iterator for Keys<R> {
    type Item = Result<Key, io::Error>;

    fn next(&mut self) -> Option<Result<Key, io::Error>> {
        loop {
            match self.iter.next() {
                Some(Ok(Event::Key(k))) => return Some(Ok(k)),
                Some(Ok(_)) => continue,
                e @ Some(Err(_)) => e,
                None => return None,
            };
        }
    }
}

/// An iterator over input events.
pub struct Events<R>  {
    inner: EventsAndRaw<R>
}

impl<R: Read> Iterator for Events<R> {
    type Item = Result<Event, io::Error>;

    fn next(&mut self) -> Option<Result<Event, io::Error>> {
        self.inner.next().map(|tuple| tuple.map(|(event, _raw)| event))
    }
}

/// An iterator over input events and the bytes that define them.
pub struct EventsAndRaw<R> {
    source: R,
    leftover: Option<u8>,
}

impl<R: Read> Iterator for EventsAndRaw<R> {
    type Item = Result<(Event, Vec<u8>), io::Error>;

    fn next(&mut self) -> Option<Result<(Event, Vec<u8>), io::Error>> {
        let mut source = &mut self.source;

        if let Some(c) = self.leftover {
            // we have a leftover byte, use it
            self.leftover = None;
            return Some(parse_event(c, &mut source.bytes()));
        }

        // Here we read two bytes at a time. We need to distinguish between single ESC key presses,
        // and escape sequences (which start with ESC or a x1B byte). The idea is that if this is
        // an escape sequence, we will read multiple bytes (the first byte being ESC) but if this
        // is a single ESC keypress, we will only read a single byte.
        let mut buf = [0u8; 2];
        let res = match source.read(&mut buf) {
            Ok(0) => return None,
            Ok(1) => {
                match buf[0] {
                    b'\x1B' => Ok((Event::Key(Key::Esc), vec![b'\x1B'])),
                    c => parse_event(c, &mut source.bytes()),
                }
            }
            Ok(2) => {
                let mut option_iter = &mut Some(buf[1]).into_iter();
                let result = {
                    let mut iter = option_iter.map(|c| Ok(c)).chain(source.bytes());
                    parse_event(buf[0], &mut iter)
                };
                // If the option_iter wasn't consumed, keep the byte for later.
                self.leftover = option_iter.next();
                result
            }
            Ok(_) => unreachable!(),
            Err(e) => Err(e),
        };

        Some(res)
    }
}

fn parse_event<I>(item: u8, iter: &mut I) -> Result<(Event, Vec<u8>), io::Error>
    where I: Iterator<Item = Result<u8, io::Error>>
{
    let mut buf = vec![item];
    let result = {
        let mut iter = iter.inspect(|byte| if let &Ok(byte) = byte {
                                        buf.push(byte);
                                    });
        event::parse_event(item, &mut iter)
    };
    result.or(Ok(Event::Unsupported(buf.clone()))).map(|e| (e, buf))
}

/// Extension to `Read` trait.
pub trait TermRead {
    /// An iterator over input events.
    fn events(self) -> Events<Self> where Self: Sized;

    /// An iterator over key inputs.
    fn keys(self) -> Keys<Self> where Self: Sized;

    /// Read a line.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_line(&mut self) -> io::Result<Option<String>>;

    /// Read a password.
    ///
    /// EOT and ETX will abort the prompt, returning `None`. Newline or carriage return will
    /// complete the input.
    fn read_passwd<W: Write>(&mut self, writer: &mut W) -> io::Result<Option<String>> {
        let _raw = try!(writer.into_raw_mode());
        self.read_line()
    }
}

impl<R: Read + TermReadEventsAndRaw> TermRead for R {
    fn events(self) -> Events<Self> {
        Events {
            inner: self.events_and_raw()
        }
    }
    fn keys(self) -> Keys<Self> {
        Keys { iter: self.events() }
    }

    fn read_line(&mut self) -> io::Result<Option<String>> {
        let mut buf = Vec::with_capacity(30);

        for c in self.bytes() {
            match c {
                Err(e) => return Err(e),
                Ok(0) | Ok(3) | Ok(4) => return Ok(None),
                Ok(0x7f) => {
                    buf.pop();
                }
                Ok(b'\n') | Ok(b'\r') => break,
                Ok(c) => buf.push(c),
            }
        }

        let string = try!(String::from_utf8(buf)
            .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)));
        Ok(Some(string))
    }
}

/// Extension to `TermRead` trait. A separate trait in order to maintain backwards compatibility.
pub trait TermReadEventsAndRaw {
    /// An iterator over input events and the bytes that define them.
    fn events_and_raw(self) -> EventsAndRaw<Self> where Self: Sized;
}

impl<R: Read> TermReadEventsAndRaw for R {
    fn events_and_raw(self) -> EventsAndRaw<Self> {
        EventsAndRaw {
            source: self,
            leftover: None,
        }
    }
}

/// A sequence of escape codes to enable terminal mouse support.
const ENTER_MOUSE_SEQUENCE: &'static str = csi!("?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h");

/// A sequence of escape codes to disable terminal mouse support.
const EXIT_MOUSE_SEQUENCE: &'static str = csi!("?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l");

/// A terminal with added mouse support.
///
/// This can be obtained through the `From` implementations.
pub struct MouseTerminal<W: Write> {
    term: W,
}

impl<W: Write> From<W> for MouseTerminal<W> {
    fn from(mut from: W) -> MouseTerminal<W> {
        from.write_all(ENTER_MOUSE_SEQUENCE.as_bytes()).unwrap();

        MouseTerminal { term: from }
    }
}

impl<W: Write> Drop for MouseTerminal<W> {
    fn drop(&mut self) {
        self.term.write_all(EXIT_MOUSE_SEQUENCE.as_bytes()).unwrap();
    }
}

impl<W: Write> ops::Deref for MouseTerminal<W> {
    type Target = W;

    fn deref(&self) -> &W {
        &self.term
    }
}

impl<W: Write> ops::DerefMut for MouseTerminal<W> {
    fn deref_mut(&mut self) -> &mut W {
        &mut self.term
    }
}

impl<W: Write> Write for MouseTerminal<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.term.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.term.flush()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::io;
    use event::{Key, Event, MouseEvent, MouseButton};

    #[test]
    fn test_keys() {
        let mut i = b"\x1Bayo\x7F\x1B[D".keys();

        assert_eq!(i.next().unwrap().unwrap(), Key::Alt('a'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('y'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Char('o'));
        assert_eq!(i.next().unwrap().unwrap(), Key::Backspace);
        assert_eq!(i.next().unwrap().unwrap(), Key::Left);
        assert!(i.next().is_none());
    }

    #[test]
    fn test_events() {
        let mut i =
            b"\x1B[\x00bc\x7F\x1B[D\
                    \x1B[M\x00\x22\x24\x1B[<0;2;4;M\x1B[32;2;4M\x1B[<0;2;4;m\x1B[35;2;4Mb"
                    .events();

        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Unsupported(vec![0x1B, b'[', 0x00]));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('b')));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('c')));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Backspace));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Left));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Press(MouseButton::WheelUp, 2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Release(2, 4)));
        assert_eq!(i.next().unwrap().unwrap(),
                   Event::Mouse(MouseEvent::Release(2, 4)));
        assert_eq!(i.next().unwrap().unwrap(), Event::Key(Key::Char('b')));
        assert!(i.next().is_none());
    }

    #[test]
    fn test_events_and_raw() {
        let input = b"\x1B[\x00bc\x7F\x1B[D\
                    \x1B[M\x00\x22\x24\x1B[<0;2;4;M\x1B[32;2;4M\x1B[<0;2;4;m\x1B[35;2;4Mb";
        let mut output = Vec::<u8>::new();
        {
            let mut i = input.events_and_raw().map(|res| res.unwrap())
                .inspect(|&(_, ref raw)| { output.extend(raw); }).map(|(event, _)| event);

            assert_eq!(i.next().unwrap(),
            Event::Unsupported(vec![0x1B, b'[', 0x00]));
            assert_eq!(i.next().unwrap(), Event::Key(Key::Char('b')));
            assert_eq!(i.next().unwrap(), Event::Key(Key::Char('c')));
            assert_eq!(i.next().unwrap(), Event::Key(Key::Backspace));
            assert_eq!(i.next().unwrap(), Event::Key(Key::Left));
            assert_eq!(i.next().unwrap(),
            Event::Mouse(MouseEvent::Press(MouseButton::WheelUp, 2, 4)));
            assert_eq!(i.next().unwrap(),
            Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4)));
            assert_eq!(i.next().unwrap(),
            Event::Mouse(MouseEvent::Press(MouseButton::Left, 2, 4)));
            assert_eq!(i.next().unwrap(),
            Event::Mouse(MouseEvent::Release(2, 4)));
            assert_eq!(i.next().unwrap(),
            Event::Mouse(MouseEvent::Release(2, 4)));
            assert_eq!(i.next().unwrap(), Event::Key(Key::Char('b')));
            assert!(i.next().is_none());
        }

        assert_eq!(input.iter().map(|b| *b).collect::<Vec<u8>>(), output)
    }

    #[test]
    fn test_function_keys() {
        let mut st = b"\x1BOP\x1BOQ\x1BOR\x1BOS".keys();
        for i in 1..5 {
            assert_eq!(st.next().unwrap().unwrap(), Key::F(i));
        }

        let mut st = b"\x1B[11~\x1B[12~\x1B[13~\x1B[14~\x1B[15~\
        \x1B[17~\x1B[18~\x1B[19~\x1B[20~\x1B[21~\x1B[23~\x1B[24~"
                .keys();
        for i in 1..13 {
            assert_eq!(st.next().unwrap().unwrap(), Key::F(i));
        }
    }

    #[test]
    fn test_special_keys() {
        let mut st = b"\x1B[2~\x1B[H\x1B[7~\x1B[5~\x1B[3~\x1B[F\x1B[8~\x1B[6~".keys();
        assert_eq!(st.next().unwrap().unwrap(), Key::Insert);
        assert_eq!(st.next().unwrap().unwrap(), Key::Home);
        assert_eq!(st.next().unwrap().unwrap(), Key::Home);
        assert_eq!(st.next().unwrap().unwrap(), Key::PageUp);
        assert_eq!(st.next().unwrap().unwrap(), Key::Delete);
        assert_eq!(st.next().unwrap().unwrap(), Key::End);
        assert_eq!(st.next().unwrap().unwrap(), Key::End);
        assert_eq!(st.next().unwrap().unwrap(), Key::PageDown);
        assert!(st.next().is_none());
    }

    #[test]
    fn test_esc_key() {
        let mut st = b"\x1B".keys();
        assert_eq!(st.next().unwrap().unwrap(), Key::Esc);
        assert!(st.next().is_none());
    }

    fn line_match(a: &str, b: Option<&str>) {
        let mut sink = io::sink();

        let line = a.as_bytes().read_line().unwrap();
        let pass = a.as_bytes().read_passwd(&mut sink).unwrap();

        // godammit rustc

        assert_eq!(line, pass);

        if let Some(l) = line {
            assert_eq!(Some(l.as_str()), b);
        } else {
            assert!(b.is_none());
        }
    }

    #[test]
    fn test_read() {
        let test1 = "this is the first test";
        let test2 = "this is the second test";

        line_match(test1, Some(test1));
        line_match(test2, Some(test2));
    }

    #[test]
    fn test_backspace() {
        line_match("this is the\x7f first\x7f\x7f test",
                   Some("this is th fir test"));
        line_match("this is the seco\x7fnd test\x7f",
                   Some("this is the secnd tes"));
    }

    #[test]
    fn test_end() {
        line_match("abc\nhttps://www.youtube.com/watch?v=dQw4w9WgXcQ",
                   Some("abc"));
        line_match("hello\rhttps://www.youtube.com/watch?v=yPYZpwSpKmA",
                   Some("hello"));
    }

    #[test]
    fn test_abort() {
        line_match("abc\x03https://www.youtube.com/watch?v=dQw4w9WgXcQ", None);
        line_match("hello\x04https://www.youtube.com/watch?v=yPYZpwSpKmA", None);
    }

}
<|endoftext|>


<commit_before>extern crate x11_dl;
extern crate regex;

use self::x11_dl::{xlib, xtest};
use std::ffi::CString;
use std::os::raw::*;
use std::ptr;
use self::regex::Regex;

use super::{MouseControllable, KeyboardControllable};

pub struct Enigo {
    pub display: *mut xlib::Display,
    pub window: xlib::Window,
    pub xlib: xlib::Xlib,
    pub xtest: xtest::Xf86vmode,
}

impl Enigo {
    pub fn new() -> Self {
        unsafe {
            let xlib = xlib::Xlib::open().unwrap();
            let xtest = xtest::Xf86vmode::open().unwrap();

            let display = (xlib.XOpenDisplay)(ptr::null());
            if display.is_null() {
                panic!("can't open display");
            }

            let window = (xlib.XDefaultRootWindow)(display);

            Enigo {
                display: display,
                window: window,
                xlib: xlib,
                xtest: xtest,
            }
        }
    }

    //TODO(dustin): implement drop
}

impl Default for Enigo {
    fn default() -> Self {
        Self::new()
    }
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, self.window, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, 0, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    //TODO(dustin): make button a new type
    fn mouse_down(&mut self, button: u32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 1, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_up(&mut self, button: u32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 0, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_click(&mut self, button: u32) {
        use std::{thread, time};

        self.mouse_down(button);
        thread::sleep(time::Duration::from_millis(100));
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = 6; //scroll left button
        } else {
            button = 7; //scroll right button
        }

        if length < 0 {
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = 4; //scroll up button
        } else {
            button = 5; //scroll down button
        }

        if length < 0 {
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&self, sequence: &str) {
        lazy_static! {
            //NOTE(dustin): no error handling nessesary, this is a bug
            static ref RE: Regex = Regex::new(r"\\u\{(.*)\}").unwrap();
        }

        for c in sequence.chars() {
            let rust_unicode: String = c.escape_unicode().collect();
            //TODO(dustin): handle this error
            let unicode_string =
                format!("U{}",
                        RE.captures(&rust_unicode).unwrap().get(1).unwrap().as_str());
            let keycode = self.unicode_string_to_keycode(&unicode_string);
            self.keycode_click(keycode)
        }
    }
}

impl Enigo {
    fn unicode_string_to_keycode(&self, unicode_string: &str) -> i32 {

        let unicode_as_c_string = CString::new(unicode_string).unwrap();
        let key_sym =
            unsafe { (self.xlib.XStringToKeysym)(unicode_as_c_string.as_ptr() as *mut c_char) };

        let mut min = 0;
        let mut max = 0;
        let mut numcodes = 0;

        unsafe { (self.xlib.XDisplayKeycodes)(self.display, &mut min, &mut max) };

        let upper = max as i32 - min as i32 + 1;
        let key_sym_mapped = unsafe {
            (self.xlib.XGetKeyboardMapping)(self.display, min as u8, upper, &mut numcodes)
        };
        let idx = ((max as i32 - min as i32 - 1) * numcodes as i32) as isize;

        unsafe {
            let map = key_sym_mapped.offset(idx);
            *map = key_sym;
        }

        unsafe {
            (self.xlib.XChangeKeyboardMapping)(self.display,
                                               min as i32,
                                               numcodes as i32,
                                               key_sym_mapped,
                                               (max as i32 - min as i32));
            (self.xlib.XFree)(key_sym_mapped as *mut c_void);
            (self.xlib.XFlush)(self.display);
            let keycode = (self.xlib.XKeysymToKeycode)(self.display, key_sym);

            keycode as i32
        }

    }

    fn keycode_click(&self, keycode: i32) {
        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));
        self.keycode_down(keycode);
        self.keycode_up(keycode);
        thread::sleep(time::Duration::from_millis(20));
    }

    fn keycode_down(&self, keycode: i32) {
        unsafe {
            (self.xtest.XTestFakeKeyEvent)(self.display, keycode as u32, 1, 1);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn keycode_up(&self, keycode: i32) {
        unsafe {
            (self.xtest.XTestFakeKeyEvent)(self.display, keycode as u32, 0, 1);
            (self.xlib.XFlush)(self.display);
        }
    }
}
<commit_msg>depublic enigo fields in linux implementation<commit_after>extern crate x11_dl;
extern crate regex;

use self::x11_dl::{xlib, xtest};
use std::ffi::CString;
use std::os::raw::*;
use std::ptr;
use self::regex::Regex;

use super::{MouseControllable, KeyboardControllable};

pub struct Enigo {
    display: *mut xlib::Display,
    window: xlib::Window,
    xlib: xlib::Xlib,
    xtest: xtest::Xf86vmode,
}

impl Enigo {
    pub fn new() -> Self {
        unsafe {
            let xlib = xlib::Xlib::open().unwrap();
            let xtest = xtest::Xf86vmode::open().unwrap();

            let display = (xlib.XOpenDisplay)(ptr::null());
            if display.is_null() {
                panic!("can't open display");
            }

            let window = (xlib.XDefaultRootWindow)(display);

            Enigo {
                display: display,
                window: window,
                xlib: xlib,
                xtest: xtest,
            }
        }
    }

    //TODO(dustin): implement drop
}

impl Default for Enigo {
    fn default() -> Self {
        Self::new()
    }
}

impl MouseControllable for Enigo {
    fn mouse_move_to(&mut self, x: i32, y: i32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, self.window, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_move_relative(&mut self, x: i32, y: i32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            (self.xlib.XWarpPointer)(self.display, 0, 0, 0, 0, 0, 0, x, y);
            (self.xlib.XFlush)(self.display);
        }
    }

    //TODO(dustin): make button a new type
    fn mouse_down(&mut self, button: u32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 1, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_up(&mut self, button: u32) {
        if self.display.is_null() {
            panic!("display is not available")
        }

        unsafe {
            //TODO(dustin): make 1, 0 / true false a new type
            (self.xtest.XTestFakeButtonEvent)(self.display, button, 0, 0);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn mouse_click(&mut self, button: u32) {
        use std::{thread, time};

        self.mouse_down(button);
        thread::sleep(time::Duration::from_millis(100));
        self.mouse_up(button);
    }

    fn mouse_scroll_x(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = 6; //scroll left button
        } else {
            button = 7; //scroll right button
        }

        if length < 0 {
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }

    fn mouse_scroll_y(&mut self, length: i32) {
        let button;
        let mut length = length;

        if length < 0 {
            button = 4; //scroll up button
        } else {
            button = 5; //scroll down button
        }

        if length < 0 {
            length *= -1;
        }

        for _ in 0..length {
            self.mouse_down(button);
            self.mouse_up(button);
        }
    }
}

impl KeyboardControllable for Enigo {
    fn key_sequence(&self, sequence: &str) {
        lazy_static! {
            //NOTE(dustin): no error handling nessesary, this is a bug
            static ref RE: Regex = Regex::new(r"\\u\{(.*)\}").unwrap();
        }

        for c in sequence.chars() {
            let rust_unicode: String = c.escape_unicode().collect();
            //TODO(dustin): handle this error
            let unicode_string =
                format!("U{}",
                        RE.captures(&rust_unicode).unwrap().get(1).unwrap().as_str());
            let keycode = self.unicode_string_to_keycode(&unicode_string);
            self.keycode_click(keycode)
        }
    }
}

impl Enigo {
    fn unicode_string_to_keycode(&self, unicode_string: &str) -> i32 {

        let unicode_as_c_string = CString::new(unicode_string).unwrap();
        let key_sym =
            unsafe { (self.xlib.XStringToKeysym)(unicode_as_c_string.as_ptr() as *mut c_char) };

        let mut min = 0;
        let mut max = 0;
        let mut numcodes = 0;

        unsafe { (self.xlib.XDisplayKeycodes)(self.display, &mut min, &mut max) };

        let upper = max as i32 - min as i32 + 1;
        let key_sym_mapped = unsafe {
            (self.xlib.XGetKeyboardMapping)(self.display, min as u8, upper, &mut numcodes)
        };
        let idx = ((max as i32 - min as i32 - 1) * numcodes as i32) as isize;

        unsafe {
            let map = key_sym_mapped.offset(idx);
            *map = key_sym;
        }

        unsafe {
            (self.xlib.XChangeKeyboardMapping)(self.display,
                                               min as i32,
                                               numcodes as i32,
                                               key_sym_mapped,
                                               (max as i32 - min as i32));
            (self.xlib.XFree)(key_sym_mapped as *mut c_void);
            (self.xlib.XFlush)(self.display);
            let keycode = (self.xlib.XKeysymToKeycode)(self.display, key_sym);

            keycode as i32
        }

    }

    fn keycode_click(&self, keycode: i32) {
        use std::{thread, time};
        thread::sleep(time::Duration::from_millis(20));
        self.keycode_down(keycode);
        self.keycode_up(keycode);
        thread::sleep(time::Duration::from_millis(20));
    }

    fn keycode_down(&self, keycode: i32) {
        unsafe {
            (self.xtest.XTestFakeKeyEvent)(self.display, keycode as u32, 1, 1);
            (self.xlib.XFlush)(self.display);
        }
    }

    fn keycode_up(&self, keycode: i32) {
        unsafe {
            (self.xtest.XTestFakeKeyEvent)(self.display, keycode as u32, 0, 1);
            (self.xlib.XFlush)(self.display);
        }
    }
}
<|endoftext|>


<commit_before>// https://leetcode.com/problems/minimum-amount-of-time-to-collect-garbage/
pub fn garbage_collection(garbage: Vec<String>, travel: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!(
        "{}",
        garbage_collection(
            vec![
                "G".to_string(),
                "P".to_string(),
                "GP".to_string(),
                "GG".to_string()
            ],
            vec![2, 4, 3]
        )
    ); // 21
    println!(
        "{}",
        garbage_collection(
            vec!["MMM".to_string(), "PGM".to_string(), "GP".to_string()],
            vec![3, 10]
        )
    ); // 37
}
<commit_msg>Solve problem 2391<commit_after>use std::collections::HashMap;

// https://leetcode.com/problems/minimum-amount-of-time-to-collect-garbage/
pub fn garbage_collection(garbage: Vec<String>, travel: Vec<i32>) -> i32 {
    fn garbage_map(garbage: String) -> HashMap<char, i32> {
        let mut map: HashMap<char, i32> = HashMap::new();
        let chars: Vec<char> = garbage.chars().collect();
        for c in chars.into_iter() {
            *map.entry(c).or_insert(0) += 1;
        }
        map
    }

    let mut garbage_vec: Vec<HashMap<char, i32>> = vec![];
    let mut metal_time = 0;
    let mut paper_time = 0;
    let mut glass_time = 0;
    let mut metal_last_index = 0;
    let mut paper_last_index = 0;
    let mut glass_last_index = 0;
    for (i, g) in garbage.into_iter().enumerate() {
        let map = garbage_map(g);
        if let Some(count) = map.get(&'M') {
            metal_time += count;
            metal_last_index = i;
        }
        if let Some(count) = map.get(&'P') {
            paper_time += count;
            paper_last_index = i;
        }
        if let Some(count) = map.get(&'G') {
            glass_time += count;
            glass_last_index = i;
        }
        garbage_vec.push(map);
    }
    for i in 0..garbage_vec.len() {
        if i == 0 {
            continue;
        }
        if metal_last_index >= i {
            metal_time += travel[i - 1];
        }
        if paper_last_index >= i {
            paper_time += travel[i - 1];
        }
        if glass_last_index >= i {
            glass_time += travel[i - 1];
        }
    }
    metal_time + paper_time + glass_time
}

fn main() {
    println!(
        "{}",
        garbage_collection(
            vec![
                "G".to_string(),
                "P".to_string(),
                "GP".to_string(),
                "GG".to_string()
            ],
            vec![2, 4, 3]
        )
    ); // 21
    println!(
        "{}",
        garbage_collection(
            vec!["MMM".to_string(), "PGM".to_string(), "GP".to_string()],
            vec![3, 10]
        )
    ); // 37
}
<|endoftext|>


<commit_before>use dungeon::{Dungeon};
use celloption::{Occupant};
use genotype::{Genotype};
use phenotype::{Seed};
use config::{Config};
use util::{odds};

use std::iter::{range_step};
use std::collections::{HashMap, HashSet};
use rand::{Rng};

#[derive(Clone, Debug)]
pub struct DesirableProperties {
    seed: Seed,
    room_number: u32,
    room_size: u32,
    doors: u32,
    monsters: u32,
    path_length: u32,
    branching: f64,
    occupants: Vec<(Occupant, (u32, u32))>,
    rooms: Vec<Room>,
    mazes: Vec<Maze>,
    connectors: Vec<Connector>,
}

#[derive(Clone, Debug)]
struct Room {
    x: u32,
    y: u32,
    w: u32,
    h: u32,
    region: u32,
}

#[derive(Clone, Debug)]
struct Maze {
    path: HashSet<(u32, u32)>,
    region: u32,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum Direction {
    North,
    East,
    South,
    West
}

static CARDINALS: [(Direction, (i32, i32)); 4] = [(Direction::North, (0, 1)),
                                                  (Direction::East, (1, 0)),
                                                  (Direction::South, (0, -1)),
                                                  (Direction::West, (-1, 0))];

// helper function: given a coordinate and a relative direction, get
// the coordinate n spaces away in that direction.
fn scale(coord: (u32, u32), dir: (i32, i32), n: i32) -> (u32, u32) {
    let (x, y) = coord;
    let (dx, dy) = dir;
    (((x as i32 + dx * n) as u32), ((y as i32 + dy * n) as u32))
}

#[derive(Clone, Debug)]
struct Connector {
    location: (u32, u32),
    regions: HashSet<u32>,
}

impl Connector {
    pub fn new(location: (u32, u32), regions: &HashSet<u32>) -> Connector {
        Connector {
            location: location,
            regions: regions.clone(),
        }
    }

    pub fn find_all(mazes: &Vec<Maze>, rooms: &Vec<Room>) -> Vec<Connector> {
        // build up a hashmap of coords to region id
        let mut lookup: HashMap<(u32, u32), u32> = HashMap::new();
        for maze in mazes {
            for coord in maze.clone().path {
                lookup.insert(coord, maze.region);
            }
        }
        for room in rooms {
            for coord in room.border() {
                lookup.insert(coord, room.region);
            }
        }
        // find connectors (blank spaces between two regions)
        let mut connectors: Vec<Connector> = Vec::new();
        let mut examined: HashSet<(u32, u32)> = HashSet::new();
        for (&coord, &region) in lookup.iter() {
            examined.insert(coord);
            let possibles: Vec<(u32, u32)> = CARDINALS.iter().map(|&(_, rel_dir)| scale(coord, rel_dir, 1)).collect();
            for new_coord in possibles {
                if !examined.contains(&new_coord) || !lookup.contains_key(&new_coord) {
                    let regions: HashSet<u32> = CARDINALS.iter().map(|&(_, rel_dir)| {
                        let coord = scale(new_coord, rel_dir, 1);
                        if lookup.contains_key(&coord) {
                            lookup[coord]
                        } else {
                            region // by design, at least two directions must fail
                        }
                    }).collect();
                    if regions.len() >= 2 {
                        let connector = Connector::new(new_coord, &regions);
                        connectors.push(connector);
                    }
                    examined.insert(new_coord);
                }
            }
        }
        connectors
    }

    pub fn merge<T: Rng>(rng: &mut T,
                         connectors: &Vec<Connector>,
                         mazes: &Vec<Maze>,
                         rooms: &Vec<Room>) -> Vec<Connector> {
        let mut current = connectors.clone();
        let mut open: HashSet<u32> = HashSet::new();
        for connector in connectors {
            open = open.union(&connector.regions.clone()).cloned().collect();
        }
        let mut merged_connectors: Vec<Connector> = Vec::new();
        while current.len() > 1 {
            // pick a random connector
            let index = rng.gen_range(0, current.clone().len());
            let connector = current.remove(index);
            let regions = connector.regions.clone();
            merged_connectors.push(connector);
            // actually merge.
            for other_connector in current.iter_mut() {
                // remove only if this connector already has all regions
                let result: HashSet<u32> = other_connector.regions.union(&regions).cloned().collect();
                if result.len() == regions.len() {
                    other_connector.regions.clear();
                }

                // for other_region in regions.clone() {
                //     other_connector.regions.remove(&other_region);
                // }
                //other_connector.regions.remove(&first);
            }
            // remove unnecessary connectors
            current = current.iter().filter(|&c| c.regions.len() > 0).cloned().collect();
            //open.remove(&first);
        }
        merged_connectors.clone()
    }
}

pub type CollisionFn<'a> = Box<Fn(&(u32, u32)) -> bool + 'a>;

impl Maze {
    pub fn new<T: Rng>(rng: &mut T,
                       previous: &HashSet<(u32, u32)>,
                       collides: CollisionFn,
                       branching: f64,
                       region: u32,
                       x: u32,
                       y: u32) -> Maze {
        let path = Maze::grow(rng, previous, collides, branching, x, y);
        Maze {
            region: region,
            path: path
        }
    }

    fn grow<T: Rng>(rng: &mut T,
                    previous: &HashSet<(u32, u32)>,
                    collides: CollisionFn,
                    branching: f64,
                    orig_x: u32,
                    orig_y: u32) -> HashSet<(u32, u32)> {
        let branching_factor = (branching * 100.0) as u64;
        let mut path: Vec<(u32, u32)> = Vec::new();
        let mut all_paths: HashSet<(u32, u32)> = previous.clone();
        let all = vec!(Direction::North, Direction::East, Direction::South, Direction::West);
        let mut direction = rng.choose(all.as_slice()).unwrap().clone();
        path.push((orig_x, orig_y));
        all_paths.insert((orig_x, orig_y));
        // "growing-tree" algorithm
        while !path.is_empty() {
            let new_coord = path[path.len()-1];
            let uncarved: HashMap<Direction, (i32, i32)> = CARDINALS.iter().filter(|&&(_, new_dir)| {
                let coord1 = scale(new_coord, new_dir, 1);
                let coord2 = scale(new_coord, new_dir, 2);
                let coord3 = scale(new_coord, new_dir, 3);
                !all_paths.contains(&coord1) &&
                    !all_paths.contains(&coord2) &&
                    !all_paths.contains(&coord3) &&
                    !collides(&coord2) &&
                    !collides(&coord3)
            }).cloned().collect();
            if !uncarved.is_empty() {
                let same_direction = odds(rng, branching_factor, 100);
                let rel_dir = if same_direction && uncarved.contains_key(&direction) {
                    uncarved[direction]
                } else {
                    let (dir, coords) = uncarved.into_iter().next().unwrap();
                    direction = dir;
                    coords
                };
                let coord1 = scale(new_coord, rel_dir, 1);
                let coord2 = scale(new_coord, rel_dir, 2);
                all_paths.insert(coord1);
                all_paths.insert(coord2);
                path.push(coord2);
            } else {
                path.pop();
            }
        }
        all_paths.difference(previous).cloned().collect()
    }
}

impl Room {
    pub fn random<T: Rng>(rng: &mut T, width: u32, height: u32, room_size: u32, region: u32) -> Room {
        let w: u32 = rng.gen_range(3, room_size);
        let h: u32 = rng.gen_range(3, room_size);
        assert!(width >= w);
        assert!(height >= h);
        let x: u32 = rng.gen_range(1, width - w);
        let y: u32 = rng.gen_range(1, height - h);
        let make_odd = |n| if n % 2 == 0 { n - 1 } else { n };
        Room {
            x: make_odd(x),
            y: make_odd(y),
            w: make_odd(w),
            h: make_odd(h),
            region: region,
        }
    }

    pub fn intersects(&self, rooms: &Vec<Room>) -> bool {
        for r in rooms {
            let rw = r.x + r.w;
            let rh = r.y + r.h;
            let roomw = self.x + self.w;
            let roomh = self.y + self.h;
            if roomw > r.x && roomh > r.y && self.x < rw && self.y < rh {
                return true
            }
        }
        false
    }

    pub fn contains(&self, x: u32, y: u32) -> bool {
        let roomw = self.x + self.w;
        let roomh = self.y + self.h;
        x >= self.x && x < roomw && y >= self.y && y < roomh
    }

    pub fn border(&self) -> Vec<(u32, u32)> {
        let mut surrounding = vec![];
        for i in range(0, self.w) {
            surrounding.push(((self.x + i), self.y));
            surrounding.push(((self.x + i), self.y + self.h - 1));
        }
        for i in range(0, self.h) {
            surrounding.push((self.x, self.y + i));
            surrounding.push((self.x + self.w - 1, self.y + i));
        }
        surrounding
    }
}

impl DesirableProperties {
    pub fn new(config: &Config, seed: &Seed) -> DesirableProperties {
        // read in the configurations
        let desirables = config.get_table(None, "desirable_patterns");
        let room_number = config.get_integer(desirables, "room_number") as u32;
        let room_size = config.get_integer(desirables, "room_size") as u32;
        let doors = config.get_integer(desirables, "doors") as u32;
        let monsters = config.get_integer(desirables, "monsters") as u32;
        let path_length = config.get_integer(desirables, "path_length") as u32;
        let branching = config.get_float(desirables, "branching");
        DesirableProperties {
            seed: seed.clone(),
            room_size: room_size,
            room_number: room_number,
            doors: doors,
            monsters: monsters,
            path_length: path_length,
            branching: branching,
            occupants: vec![],
            rooms: vec![],
            mazes: vec![],
            connectors: vec![],
        }
    }

}

impl Genotype for DesirableProperties {
    fn initialize<T: Rng>(&self, rng: &mut T) -> DesirableProperties {
        let w = self.seed.width;
        let h = self.seed.height;
        let occupants = self.seed.random_occupants(rng).iter().take(self.monsters as usize).cloned().collect();
        let mut region = 0;
        // randomly generate rooms
        let mut rooms = vec![];
        for _ in range(0, self.room_number) {
            for _ in range(0, 10) {
                let room = Room::random(rng, w, h, self.room_size, region);
                if !room.intersects(&rooms) {
                    rooms.push(room);
                    region += 1;
                    break;
                }
            }
        }
        // fill in mazes
        let mut mazes = vec![];
        let mut positions: HashSet<(u32, u32)> = HashSet::new();
        let is_occupied = |x, y| rooms.clone().iter().fold(false, |accum, ref m| accum || m.contains(x, y));
        for x in range_step(1, w, 2) {
            for y in range_step(1, h, 2) {
                if !is_occupied(x, y) && !positions.contains(&(x, y)) {
                    let collides: CollisionFn = box |&(cx, cy)| cx >= w || cy >= h || is_occupied(cx, cy);
                    let maze = Maze::new(rng, &positions, collides, self.branching, region, x, y);
                    positions = positions.union(&maze.path).cloned().collect();
                    mazes.push(maze);
                    region += 1;
                }
            }
        }
        // find connectors
        let all_connectors = Connector::find_all(&mazes, &rooms);
        let connectors = Connector::merge(rng, &all_connectors, &mazes, &rooms);
        // remove dead ends
        DesirableProperties {
            seed: self.seed.clone(),
            room_number: self.room_number,
            room_size: self.room_size,
            doors: self.doors,
            monsters: self.monsters,
            path_length: self.path_length,
            branching: self.branching,
            occupants: occupants,
            rooms: rooms.clone(),
            mazes: mazes,
            connectors: connectors,
        }
    }

    fn mutate<T: Rng>(&mut self, _: &mut T, _: f64) {
        // mutate a certain % of the rooms and start again
    }

    fn generate(&self) -> Dungeon {
        let w = self.seed.width;
        let h = self.seed.height;
        let mut dungeon = Dungeon::new(w, h, None);
        let wall = self.seed.tiles.get("wall").unwrap();
        let door = self.seed.tiles.get("door").unwrap();
        let floor = self.seed.tiles.get("floor").unwrap();
        for room in self.rooms.iter() {
            for i in range(room.x, room.x + room.w) {
                for j in range(room.y, room.y + room.h) {
                    dungeon.cells[i as usize][j as usize].tile = Some(wall.clone())
                }
            }
            // will overdraw, but that's OK.
            for (i, j) in room.border() {
                dungeon.cells[i as usize][j as usize].tile = Some(floor.clone())
            }
        }
        for maze in self.mazes.iter() {
            for path in maze.path.iter() {
                let (x, y): (u32, u32) = *path;
                dungeon.cells[x as usize][y as usize].tile = Some(floor.clone());
            }
        }
        for connector in self.connectors.iter() {
            let (x, y) = connector.location;
            dungeon.cells[x as usize][y as usize].tile = Some(door.clone());
        }
        dungeon.clone()
    }
}
<commit_msg>Fully linked connectors.<commit_after>use dungeon::{Dungeon};
use celloption::{Occupant};
use genotype::{Genotype};
use phenotype::{Seed};
use config::{Config};
use util::{odds};

use std::iter::{range_step};
use std::collections::{HashMap, HashSet};
use rand::{Rng};

#[derive(Clone, Debug)]
pub struct DesirableProperties {
    seed: Seed,
    room_number: u32,
    room_size: u32,
    doors: u32,
    monsters: u32,
    path_length: u32,
    branching: f64,
    occupants: Vec<(Occupant, (u32, u32))>,
    rooms: Vec<Room>,
    mazes: Vec<Maze>,
    connectors: Vec<Connector>,
}

#[derive(Clone, Debug)]
struct Room {
    x: u32,
    y: u32,
    w: u32,
    h: u32,
    region: u32,
}

#[derive(Clone, Debug)]
struct Maze {
    path: HashSet<(u32, u32)>,
    region: u32,
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
enum Direction {
    North,
    East,
    South,
    West
}

static CARDINALS: [(Direction, (i32, i32)); 4] = [(Direction::North, (0, 1)),
                                                  (Direction::East, (1, 0)),
                                                  (Direction::South, (0, -1)),
                                                  (Direction::West, (-1, 0))];

// helper function: given a coordinate and a relative direction, get
// the coordinate n spaces away in that direction.
fn scale(coord: (u32, u32), dir: (i32, i32), n: i32) -> (u32, u32) {
    let (x, y) = coord;
    let (dx, dy) = dir;
    (((x as i32 + dx * n) as u32), ((y as i32 + dy * n) as u32))
}

#[derive(Clone, Debug)]
struct Connector {
    location: (u32, u32),
    regions: HashSet<u32>,
}

impl Connector {
    pub fn new(location: (u32, u32), regions: &HashSet<u32>) -> Connector {
        Connector {
            location: location,
            regions: regions.clone(),
        }
    }

    pub fn find_all(mazes: &Vec<Maze>, rooms: &Vec<Room>) -> Vec<Connector> {
        // build up a hashmap of coords to region id
        let mut lookup: HashMap<(u32, u32), u32> = HashMap::new();
        for maze in mazes {
            for coord in maze.clone().path {
                lookup.insert(coord, maze.region);
            }
        }
        for room in rooms {
            for coord in room.border() {
                lookup.insert(coord, room.region);
            }
        }
        // find connectors (blank spaces between two regions)
        let mut connectors: Vec<Connector> = Vec::new();
        let mut examined: HashSet<(u32, u32)> = HashSet::new();
        for (&coord, &region) in lookup.iter() {
            examined.insert(coord);
            let possibles: Vec<(u32, u32)> = CARDINALS.iter().map(|&(_, rel_dir)| scale(coord, rel_dir, 1)).collect();
            for new_coord in possibles {
                if !examined.contains(&new_coord) || !lookup.contains_key(&new_coord) {
                    let regions: HashSet<u32> = CARDINALS.iter().map(|&(_, rel_dir)| {
                        let coord = scale(new_coord, rel_dir, 1);
                        if lookup.contains_key(&coord) {
                            lookup[coord]
                        } else {
                            region // by design, at least two directions must fail
                        }
                    }).collect();
                    if regions.len() >= 2 {
                        let connector = Connector::new(new_coord, &regions);
                        connectors.push(connector);
                    }
                    examined.insert(new_coord);
                }
            }
        }
        connectors
    }

    pub fn merge<T: Rng>(rng: &mut T, connectors: &Vec<Connector>) -> Vec<Connector> {
        // accumulate all of the regions
        let mut open: HashSet<u32> = HashSet::new();
        for connector in connectors {
            open = open.union(&connector.regions.clone()).cloned().collect();
        }
        // lookup for merged regions
        let region_number = open.len();
        let mut merged_lookup: Vec<u32> = Vec::new();
        for i in range(0, region_number as u32) {
            merged_lookup.push(i);
        }
        let mut current = connectors.clone();
        let mut merged_connectors: Vec<Connector> = Vec::new();
        while open.len() > 1 {
            // pick a random connector and region
            let connectors = current.clone();
            let connector = rng.choose(connectors.as_slice()).unwrap();
            let mut regions: Vec<u32> = connector.regions.iter().map(|&r| merged_lookup[r as usize]).collect();
            let first = regions.pop().unwrap();
            let rest: HashSet<u32> = regions.clone().iter().cloned().collect();
            merged_connectors.push(connector.clone());
            for i in range(0, region_number) {
                if rest.contains(&merged_lookup[i]) {
                    merged_lookup[i] = first;
                }
            }
            // remove unnecessary connectors
            current = current.iter().filter(|&c| {
                let regions: HashSet<u32> = c.regions.iter().map(|&r| merged_lookup[r as usize]).collect();
                regions.len() > 1
            }).cloned().collect();
            open = open.difference(&rest).cloned().collect();
        }
        merged_connectors.clone()
    }
}

pub type CollisionFn<'a> = Box<Fn(&(u32, u32)) -> bool + 'a>;

impl Maze {
    pub fn new<T: Rng>(rng: &mut T,
                       previous: &HashSet<(u32, u32)>,
                       collides: CollisionFn,
                       branching: f64,
                       region: u32,
                       x: u32,
                       y: u32) -> Maze {
        let path = Maze::grow(rng, previous, collides, branching, x, y);
        Maze {
            region: region,
            path: path
        }
    }

    fn grow<T: Rng>(rng: &mut T,
                    previous: &HashSet<(u32, u32)>,
                    collides: CollisionFn,
                    branching: f64,
                    orig_x: u32,
                    orig_y: u32) -> HashSet<(u32, u32)> {
        let branching_factor = (branching * 100.0) as u64;
        let mut path: Vec<(u32, u32)> = Vec::new();
        let mut all_paths: HashSet<(u32, u32)> = previous.clone();
        let all = vec!(Direction::North, Direction::East, Direction::South, Direction::West);
        let mut direction = rng.choose(all.as_slice()).unwrap().clone();
        path.push((orig_x, orig_y));
        all_paths.insert((orig_x, orig_y));
        // "growing-tree" algorithm
        while !path.is_empty() {
            let new_coord = path[path.len()-1];
            let uncarved: HashMap<Direction, (i32, i32)> = CARDINALS.iter().filter(|&&(_, new_dir)| {
                let coord1 = scale(new_coord, new_dir, 1);
                let coord2 = scale(new_coord, new_dir, 2);
                let coord3 = scale(new_coord, new_dir, 3);
                !all_paths.contains(&coord1) &&
                    !all_paths.contains(&coord2) &&
                    !all_paths.contains(&coord3) &&
                    !collides(&coord2) &&
                    !collides(&coord3)
            }).cloned().collect();
            if !uncarved.is_empty() {
                let same_direction = odds(rng, branching_factor, 100);
                let rel_dir = if same_direction && uncarved.contains_key(&direction) {
                    uncarved[direction]
                } else {
                    let (dir, coords) = uncarved.into_iter().next().unwrap();
                    direction = dir;
                    coords
                };
                let coord1 = scale(new_coord, rel_dir, 1);
                let coord2 = scale(new_coord, rel_dir, 2);
                all_paths.insert(coord1);
                all_paths.insert(coord2);
                path.push(coord2);
            } else {
                path.pop();
            }
        }
        all_paths.difference(previous).cloned().collect()
    }
}

impl Room {
    pub fn random<T: Rng>(rng: &mut T, width: u32, height: u32, room_size: u32, region: u32) -> Room {
        let w: u32 = rng.gen_range(3, room_size);
        let h: u32 = rng.gen_range(3, room_size);
        assert!(width >= w);
        assert!(height >= h);
        let x: u32 = rng.gen_range(1, width - w);
        let y: u32 = rng.gen_range(1, height - h);
        let make_odd = |n| if n % 2 == 0 { n - 1 } else { n };
        Room {
            x: make_odd(x),
            y: make_odd(y),
            w: make_odd(w),
            h: make_odd(h),
            region: region,
        }
    }

    pub fn intersects(&self, rooms: &Vec<Room>) -> bool {
        for r in rooms {
            let rw = r.x + r.w;
            let rh = r.y + r.h;
            let roomw = self.x + self.w;
            let roomh = self.y + self.h;
            if roomw > r.x && roomh > r.y && self.x < rw && self.y < rh {
                return true
            }
        }
        false
    }

    pub fn contains(&self, x: u32, y: u32) -> bool {
        let roomw = self.x + self.w;
        let roomh = self.y + self.h;
        x >= self.x && x < roomw && y >= self.y && y < roomh
    }

    pub fn border(&self) -> Vec<(u32, u32)> {
        let mut surrounding = vec![];
        for i in range(0, self.w) {
            surrounding.push(((self.x + i), self.y));
            surrounding.push(((self.x + i), self.y + self.h - 1));
        }
        for i in range(0, self.h) {
            surrounding.push((self.x, self.y + i));
            surrounding.push((self.x + self.w - 1, self.y + i));
        }
        surrounding
    }
}

impl DesirableProperties {
    pub fn new(config: &Config, seed: &Seed) -> DesirableProperties {
        // read in the configurations
        let desirables = config.get_table(None, "desirable_patterns");
        let room_number = config.get_integer(desirables, "room_number") as u32;
        let room_size = config.get_integer(desirables, "room_size") as u32;
        let doors = config.get_integer(desirables, "doors") as u32;
        let monsters = config.get_integer(desirables, "monsters") as u32;
        let path_length = config.get_integer(desirables, "path_length") as u32;
        let branching = config.get_float(desirables, "branching");
        DesirableProperties {
            seed: seed.clone(),
            room_size: room_size,
            room_number: room_number,
            doors: doors,
            monsters: monsters,
            path_length: path_length,
            branching: branching,
            occupants: vec![],
            rooms: vec![],
            mazes: vec![],
            connectors: vec![],
        }
    }

}

impl Genotype for DesirableProperties {
    fn initialize<T: Rng>(&self, rng: &mut T) -> DesirableProperties {
        let w = self.seed.width;
        let h = self.seed.height;
        let occupants = self.seed.random_occupants(rng).iter().take(self.monsters as usize).cloned().collect();
        let mut region = 0;
        // randomly generate rooms
        let mut rooms = vec![];
        for _ in range(0, self.room_number) {
            for _ in range(0, 10) {
                let room = Room::random(rng, w, h, self.room_size, region);
                if !room.intersects(&rooms) {
                    rooms.push(room);
                    region += 1;
                    break;
                }
            }
        }
        // fill in mazes
        let mut mazes = vec![];
        let mut positions: HashSet<(u32, u32)> = HashSet::new();
        let is_occupied = |x, y| rooms.clone().iter().fold(false, |accum, ref m| accum || m.contains(x, y));
        for x in range_step(1, w, 2) {
            for y in range_step(1, h, 2) {
                if !is_occupied(x, y) && !positions.contains(&(x, y)) {
                    let collides: CollisionFn = box |&(cx, cy)| cx >= w || cy >= h || is_occupied(cx, cy);
                    let maze = Maze::new(rng, &positions, collides, self.branching, region, x, y);
                    positions = positions.union(&maze.path).cloned().collect();
                    mazes.push(maze);
                    region += 1;
                }
            }
        }
        // find connectors
        let all_connectors = Connector::find_all(&mazes, &rooms);
        let connectors = Connector::merge(rng, &all_connectors);
        // remove dead ends
        DesirableProperties {
            seed: self.seed.clone(),
            room_number: self.room_number,
            room_size: self.room_size,
            doors: self.doors,
            monsters: self.monsters,
            path_length: self.path_length,
            branching: self.branching,
            occupants: occupants,
            rooms: rooms.clone(),
            mazes: mazes,
            connectors: connectors,
        }
    }

    fn mutate<T: Rng>(&mut self, _: &mut T, _: f64) {
        // mutate a certain % of the rooms and start again
    }

    fn generate(&self) -> Dungeon {
        let w = self.seed.width;
        let h = self.seed.height;
        let mut dungeon = Dungeon::new(w, h, None);
        let wall = self.seed.tiles.get("wall").unwrap();
        let door = self.seed.tiles.get("door").unwrap();
        let floor = self.seed.tiles.get("floor").unwrap();
        for room in self.rooms.iter() {
            for i in range(room.x, room.x + room.w) {
                for j in range(room.y, room.y + room.h) {
                    dungeon.cells[i as usize][j as usize].tile = Some(wall.clone())
                }
            }
            // will overdraw, but that's OK.
            for (i, j) in room.border() {
                dungeon.cells[i as usize][j as usize].tile = Some(floor.clone())
            }
        }
        for maze in self.mazes.iter() {
            for path in maze.path.iter() {
                let (x, y): (u32, u32) = *path;
                dungeon.cells[x as usize][y as usize].tile = Some(floor.clone());
            }
        }
        for connector in self.connectors.iter() {
            let (x, y) = connector.location;
            dungeon.cells[x as usize][y as usize].tile = Some(door.clone());
        }
        dungeon.clone()
    }
}
<|endoftext|>


<commit_before>use std::{cmp, usize};
use slsr_core::puzzle::Side;
use slsr_core::geom::{CellId, Geom};

use {State, SolverResult};
use model::connect_map::ConnectMap;
use model::side_map::SideMap;

fn create_conn_graph(conn_map: &mut ConnectMap,
                     exclude_side: Side)
                     -> (Vec<CellId>, Vec<State<Side>>, Vec<Vec<usize>>) {
    let mut pts = vec![];
    let mut sides = vec![];
    for i in 0..conn_map.cell_len() {
        let p = CellId::new(i);
        let a = conn_map.get(p);
        if a.coord() != p || a.side() == State::Fixed(exclude_side) {
            continue;
        }
        pts.push(p);
        sides.push(a.side());
    }

    let mut verts = vec![None; conn_map.cell_len()];
    for (i, &p) in pts.iter().enumerate() {
        verts[p.id()] = Some(i);
    }

    let graph = pts.iter()
                   .map(|&p| {
                       conn_map.get(p)
                               .unknown_edge()
                               .iter()
                               .filter_map(|p2| verts[p2.id()])
                               .collect::<Vec<_>>()
                   })
                   .collect();

    (pts, sides, graph)
}

fn get_articulation(graph: &[Vec<usize>],
                    v: usize,
                    arts: &mut Vec<usize>,
                    gvisited: &mut [bool])
                    -> Vec<bool> {
    let mut visited = vec![false; graph.len()];
    let mut ord = vec![0; graph.len()];
    let mut low = vec![0; graph.len()];
    let mut ord_cnt = 0;
    unsafe {
        dfs(graph,
            v,
            usize::MAX,
            arts,
            gvisited,
            &mut visited,
            &mut ord,
            &mut low,
            &mut ord_cnt);
    }

    return visited;

    unsafe fn dfs(graph: &[Vec<usize>],
                  v: usize,
                  prev: usize,
                  arts: &mut Vec<usize>,
                  gvisited: &mut [bool],
                  visited: &mut [bool],
                  ord: &mut [usize],
                  low: &mut [usize],
                  ord_cnt: &mut usize) {
        debug_assert!(!visited[v]);

        *visited.get_unchecked_mut(v) = true;
        *gvisited.get_unchecked_mut(v) = true;
        *ord.get_unchecked_mut(v) = *ord_cnt;
        *low.get_unchecked_mut(v) = *ord_cnt;
        *ord_cnt += 1;

        let mut is_articulation = false;
        let mut num_child = 0;

        for &u in graph.get_unchecked(v) {
            if u == v {
                continue;
            }

            if !*visited.get_unchecked(u) {
                dfs(graph, u, v, arts, gvisited, visited, ord, low, ord_cnt);

                num_child += 1;
                *low.get_unchecked_mut(v) = cmp::min(*low.get_unchecked(v), *low.get_unchecked(u));
                if *ord.get_unchecked(v) != 1 && *ord.get_unchecked(v) <= *low.get_unchecked(u) {
                    is_articulation = true;
                }
            } else if u != prev {
                *low.get_unchecked_mut(v) = cmp::min(*low.get_unchecked(v), *ord.get_unchecked(u));
            }
        }

        if prev == usize::MAX && num_child > 1 {
            is_articulation = true;
        }

        if is_articulation {
            arts.push(v);
        }
    }
}

fn find_disconn_area(conn_map: &mut ConnectMap,
                     pts: &[CellId],
                     visited: &[bool])
                     -> SolverResult<Vec<usize>> {
    let mut disconn = vec![];
    let mut disconn_sum = 0;
    for (u, &vis) in visited.iter().enumerate() {
        if !vis {
            disconn.push(u);
            disconn_sum += conn_map.get(pts[u]).sum_of_hint();
        }
    }
    if disconn.is_empty() {
        // All area is connected
        return Ok(vec![]);
    }
    if disconn_sum == 0 {
        // Disconnected components does not contain any edges. It is a hole in
        // the exclude_side area.
        return Ok(disconn);
    }

    let mut conn = vec![];
    let mut conn_sum = 0;
    for (u, &vis) in visited.iter().enumerate() {
        if vis {
            conn.push(u);
            conn_sum += conn_map.get(pts[u]).sum_of_hint();
        }
    }
    if conn_sum == 0 {
        // Conencted area does not contain any edges. It is a hole in the
        // exclude_side area.
        return Ok(conn);
    }

    // Graph is splitted into more than two parts, but both parts contain edges.
    // This may be valid in some situation, so, return empty.
    Ok(vec![])
}

fn splits(graph: &[Vec<usize>], v: usize, sides: &[State<Side>], set_side: Side) -> bool {
    if graph.is_empty() {
        return false;
    }

    let mut contain_cnt = 0;
    let mut visited = vec![false; graph.len()];

    unsafe {
        *visited.get_unchecked_mut(v) = true;

        for &u in graph.get_unchecked(v) {
            if *visited.get_unchecked(u) {
                continue;
            }

            let mut contains = false;
            dfs(graph, u, &mut contains, &mut visited, sides, set_side);

            if contains {
                contain_cnt += 1;
                if contain_cnt > 1 {
                    return true;
                }
            }
        }
    }

    return false;

    unsafe fn dfs(graph: &[Vec<usize>],
                  v: usize,
                  contains: &mut bool,
                  visited: &mut [bool],
                  sides: &[State<Side>],
                  set_side: Side) {
        if *sides.get_unchecked(v) == State::Fixed(set_side) {
            *contains = true;
        }
        *visited.get_unchecked_mut(v) = true;

        for &u in graph.get_unchecked(v) {
            if *visited.get_unchecked_mut(u) {
                continue;
            }
            dfs(graph, u, contains, visited, sides, set_side);
        }
    }
}

pub fn run(side_map: &mut SideMap, conn_map: &mut ConnectMap) -> SolverResult<()> {
    try!(conn_map.sync(side_map));

    let sides = &[(Side::In, Side::Out), (Side::Out, Side::In)];

    for &(set_side, exclude_side) in sides {
        let (pts, sides, graph) = create_conn_graph(conn_map, exclude_side);

        let mut arts = vec![];
        let mut gvisited = vec![false; graph.len()];
        for v in 0..graph.len() {
            if gvisited[v] {
                continue;
            }

            let visited = get_articulation(&graph, v, &mut arts, &mut gvisited);

            if set_side == Side::Out || conn_map.sum_of_hint() != 0 {
                // If there is no edge in puzzle (sum_of_hint == 0) and set_side ==
                // Side::In, any disconnected area can be loop.
                let disconn = try!(find_disconn_area(conn_map, &pts, &visited));
                for v in disconn {
                    side_map.set_side(pts[v], exclude_side);
                }
            }
        }

        for v in arts {
            if sides[v] == State::Fixed(set_side) {
                continue;
            }

            if splits(&graph, v, &sides, set_side) {
                side_map.set_side(pts[v], set_side);
            }
        }
    }

    Ok(())
}
<commit_msg>solver: fix connect analysis bug<commit_after>use std::{cmp, usize};
use slsr_core::puzzle::Side;
use slsr_core::geom::{CellId, Geom};

use {State, SolverResult};
use model::connect_map::ConnectMap;
use model::side_map::SideMap;

fn create_conn_graph(conn_map: &mut ConnectMap,
                     exclude_side: Side)
                     -> (Vec<CellId>, Vec<State<Side>>, Vec<Vec<usize>>) {
    let mut pts = vec![];
    let mut sides = vec![];
    for i in 0..conn_map.cell_len() {
        let p = CellId::new(i);
        let a = conn_map.get(p);
        if a.coord() != p || a.side() == State::Fixed(exclude_side) {
            continue;
        }
        pts.push(p);
        sides.push(a.side());
    }

    let mut verts = vec![None; conn_map.cell_len()];
    for (i, &p) in pts.iter().enumerate() {
        verts[p.id()] = Some(i);
    }

    let graph = pts.iter()
                   .map(|&p| {
                       conn_map.get(p)
                               .unknown_edge()
                               .iter()
                               .filter_map(|p2| verts[p2.id()])
                               .collect::<Vec<_>>()
                   })
                   .collect();

    (pts, sides, graph)
}

fn get_articulation(graph: &[Vec<usize>],
                    v: usize,
                    arts: &mut Vec<usize>,
                    gvisited: &mut [bool])
                    -> Vec<bool> {
    let mut visited = vec![false; graph.len()];
    let mut ord = vec![0; graph.len()];
    let mut low = vec![0; graph.len()];
    let mut ord_cnt = 0;
    unsafe {
        dfs(graph,
            v,
            usize::MAX,
            arts,
            gvisited,
            &mut visited,
            &mut ord,
            &mut low,
            &mut ord_cnt);
    }

    return visited;

    unsafe fn dfs(graph: &[Vec<usize>],
                  v: usize,
                  prev: usize,
                  arts: &mut Vec<usize>,
                  gvisited: &mut [bool],
                  visited: &mut [bool],
                  ord: &mut [usize],
                  low: &mut [usize],
                  ord_cnt: &mut usize) {
        debug_assert!(!visited[v]);

        *visited.get_unchecked_mut(v) = true;
        *gvisited.get_unchecked_mut(v) = true;

        let ord_v = *ord_cnt;
        *ord.get_unchecked_mut(v) = ord_v;
        *low.get_unchecked_mut(v) = ord_v;
        *ord_cnt += 1;

        let mut is_articulation = false;
        let mut num_child = 0;

        for &u in graph.get_unchecked(v) {
            if u == v {
                continue;
            }

            if !*visited.get_unchecked(u) {
                dfs(graph, u, v, arts, gvisited, visited, ord, low, ord_cnt);

                let low_u = *low.get_unchecked(u);
                num_child += 1;
                *low.get_unchecked_mut(v) = cmp::min(*low.get_unchecked(v), low_u);
                if ord_v <= low_u {
                    is_articulation = true;
                }
            } else if u != prev {
                *low.get_unchecked_mut(v) = cmp::min(*low.get_unchecked(v), *ord.get_unchecked(u));
            } else {
            }
        }

        if ord_v == 0 {
            is_articulation = num_child > 1;
        }
        if is_articulation {
            arts.push(v);
        }
    }
}

fn find_disconn_area(conn_map: &mut ConnectMap,
                     pts: &[CellId],
                     visited: &[bool])
                     -> SolverResult<Vec<usize>> {
    let mut disconn = vec![];
    let mut disconn_sum = 0;
    for (u, &vis) in visited.iter().enumerate() {
        if !vis {
            disconn.push(u);
            disconn_sum += conn_map.get(pts[u]).sum_of_hint();
        }
    }
    if disconn.is_empty() {
        // All area is connected
        return Ok(vec![]);
    }
    if disconn_sum == 0 {
        // Disconnected components does not contain any edges. It is a hole in
        // the exclude_side area.
        return Ok(disconn);
    }

    let mut conn = vec![];
    let mut conn_sum = 0;
    for (u, &vis) in visited.iter().enumerate() {
        if vis {
            conn.push(u);
            conn_sum += conn_map.get(pts[u]).sum_of_hint();
        }
    }
    if conn_sum == 0 {
        // Conencted area does not contain any edges. It is a hole in the
        // exclude_side area.
        return Ok(conn);
    }

    // Graph is splitted into more than two parts, but both parts contain edges.
    // This may be valid in some situation, so, return empty.
    Ok(vec![])
}

fn splits(graph: &[Vec<usize>], v: usize, sides: &[State<Side>], set_side: Side) -> bool {
    if graph.is_empty() {
        return false;
    }

    let mut contain_cnt = 0;
    let mut visited = vec![false; graph.len()];

    unsafe {
        *visited.get_unchecked_mut(v) = true;

        for &u in graph.get_unchecked(v) {
            if *visited.get_unchecked(u) {
                continue;
            }

            let mut contains = false;
            dfs(graph, u, &mut contains, &mut visited, sides, set_side);

            if contains {
                contain_cnt += 1;
                if contain_cnt > 1 {
                    return true;
                }
            }
        }
    }

    return false;

    unsafe fn dfs(graph: &[Vec<usize>],
                  v: usize,
                  contains: &mut bool,
                  visited: &mut [bool],
                  sides: &[State<Side>],
                  set_side: Side) {
        if *sides.get_unchecked(v) == State::Fixed(set_side) {
            *contains = true;
        }
        *visited.get_unchecked_mut(v) = true;

        for &u in graph.get_unchecked(v) {
            if *visited.get_unchecked_mut(u) {
                continue;
            }
            dfs(graph, u, contains, visited, sides, set_side);
        }
    }
}

pub fn run(side_map: &mut SideMap, conn_map: &mut ConnectMap) -> SolverResult<()> {
    try!(conn_map.sync(side_map));

    let sides = &[(Side::In, Side::Out), (Side::Out, Side::In)];

    for &(set_side, exclude_side) in sides {
        let (pts, sides, graph) = create_conn_graph(conn_map, exclude_side);

        let mut arts = vec![];
        let mut gvisited = vec![false; graph.len()];
        for v in 0..graph.len() {
            if gvisited[v] {
                continue;
            }

            let visited = get_articulation(&graph, v, &mut arts, &mut gvisited);

            if set_side == Side::Out || conn_map.sum_of_hint() != 0 {
                // If there is no edge in puzzle (sum_of_hint == 0) and set_side ==
                // Side::In, any disconnected area can be loop.
                let disconn = try!(find_disconn_area(conn_map, &pts, &visited));
                for v in disconn {
                    side_map.set_side(pts[v], exclude_side);
                }
            }
        }

        for v in arts {
            if sides[v] == State::Fixed(set_side) {
                continue;
            }

            if splits(&graph, v, &sides, set_side) {
                side_map.set_side(pts[v], set_side);
            }
        }
    }

    Ok(())
}
<|endoftext|>