<commit_before>use std::mem;
use std::os::unix::io::RawFd;
use libc::{c_int, c_uint, c_void, c_ulong, pid_t};
use {Errno, Result};

pub type CloneFlags = c_uint;

pub static CLONE_VM:             CloneFlags = 0x00000100;
pub static CLONE_FS:             CloneFlags = 0x00000200;
pub static CLONE_FILES:          CloneFlags = 0x00000400;
pub static CLONE_SIGHAND:        CloneFlags = 0x00000800;
pub static CLONE_PTRACE:         CloneFlags = 0x00002000;
pub static CLONE_VFORK:          CloneFlags = 0x00004000;
pub static CLONE_PARENT:         CloneFlags = 0x00008000;
pub static CLONE_THREAD:         CloneFlags = 0x00010000;
pub static CLONE_NEWNS:          CloneFlags = 0x00020000;
pub static CLONE_SYSVSEM:        CloneFlags = 0x00040000;
pub static CLONE_SETTLS:         CloneFlags = 0x00080000;
pub static CLONE_PARENT_SETTID:  CloneFlags = 0x00100000;
pub static CLONE_CHILD_CLEARTID: CloneFlags = 0x00200000;
pub static CLONE_DETACHED:       CloneFlags = 0x00400000;
pub static CLONE_UNTRACED:       CloneFlags = 0x00800000;
pub static CLONE_CHILD_SETTID:   CloneFlags = 0x01000000;
pub static CLONE_NEWUTS:         CloneFlags = 0x04000000;
pub static CLONE_NEWIPC:         CloneFlags = 0x08000000;
pub static CLONE_NEWUSER:        CloneFlags = 0x10000000;
pub static CLONE_NEWPID:         CloneFlags = 0x20000000;
pub static CLONE_NEWNET:         CloneFlags = 0x40000000;
pub static CLONE_IO:             CloneFlags = 0x80000000;

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: super::CloneFlags,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: super::CloneFlags) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: super::CloneFlags) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags, &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype) };

    Errno::result(res).map(drop)
}
<commit_msg>Convert CLONE_ flags to bitflags! type.<commit_after>use std::mem;
use std::os::unix::io::RawFd;
use libc::{self, c_int, c_void, c_ulong, pid_t};
use {Errno, Result};

// For some functions taking with a parameter of type CloneFlags,
// only a subset of these flags have an effect.
bitflags!{
    flags CloneFlags: c_int {
        const CLONE_VM             = libc::CLONE_VM,
        const CLONE_FS             = libc::CLONE_FS,
        const CLONE_FILES          = libc::CLONE_FILES,
        const CLONE_SIGHAND        = libc::CLONE_SIGHAND,
        const CLONE_PTRACE         = libc::CLONE_PTRACE,
        const CLONE_VFORK          = libc::CLONE_VFORK,
        const CLONE_PARENT         = libc::CLONE_PARENT,
        const CLONE_THREAD         = libc::CLONE_THREAD,
        const CLONE_NEWNS          = libc::CLONE_NEWNS,
        const CLONE_SYSVSEM        = libc::CLONE_SYSVSEM,
        const CLONE_SETTLS         = libc::CLONE_SETTLS,
        const CLONE_PARENT_SETTID  = libc::CLONE_PARENT_SETTID,
        const CLONE_CHILD_CLEARTID = libc::CLONE_CHILD_CLEARTID,
        const CLONE_DETACHED       = libc::CLONE_DETACHED,
        const CLONE_UNTRACED       = libc::CLONE_UNTRACED,
        const CLONE_CHILD_SETTID   = libc::CLONE_CHILD_SETTID,
        // TODO: Once, we use a version containing
        // https://github.com/rust-lang-nursery/libc/pull/147
        // get rid of the casts.
        const CLONE_NEWUTS         = libc::CLONE_NEWUTS as c_int,
        const CLONE_NEWIPC         = libc::CLONE_NEWIPC as c_int,
        const CLONE_NEWUSER        = libc::CLONE_NEWUSER as c_int,
        const CLONE_NEWPID         = libc::CLONE_NEWPID as c_int,
        const CLONE_NEWNET         = libc::CLONE_NEWNET as c_int,
        const CLONE_IO             = libc::CLONE_IO as c_int,
    }
}

// Support a maximum CPU set of 1024 nodes
#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "x86", target_os = "linux"))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

#[cfg(all(target_arch = "aarch64", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    pub const CPU_SETSIZE:           usize = 1024;
    pub const CPU_MASK_BITS:         usize = 64;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u64 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u64 << bit)
    }
}

#[cfg(all(target_arch = "arm", any(target_os = "linux", target_os = "android")))]
mod cpuset_attribs {
    use super::CpuMask;
    // bionic only supports up to 32 independent CPUs, instead of 1024.
    pub const CPU_SETSIZE:          usize = 32;
    pub const CPU_MASK_BITS:        usize = 32;

    #[inline]
    pub fn set_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur | (1u32 << bit)
    }

    #[inline]
    pub fn clear_cpu_mask_flag(cur: CpuMask, bit: usize) -> CpuMask {
        cur & !(1u32 << bit)
    }
}

pub type CloneCb<'a> = Box<FnMut() -> isize + 'a>;

// A single CPU mask word
pub type CpuMask = c_ulong;

// Structure representing the CPU set to apply
#[repr(C)]
#[derive(Clone, Copy)]
pub struct CpuSet {
    cpu_mask: [CpuMask; cpuset_attribs::CPU_SETSIZE/cpuset_attribs::CPU_MASK_BITS]
}

impl CpuSet {
    pub fn new() -> CpuSet {
        CpuSet {
            cpu_mask: unsafe { mem::zeroed() }
        }
    }

    pub fn set(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::set_cpu_mask_flag(self.cpu_mask[word], bit);
    }

    pub fn unset(&mut self, field: usize) {
        let word = field / cpuset_attribs::CPU_MASK_BITS;
        let bit = field % cpuset_attribs::CPU_MASK_BITS;

        self.cpu_mask[word] = cpuset_attribs::clear_cpu_mask_flag(self.cpu_mask[word], bit);
    }
}

mod ffi {
    use libc::{c_void, c_int, pid_t, size_t};
    use super::CpuSet;

    pub type CloneCb = extern "C" fn (data: *const super::CloneCb) -> c_int;

    // We cannot give a proper #[repr(C)] to super::CloneCb
    #[allow(improper_ctypes)]
    extern {
        // create a child process
        // doc: http://man7.org/linux/man-pages/man2/clone.2.html
        pub fn clone(
            cb: *const CloneCb,
            child_stack: *mut c_void,
            flags: c_int,
            arg: *mut super::CloneCb,
            ...) -> c_int;

        // disassociate parts of the process execution context
        // doc: http://man7.org/linux/man-pages/man2/unshare.2.html
        pub fn unshare(flags: c_int) -> c_int;

        // reassociate thread with a namespace
        // doc: http://man7.org/linux/man-pages/man2/setns.2.html
        pub fn setns(fd: c_int, nstype: c_int) -> c_int;

        // Set the current CPU set that a task is allowed to run on
        pub fn sched_setaffinity(__pid: pid_t, __cpusetsize: size_t, __cpuset: *const CpuSet) -> c_int;
    }
}

pub fn sched_setaffinity(pid: isize, cpuset: &CpuSet) -> Result<()> {
    use libc::{pid_t, size_t};

    let res = unsafe {
        ffi::sched_setaffinity(pid as pid_t, mem::size_of::<CpuSet>() as size_t, mem::transmute(cpuset))
    };

    Errno::result(res).map(drop)
}

pub fn clone(mut cb: CloneCb, stack: &mut [u8], flags: CloneFlags) -> Result<pid_t> {
    extern "C" fn callback(data: *mut CloneCb) -> c_int {
        let cb: &mut CloneCb = unsafe { &mut *data };
        (*cb)() as c_int
    }

    let res = unsafe {
        let ptr = stack.as_mut_ptr().offset(stack.len() as isize);
        ffi::clone(mem::transmute(callback), ptr as *mut c_void, flags.bits(), &mut cb)
    };

    Errno::result(res)
}

pub fn unshare(flags: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::unshare(flags.bits()) };

    Errno::result(res).map(drop)
}

pub fn setns(fd: RawFd, nstype: CloneFlags) -> Result<()> {
    let res = unsafe { ffi::setns(fd, nstype.bits()) };

    Errno::result(res).map(drop)
}
<|endoftext|>


<commit_before>use std::cmp::min;

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Quality(pub f32);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Substring(pub usize,pub usize);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Match<'a> {
    pub quality: Quality,
    pub range: Substring,
    pub original: &'a String,

}

impl <'a>Match<'a>{
    pub fn new(quality: Quality, range: Substring, original: &'a String) -> Match<'a> {
        Match { quality: quality, range: range, original: original }
    }
}

pub fn score<'a>(choice: &'a String, query: &String) -> Option<Match<'a>> {
    let choice_length = choice.len() as f32;
    let query_length = query.len() as f32;

    if query_length == 0.0 { return Some(Match::new(Quality(1.0), Substring(0,0), choice)) }

    match new_compute_match_length(choice, query) {
        Some((start, match_length)) => {
            let quality = Quality( (query_length / match_length as f32) / choice_length);
            let substring = Substring(start, start+match_length);
            Some(Match::new(quality, substring, choice))
        },
        None => None,
    }
}

fn new_compute_match_length(choice: &String, query: &String) -> Option<(usize, usize)> {
    let (first, rest) = match query.slice_shift_char() {
        Some((c, r)) => (c,r),
        None => return None,
    };

    let impossible_match = choice.len() + 1;
    let mut shortest_match = impossible_match;
    let mut shortest_start = impossible_match;

    for_each_beginning(choice, first, |beginning| {
        match match_length_from(choice, rest, beginning) {
            Some(length) => {
                             shortest_match = min(length, shortest_match);
                             shortest_start = beginning;
            },
            None         => {},
        };
    });

    if shortest_match == impossible_match {None} else {Some((shortest_start, shortest_match))}
}

fn for_each_beginning<F: FnMut(usize)>(choice: &String, beginning: char, mut f: F) {
    for (idx, character) in choice.chars().enumerate() {
        if character == beginning {
            f(idx);
        }
    }
}

fn match_length_from(choice: &String, query: &str, beginning: usize) -> Option<usize> {
    let mut match_index = beginning;

    for query_char in query.chars() {
       match find_first_after(choice, query_char, match_index + 1) {
           Some(n) => match_index = n,
           None => return None,
       };
    }
    Some(match_index - beginning + 1)
}

fn find_first_after(choice: &String, query: char, offset: usize) -> Option<usize> {
    choice[offset..]
        .find(query)
        .map(|index| index + offset)
}
<commit_msg>Minor cleanup using Option in compue_match_length<commit_after>use std::cmp::min;

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Quality(pub f32);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Substring(pub usize,pub usize);

#[derive(Debug)]
#[derive(PartialEq)]
pub struct Match<'a> {
    pub quality: Quality,
    pub range: Substring,
    pub original: &'a String,

}

impl <'a>Match<'a>{
    pub fn new(quality: Quality, range: Substring, original: &'a String) -> Match<'a> {
        Match { quality: quality, range: range, original: original }
    }
}

pub fn score<'a>(choice: &'a String, query: &String) -> Option<Match<'a>> {
    let choice_length = choice.len() as f32;
    let query_length = query.len() as f32;

    if query_length == 0.0 { return Some(Match::new(Quality(1.0), Substring(0,0), choice)) }

    match new_compute_match_length(choice, query) {
        Some((start, match_length)) => {
            let quality = Quality( (query_length / match_length as f32) / choice_length);
            let substring = Substring(start, start+match_length);
            Some(Match::new(quality, substring, choice))
        },
        None => None,
    }
}

fn new_compute_match_length(choice: &String, query: &String) -> Option<(usize, usize)> {
    if query.len() == 0 {
        return None;
    }
    let (first, rest) = query.slice_shift_char().unwrap();

    let impossible_match = choice.len() + 1;
    let mut shortest_match = impossible_match;
    let mut shortest_start = impossible_match;

    for_each_beginning(choice, first, |beginning| {
        match match_length_from(choice, rest, beginning) {
            Some(length) => {
                             shortest_match = min(length, shortest_match);
                             shortest_start = beginning;
            },
            None => {},
        };
    });

    if shortest_match == impossible_match {None} else {Some((shortest_start, shortest_match))}
}

fn for_each_beginning<F: FnMut(usize)>(choice: &String, beginning: char, mut f: F) {
    for (idx, character) in choice.chars().enumerate() {
        if character == beginning {
            f(idx);
        }
    }
}

fn match_length_from(choice: &String, query: &str, beginning: usize) -> Option<usize> {
    let mut match_index = beginning;

    for query_char in query.chars() {
       match find_first_after(choice, query_char, match_index + 1) {
           Some(n) => match_index = n,
           None => return None,
       };
    }
    Some(match_index - beginning + 1)
}

fn find_first_after(choice: &String, query: char, offset: usize) -> Option<usize> {
    choice[offset..]
        .find(query)
        .map(|index| index + offset)
}
<|endoftext|>


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

//! Angle units for type-safe, self-documenting code.

use std::fmt;
use std::f64;
use std::ops::*;

use rand::{Rand, Rng};
use rand::distributions::range::SampleRange;

use rust_num::{Float, Zero};
use rust_num::traits::cast;

use approx::ApproxEq;
use num::BaseFloat;

/// An angle, in radians
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Rad<S> { pub s: S }
/// An angle, in degrees
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Deg<S> { pub s: S }

/// Create a new angle, in radians
#[inline] pub fn rad<S: BaseFloat>(s: S) -> Rad<S> { Rad { s: s } }
/// Create a new angle, in degrees
#[inline] pub fn deg<S: BaseFloat>(s: S) -> Deg<S> { Deg { s: s } }

impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
    #[inline]
    fn from(r: Rad<S>) -> Deg<S> {
        Deg::new(r.s * cast(180.0 / f64::consts::PI).unwrap())
    }
}

impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
    #[inline]
    fn from(d: Deg<S>) -> Rad<S> {
        Rad::new(d.s * cast(f64::consts::PI / 180.0).unwrap())
    }
}

/// Operations on angles.
pub trait Angle where
    Self: Copy + Clone,
    Self: PartialEq + PartialOrd,
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    Self: ApproxEq<Epsilon = <Self as Angle>::Unitless>,

    Self: Neg<Output = Self>,
    Self: Add<Self, Output = Self>,
    Self: Sub<Self, Output = Self>,
    Self: Rem<Self, Output = Self>,
    Self: Mul<<Self as Angle>::Unitless, Output = Self>,
    Self: Div<Self, Output = <Self as Angle>::Unitless>,
    Self: Div<<Self as Angle>::Unitless, Output = Self>,
    Self: Rem<<Self as Angle>::Unitless, Output = Self>,
{
    type Unitless: BaseFloat;

    /// Create an angle from a unitless value.
    fn new(value: Self::Unitless) -> Self;

    /// Return the angle, normalized to the range `[0, full_turn)`.
    #[inline]
    fn normalize(self) -> Self {
        let rem = self % Self::full_turn();
        if rem < Self::zero() { rem + Self::full_turn() } else { rem }
    }

    /// Return the angle rotated by half a turn
    #[inline]
    fn opposite(self) -> Self {
        Self::normalize(self + Self::turn_div_2())
    }

    /// Returns the interior bisector of the two angles
    #[inline]
    fn bisect(self, other: Self) -> Self {
        let half = cast(0.5f64).unwrap();
        Self::normalize((self - other) * half + self)
    }

    fn zero() -> Self;
    fn full_turn() -> Self;
    fn turn_div_2() -> Self;
    fn turn_div_3() -> Self;
    fn turn_div_4() -> Self;
    fn turn_div_6() -> Self;

    #[inline]
    fn equiv(&self, other: &Self) -> bool {
        self.normalize() == other.normalize()
    }

    fn sin(self) -> Self::Unitless;
    fn cos(self) -> Self::Unitless;
    fn tan(self) -> Self::Unitless;
    fn sin_cos(self) -> (Self::Unitless, Self::Unitless);

    #[inline] fn cot(self) -> Self::Unitless { Self::tan(self).recip() }
    #[inline] fn sec(self) -> Self::Unitless { Self::cos(self).recip() }
    #[inline] fn csc(self) -> Self::Unitless { Self::sin(self).recip() }

    fn asin(a: Self::Unitless) -> Self;
    fn acos(a: Self::Unitless) -> Self;
    fn atan(a: Self::Unitless) -> Self;
    fn atan2(a: Self::Unitless, b: Self::Unitless) -> Self;
}

macro_rules! impl_angle {
    ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
        impl<S: BaseFloat> Angle for $Angle<S> {
            type Unitless = S;

            #[inline]
            fn new(value: S) -> $Angle<S> {
                $Angle { s: value }
            }

            #[inline]
            fn zero() -> $Angle<S> {
                $Angle::new(S::zero())
            }

            #[inline] fn full_turn() -> $Angle<S> { $Angle::new(cast($full_turn).unwrap()) }
            #[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }

            #[inline] fn sin(self) -> S { Rad::from(self).s.sin() }
            #[inline] fn cos(self) -> S { Rad::from(self).s.cos() }
            #[inline] fn tan(self) -> S { Rad::from(self).s.tan() }
            #[inline] fn sin_cos(self) -> (S, S) { Rad::from(self).s.sin_cos() }

            #[inline] fn asin(a: S) -> $Angle<S> { Rad::new(a.asin()).into() }
            #[inline] fn acos(a: S) -> $Angle<S> { Rad::new(a.acos()).into() }
            #[inline] fn atan(a: S) -> $Angle<S> { Rad::new(a.atan()).into() }
            #[inline] fn atan2(a: S, b: S) -> $Angle<S> { Rad::new(a.atan2(b)).into() }
        }

        impl<S: BaseFloat> Neg for $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
            fn add(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s + rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
            fn sub(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s - rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
            fn div(lhs, rhs) -> S { lhs.s / rhs.s }
        });
        impl_binary_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
            fn rem(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s % rhs.s) }
        });

        impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
            fn mul(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s * scalar) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
            fn div(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s / scalar) }
        });
        impl_binary_operator!(<S: BaseFloat> Rem<S> for $Angle<S> {
            fn rem(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s % scalar) }
        });

        impl<S: BaseFloat> ApproxEq for $Angle<S> {
            type Epsilon = S;

            #[inline]
            fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
                self.s.approx_eq_eps(&other.s, epsilon)
            }
        }

        impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
            #[inline]
            fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
                $Angle::new(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
            }
        }

        impl<S: BaseFloat> fmt::Debug for $Angle<S> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $fmt, self.s)
            }
        }
    }
}

impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
impl_angle!(Deg, "{:?}°", 360, 180);
<commit_msg>Remove Angle % Angle::Unitless<commit_after>// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
// refer to the Cargo.toml file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Angle units for type-safe, self-documenting code.

use std::fmt;
use std::f64;
use std::ops::*;

use rand::{Rand, Rng};
use rand::distributions::range::SampleRange;

use rust_num::{Float, Zero};
use rust_num::traits::cast;

use approx::ApproxEq;
use num::BaseFloat;

/// An angle, in radians
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Rad<S> { pub s: S }
/// An angle, in degrees
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Deg<S> { pub s: S }

/// Create a new angle, in radians
#[inline] pub fn rad<S: BaseFloat>(s: S) -> Rad<S> { Rad { s: s } }
/// Create a new angle, in degrees
#[inline] pub fn deg<S: BaseFloat>(s: S) -> Deg<S> { Deg { s: s } }

impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
    #[inline]
    fn from(r: Rad<S>) -> Deg<S> {
        Deg::new(r.s * cast(180.0 / f64::consts::PI).unwrap())
    }
}

impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
    #[inline]
    fn from(d: Deg<S>) -> Rad<S> {
        Rad::new(d.s * cast(f64::consts::PI / 180.0).unwrap())
    }
}

/// Operations on angles.
pub trait Angle where
    Self: Copy + Clone,
    Self: PartialEq + PartialOrd,
    // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
    Self: ApproxEq<Epsilon = <Self as Angle>::Unitless>,

    Self: Neg<Output = Self>,
    Self: Add<Self, Output = Self>,
    Self: Sub<Self, Output = Self>,
    Self: Rem<Self, Output = Self>,
    Self: Mul<<Self as Angle>::Unitless, Output = Self>,
    Self: Div<Self, Output = <Self as Angle>::Unitless>,
    Self: Div<<Self as Angle>::Unitless, Output = Self>,
{
    type Unitless: BaseFloat;

    /// Create an angle from a unitless value.
    fn new(value: Self::Unitless) -> Self;

    /// Return the angle, normalized to the range `[0, full_turn)`.
    #[inline]
    fn normalize(self) -> Self {
        let rem = self % Self::full_turn();
        if rem < Self::zero() { rem + Self::full_turn() } else { rem }
    }

    /// Return the angle rotated by half a turn
    #[inline]
    fn opposite(self) -> Self {
        Self::normalize(self + Self::turn_div_2())
    }

    /// Returns the interior bisector of the two angles
    #[inline]
    fn bisect(self, other: Self) -> Self {
        let half = cast(0.5f64).unwrap();
        Self::normalize((self - other) * half + self)
    }

    fn zero() -> Self;
    fn full_turn() -> Self;
    fn turn_div_2() -> Self;
    fn turn_div_3() -> Self;
    fn turn_div_4() -> Self;
    fn turn_div_6() -> Self;

    #[inline]
    fn equiv(&self, other: &Self) -> bool {
        self.normalize() == other.normalize()
    }

    fn sin(self) -> Self::Unitless;
    fn cos(self) -> Self::Unitless;
    fn tan(self) -> Self::Unitless;
    fn sin_cos(self) -> (Self::Unitless, Self::Unitless);

    #[inline] fn cot(self) -> Self::Unitless { Self::tan(self).recip() }
    #[inline] fn sec(self) -> Self::Unitless { Self::cos(self).recip() }
    #[inline] fn csc(self) -> Self::Unitless { Self::sin(self).recip() }

    fn asin(a: Self::Unitless) -> Self;
    fn acos(a: Self::Unitless) -> Self;
    fn atan(a: Self::Unitless) -> Self;
    fn atan2(a: Self::Unitless, b: Self::Unitless) -> Self;
}

macro_rules! impl_angle {
    ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
        impl<S: BaseFloat> Angle for $Angle<S> {
            type Unitless = S;

            #[inline]
            fn new(value: S) -> $Angle<S> {
                $Angle { s: value }
            }

            #[inline]
            fn zero() -> $Angle<S> {
                $Angle::new(S::zero())
            }

            #[inline] fn full_turn() -> $Angle<S> { $Angle::new(cast($full_turn).unwrap()) }
            #[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
            #[inline] fn turn_div_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }

            #[inline] fn sin(self) -> S { Rad::from(self).s.sin() }
            #[inline] fn cos(self) -> S { Rad::from(self).s.cos() }
            #[inline] fn tan(self) -> S { Rad::from(self).s.tan() }
            #[inline] fn sin_cos(self) -> (S, S) { Rad::from(self).s.sin_cos() }

            #[inline] fn asin(a: S) -> $Angle<S> { Rad::new(a.asin()).into() }
            #[inline] fn acos(a: S) -> $Angle<S> { Rad::new(a.acos()).into() }
            #[inline] fn atan(a: S) -> $Angle<S> { Rad::new(a.atan()).into() }
            #[inline] fn atan2(a: S, b: S) -> $Angle<S> { Rad::new(a.atan2(b)).into() }
        }

        impl<S: BaseFloat> Neg for $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
            type Output = $Angle<S>;

            #[inline]
            fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
        }

        impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
            fn add(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s + rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
            fn sub(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s - rhs.s) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
            fn div(lhs, rhs) -> S { lhs.s / rhs.s }
        });
        impl_binary_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
            fn rem(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s % rhs.s) }
        });

        impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
            fn mul(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s * scalar) }
        });
        impl_binary_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
            fn div(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s / scalar) }
        });

        impl<S: BaseFloat> ApproxEq for $Angle<S> {
            type Epsilon = S;

            #[inline]
            fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
                self.s.approx_eq_eps(&other.s, epsilon)
            }
        }

        impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
            #[inline]
            fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
                $Angle::new(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
            }
        }

        impl<S: BaseFloat> fmt::Debug for $Angle<S> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, $fmt, self.s)
            }
        }
    }
}

impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
impl_angle!(Deg, "{:?}°", 360, 180);
<|endoftext|>


<commit_before>#![feature(globs)]
extern crate debug;

extern crate graphics;
extern crate piston;
extern crate opengl_graphics;
extern crate sdl2_game_window;

use std::os;

use graphics::*;
use opengl_graphics::{Gl, Texture};
use piston::*;
use sdl2_game_window::GameWindowSDL2;

use lightsout::{StructLevel, Level};
use number_renderer::NumberRenderer;
use game::Game;

mod lightsout;
mod number_renderer;
mod game;

fn cmd_main() {
	let sx:Option<uint> = from_str(os::args()[1].as_slice());
	let sx:uint = match sx {
		Some(x) => x,
		None => 4
	};
	let sy:Option<uint> = from_str(os::args()[2].as_slice());
	let sy:uint = match sy {
		Some(y) => y,
		None => 4
	};
	let mut l:StructLevel = Level::new(sx, sy);
	println!("{}", l);
	println!("solved: {}", l.is_solved());

	let sol = lightsout::solve(&mut l);

	println!("{}", sol);
}

struct Env {
	mousex: f64,
	mousey: f64,
	window_width: f64,
	window_height: f64,
}

#[inline(always)]
fn pt_in_rect(px:f64, py:f64, rx: f64, ry:f64, w:f64, h:f64) -> bool {
	px >= rx && px <= rx + w && py >= ry && py <= ry + h
}

fn clear_board(sx: uint, sy: uint, c: &Context, gl: &mut Gl) {
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	c.rect(0.0, 0.0, margin + (margin + w) * (sx as f64) + 1.0, margin + (margin + h) * (sy as f64) + 1.0)
		.rgb(0.0, 0.0, 0.0).draw(gl);
}

fn render_level(level: &Level, env: &Env, c: &Context, gl: &mut Gl) {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	for y in range(0, sy) {
		for x in range(0, sx) {
			let cx = margin + (margin + w) * (x as f64);
			let cy = margin + (margin + h) * (y as f64);
			if pt_in_rect(env.mousex, env.mousey, cx, cy, w, h) {
				c.rect(cx-1.0, cy-1.0, w+2.0, h+2.0).rgb(1.0, 1.0, 0.0).draw(gl);
			}
			let c = c.rect(cx, cy, w, h);
			if level.get(x, y).unwrap() == 0 {
				c.rgb(0.4, 0.4, 0.4)
			} else {
				c.rgb(0.8, 0.8, 0.8)
			}.draw(gl);
		}
	}
}

fn mouse_to_level(level: &Level, mx: f64, my: f64) -> Option<(uint, uint)> {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	if !pt_in_rect(mx, my,
		       margin, margin,
		       margin + (w + margin) * sx as f64, margin + (h + margin) * sy as f64) {
		return None
	}

	let lx = (mx - margin) / (margin + w);
	let ly = (my - margin) / (margin + h);
	let ulx = lx as uint;
	let uly = ly as uint;
	let sx = margin + (margin + w) * (ulx as f64);
	let sy = margin + (margin + h) * (uly as f64);
	if pt_in_rect(mx, my, sx, sy, w, h) {
		Some((ulx, uly))
	} else {
		None
	}
}

fn render_score(score: int, bg: &Texture, nr: &NumberRenderer, c: &Context, gl: &mut Gl) {
	c.rect(800.0-160.0, 0.0, 160.0, 600.0)
		.image(bg)
		.draw(gl);
	nr.render(score as u32, 715.0, 100.0, 170.0, [1.0, 1.0, 1.0], c, gl);
}

fn win_screen<T: GameWindow>(gameiter: &mut GameIterator<T>, game: &Game, assets: &AssetStore, gl: &mut Gl) {
	let win = Texture::from_path(&assets.path("win.png").unwrap()).unwrap();
	let bg = Texture::from_path(&assets.path("bg.png").unwrap()).unwrap();
	let nr = NumberRenderer::new(assets);
	let mut t = 0.0f64;

	for event in *gameiter {
		match event {
			Render(args) => {
				let c = Context::abs(args.width as f64, args.height as f64);
				c.rect(200.0, 175.0, 400.0, 250.0)
					.image(&win)
					.draw(gl);
				nr.render(game.score as u32, 400.0, 350.0, 200.0, [1.0, 1.0, 1.0], &c, gl);
				render_score(game.score, &bg, &nr, &c, gl);
			},
			Update(args) => {
				t += args.dt;
			},
			MousePress(_)
			| KeyPress(_) => {
				if t > 0.6 {
					return;
				}
			},
			_ => {},
		}
	}
}

fn start_screen<T: GameWindow>(gameiter: &mut GameIterator<T>, assets: &AssetStore, gl: &mut Gl) {
	let msg = Texture::from_path(&assets.path("start.png").unwrap()).unwrap();
	let mut t = 0.0f64;

	for event in *gameiter {
		match event {
			Render(args) => {
				let c = Context::abs(args.width as f64, args.height as f64);
				c.rect(200.0, 175.0, 400.0, 250.0)
					.image(&msg)
					.draw(gl);
			},
			Update(args) => {
				t += args.dt;
			},
			MousePress(_)
			| KeyPress(_) => {
				if t > 1.0 {
					return;
				}
			},
			_ => {},
		}
	}
}

fn main() {
	let mut window = GameWindowSDL2::new(
		GameWindowSettings {
			title: "Rust Lights Out".to_string(),
			size: [800u32, 600u32],
			fullscreen: false,
			exit_on_esc: true,
		}
	);
	println!("window: {:?}", window);

	let game_iter_settings = GameIteratorSettings {
		updates_per_second: 30,
		max_frames_per_second: 60,
	};

	let ref mut gl = Gl::new();

	let mut env = Env {
		mousex: 0f64,
		mousey: 0f64,
		window_width: window.get_settings().size[0] as f64,
		window_height: window.get_settings().size[1] as f64,
	};

	let assets = AssetStore::from_folder("../bin/assets");
	let nr = NumberRenderer::new(&assets);
	let bg = Texture::from_path(&assets.path("bg.png").unwrap()).unwrap();

	let mut game = Game::new(2u, 2u);
	let mut gameiter = GameIterator::new(&mut window, &game_iter_settings);

	start_screen(&mut gameiter, &assets, gl);

	for event in gameiter {
		match event {
			Render(args) => {
				gl.viewport(0, 0, args.width as i32, args.height as i32);
				let c = Context::abs(args.width as f64, args.height as f64);
				clear_board(9, 9, &c, gl);
				render_level(&game.level, &env, &c, gl);
				render_score(game.score, &bg, &nr, &c, gl);
			},
			Update(args) => {
				game.update(args.dt);
				if game.level.is_solved() {
					win_screen(&mut gameiter, &game, &assets, gl);
					if !game.change_level_size(1, 1, true) {
						game.restart(2, 2, true);
					}
				}
			},
			MouseMove(args) => {
				env.mousex = args.x;
				env.mousey = args.y;
			},
			MousePress(args) => {
				println!("{:?} {:?}", args, env);
				match mouse_to_level(&game.level, env.mousex, env.mousey) {
					Some((x, y)) => { game.level.make_move(x, y); game.add_score(-1); },
					_ => {}
				}
			},
			KeyPress(args) => {
				println!("{:?} {:?}", args, env);
				match args.key {
					keyboard::Space => { game.make_ai_move(); game.add_score(-3); },
					keyboard::Up => { game.change_level_size(0, -1, false); game.add_score(-50); },
					keyboard::Right => { game.change_level_size(1, 0, false); game.add_score(-50); },
					keyboard::Down => { game.change_level_size(0, 1, false); game.add_score(-50); },
					keyboard::Left => { game.change_level_size(-1, 0, false); game.add_score(-50); },
					keyboard::D1 => match mouse_to_level(&game.level, env.mousex, env.mousey) {
						Some((x, y)) => { game.level.set(x, y, 0); },
						_ => {},
					},
					keyboard::D2 => match mouse_to_level(&game.level, env.mousex, env.mousey) {
						Some((x, y)) => { game.level.set(x, y, 1); },
						_ => {},
					},
					_ => {}
				}
			},
			_ => {}
		}
	}
}
<commit_msg>clear screen on every render event<commit_after>#![feature(globs)]
extern crate debug;

extern crate graphics;
extern crate piston;
extern crate opengl_graphics;
extern crate sdl2_game_window;

use std::os;

use graphics::*;
use opengl_graphics::{Gl, Texture};
use piston::*;
use sdl2_game_window::GameWindowSDL2;

use lightsout::{StructLevel, Level};
use number_renderer::NumberRenderer;
use game::Game;

mod lightsout;
mod number_renderer;
mod game;

fn cmd_main() {
	let sx:Option<uint> = from_str(os::args()[1].as_slice());
	let sx:uint = match sx {
		Some(x) => x,
		None => 4
	};
	let sy:Option<uint> = from_str(os::args()[2].as_slice());
	let sy:uint = match sy {
		Some(y) => y,
		None => 4
	};
	let mut l:StructLevel = Level::new(sx, sy);
	println!("{}", l);
	println!("solved: {}", l.is_solved());

	let sol = lightsout::solve(&mut l);

	println!("{}", sol);
}

struct Env {
	mousex: f64,
	mousey: f64,
	window_width: f64,
	window_height: f64,
}

#[inline(always)]
fn pt_in_rect(px:f64, py:f64, rx: f64, ry:f64, w:f64, h:f64) -> bool {
	px >= rx && px <= rx + w && py >= ry && py <= ry + h
}

fn render_level(level: &Level, env: &Env, c: &Context, gl: &mut Gl) {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	for y in range(0, sy) {
		for x in range(0, sx) {
			let cx = margin + (margin + w) * (x as f64);
			let cy = margin + (margin + h) * (y as f64);
			if pt_in_rect(env.mousex, env.mousey, cx, cy, w, h) {
				c.rect(cx-1.0, cy-1.0, w+2.0, h+2.0).rgb(1.0, 1.0, 0.0).draw(gl);
			}
			let c = c.rect(cx, cy, w, h);
			if level.get(x, y).unwrap() == 0 {
				c.rgb(0.4, 0.4, 0.4)
			} else {
				c.rgb(0.8, 0.8, 0.8)
			}.draw(gl);
		}
	}
}

fn mouse_to_level(level: &Level, mx: f64, my: f64) -> Option<(uint, uint)> {
	let (sx, sy) = level.size();
	let margin = 10.0;
	let w = 60.0;
	let h = 50.0;
	if !pt_in_rect(mx, my,
		       margin, margin,
		       margin + (w + margin) * sx as f64, margin + (h + margin) * sy as f64) {
		return None
	}

	let lx = (mx - margin) / (margin + w);
	let ly = (my - margin) / (margin + h);
	let ulx = lx as uint;
	let uly = ly as uint;
	let sx = margin + (margin + w) * (ulx as f64);
	let sy = margin + (margin + h) * (uly as f64);
	if pt_in_rect(mx, my, sx, sy, w, h) {
		Some((ulx, uly))
	} else {
		None
	}
}

fn render_score(score: int, bg: &Texture, nr: &NumberRenderer, c: &Context, gl: &mut Gl) {
	c.rect(800.0-160.0, 0.0, 160.0, 600.0)
		.image(bg)
		.draw(gl);
	nr.render(score as u32, 715.0, 100.0, 170.0, [1.0, 1.0, 1.0], c, gl);
}

fn win_screen<T: GameWindow>(gameiter: &mut GameIterator<T>, game: &Game, assets: &AssetStore, gl: &mut Gl) {
	let win = Texture::from_path(&assets.path("win.png").unwrap()).unwrap();
	let bg = Texture::from_path(&assets.path("bg.png").unwrap()).unwrap();
	let nr = NumberRenderer::new(assets);
	let mut t = 0.0f64;

	for event in *gameiter {
		match event {
			Render(args) => {
				let c = Context::abs(args.width as f64, args.height as f64);
				c.rgb(0.0, 0.0, 0.0).draw(gl);
				c.rect(200.0, 175.0, 400.0, 250.0)
					.image(&win)
					.draw(gl);
				nr.render(game.score as u32, 400.0, 350.0, 200.0, [1.0, 1.0, 1.0], &c, gl);
				render_score(game.score, &bg, &nr, &c, gl);
			},
			Update(args) => {
				t += args.dt;
			},
			MousePress(_)
			| KeyPress(_) => {
				if t > 0.6 {
					return;
				}
			},
			_ => {},
		}
	}
}

fn start_screen<T: GameWindow>(gameiter: &mut GameIterator<T>, assets: &AssetStore, gl: &mut Gl) {
	let msg = Texture::from_path(&assets.path("start.png").unwrap()).unwrap();
	let mut t = 0.0f64;

	for event in *gameiter {
		match event {
			Render(args) => {
				let c = Context::abs(args.width as f64, args.height as f64);
				c.rgb(0.0, 0.0, 0.0).draw(gl);
				c.rect(200.0, 175.0, 400.0, 250.0)
					.image(&msg)
					.draw(gl);
			},
			Update(args) => {
				t += args.dt;
			},
			MousePress(_)
			| KeyPress(_) => {
				if t > 1.0 {
					return;
				}
			},
			_ => {},
		}
	}
}

fn main() {
	let mut window = GameWindowSDL2::new(
		GameWindowSettings {
			title: "Rust Lights Out".to_string(),
			size: [800u32, 600u32],
			fullscreen: false,
			exit_on_esc: true,
		}
	);
	println!("window: {:?}", window);

	let game_iter_settings = GameIteratorSettings {
		updates_per_second: 30,
		max_frames_per_second: 60,
	};

	let ref mut gl = Gl::new();

	let mut env = Env {
		mousex: 0f64,
		mousey: 0f64,
		window_width: window.get_settings().size[0] as f64,
		window_height: window.get_settings().size[1] as f64,
	};

	let assets = AssetStore::from_folder("../bin/assets");
	let nr = NumberRenderer::new(&assets);
	let bg = Texture::from_path(&assets.path("bg.png").unwrap()).unwrap();

	let mut game = Game::new(2u, 2u);
	let mut gameiter = GameIterator::new(&mut window, &game_iter_settings);

	start_screen(&mut gameiter, &assets, gl);

	for event in gameiter {
		match event {
			Render(args) => {
				gl.viewport(0, 0, args.width as i32, args.height as i32);
				let c = Context::abs(args.width as f64, args.height as f64);
				c.rgb(0.0, 0.0, 0.0).draw(gl);
				render_level(&game.level, &env, &c, gl);
				render_score(game.score, &bg, &nr, &c, gl);
			},
			Update(args) => {
				game.update(args.dt);
				if game.level.is_solved() {
					win_screen(&mut gameiter, &game, &assets, gl);
					if !game.change_level_size(1, 1, true) {
						game.restart(2, 2, true);
					}
				}
			},
			MouseMove(args) => {
				env.mousex = args.x;
				env.mousey = args.y;
			},
			MousePress(args) => {
				println!("{:?} {:?}", args, env);
				match mouse_to_level(&game.level, env.mousex, env.mousey) {
					Some((x, y)) => { game.level.make_move(x, y); game.add_score(-1); },
					_ => {}
				}
			},
			KeyPress(args) => {
				println!("{:?} {:?}", args, env);
				match args.key {
					keyboard::Space => { game.make_ai_move(); game.add_score(-3); },
					keyboard::Up => { game.change_level_size(0, -1, false); game.add_score(-50); },
					keyboard::Right => { game.change_level_size(1, 0, false); game.add_score(-50); },
					keyboard::Down => { game.change_level_size(0, 1, false); game.add_score(-50); },
					keyboard::Left => { game.change_level_size(-1, 0, false); game.add_score(-50); },
					keyboard::D1 => match mouse_to_level(&game.level, env.mousex, env.mousey) {
						Some((x, y)) => { game.level.set(x, y, 0); },
						_ => {},
					},
					keyboard::D2 => match mouse_to_level(&game.level, env.mousex, env.mousey) {
						Some((x, y)) => { game.level.set(x, y, 1); },
						_ => {},
					},
					_ => {}
				}
			},
			_ => {}
		}
	}
}
<|endoftext|>


<commit_before>pub mod task;
pub mod author;

use std::io::prelude::*;
use std::str::*;
use std::fs::File;

use task::Task;

fn get_task_lines(lines: Lines) -> Vec<Vec<&str>> {
    let mut result = vec![];

    let mut task_lines = vec![];
    let mut is_inside_task_section = false;
    let mut is_inside_task = false;

    for (_, line) in lines.enumerate() {
        if line.trim().to_uppercase().starts_with("## TASKS") {
            is_inside_task_section = true;
        } else if line.trim().starts_with("## ") {
            is_inside_task_section = false;
        } else if is_inside_task_section {
            if line.trim().starts_with("### ") {
                is_inside_task = true;
            }
            if is_inside_task {
                if line.trim().starts_with("### ") && task_lines.len() > 0 {
                    result.push(task_lines.clone());
                    task_lines.clear();
                }
                task_lines.push(line);
            }
        }
    }

    // add last task
    if task_lines.len() > 0 {
        result.push(task_lines.clone());
    }

    result
}

fn load_tasks(filename: String) -> Vec<Task> {
    let mut file = File::open(filename).unwrap();
    let mut body = String::new();
    file.read_to_string(&mut body).unwrap();

    let mut tasks = vec![];
    let lines = get_task_lines(body.lines());

    for task_lines in lines {
        tasks.push(Task::new(task_lines[0].to_string()));
    }
    tasks
}

fn main() {
    let tasks = load_tasks("frump.md".to_string());
    for task in tasks {
        println!("{:?}", task.title);
    }

}
<commit_msg>Minor changes<commit_after>pub mod task;
pub mod author;

use std::io::prelude::*;
use std::str::*;
use std::fs::File;

use task::Task;

fn get_task_lines(lines: Lines) -> Vec<Vec<&str>> {
    let mut result = vec![];
    let mut task_lines = vec![];
    let mut is_inside_task_section = false;
    let mut is_inside_task = false;

    for (_, line) in lines.enumerate() {
        if line.trim().to_uppercase().starts_with("## TASKS") {
            is_inside_task_section = true;
        } else if line.trim().starts_with("## ") {
            is_inside_task_section = false;
        } else if is_inside_task_section {
            if line.trim().starts_with("### ") {
                is_inside_task = true;
            }
            if is_inside_task {
                if line.trim().starts_with("### ") && task_lines.len() > 0 {
                    result.push(task_lines.clone());
                    task_lines.clear();
                }
                task_lines.push(line);
            }
        }
    }

    // add last task
    if task_lines.len() > 0 {
        result.push(task_lines);
    }

    result
}

fn load_tasks(filename: String) -> Vec<Task> {
    let mut file = File::open(filename).unwrap();
    let mut body = String::new();
    file.read_to_string(&mut body).unwrap();

    let mut tasks = vec![];
    let lines = get_task_lines(body.lines());

    for task_lines in lines {
        tasks.push(Task::new(task_lines[0].to_string()));
    }
    tasks
}

fn main() {
    let tasks = load_tasks("frump.md".to_string());
    for task in tasks {
        println!("{:?}", task.title);
    }
}
<|endoftext|>


<commit_before>extern crate orbclient;
extern crate orbfont;
extern crate orbimage;
extern crate starship;

use orbclient::{Color, EventOption, Window, K_UP, K_DOWN, K_DEL, K_ESC, K_F1, K_F2, K_F5, K_F6};
use orbfont::Font;
use orbimage::Image;

use starship::block::{Block, BlockResource};

use std::collections::BTreeMap;
use std::cmp::max;
use std::fs;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

fn main(){
    let mut window = Window::new_flags(100, 100, 1024, 768, "Frontier", true).unwrap();
    let font = Font::from_path("res/FiraMono-Regular.ttf").unwrap();

    let ship_lock = Arc::new(Mutex::new(starship::load("res/ship.json").unwrap()));

    let mut block_kinds: BTreeMap<String, Image> = BTreeMap::new();
    for entry_result in fs::read_dir("res/blocks/").unwrap() {
        let entry = entry_result.unwrap();
        let path = entry.path();
        if path.is_dir() {
            let mut image_path = path.clone();
            image_path.push("image.png");
            if image_path.is_file() {
                block_kinds.insert(entry.file_name().into_string().unwrap(), Image::from_path(&image_path).unwrap());
            }
        }
    }

    assert!(ship_lock.lock().unwrap().decks.len() > 0);

    let running = Arc::new(AtomicBool::new(true));
    let redraw = Arc::new(AtomicBool::new(true));

    let running_update = running.clone();
    let redraw_update = redraw.clone();
    let ship_update = ship_lock.clone();
    let handle = thread::spawn(move || {
        while running_update.load(Ordering::SeqCst) {
            {
                let mut ship = ship_update.lock().unwrap();
                if ship.update() {
                    redraw_update.store(true, Ordering::SeqCst);
                }
            }
            thread::sleep(Duration::from_millis(10));
        }
    });

    let mut dragging = None;
    let mut editing = None;
    let mut show_info = false;

    while running.load(Ordering::SeqCst) {
        {
            let mut ship = ship_lock.lock().unwrap();
            let mut deck_i = ship.current_deck;
            let mut reload = false;
            let mut save = false;

            {
                let name = ship.name.clone();
                let deck_len = ship.decks.len();
                let deck = &mut ship.decks[deck_i];

                if redraw.load(Ordering::SeqCst) {
                    redraw.store(false, Ordering::SeqCst);

                    let window_w = window.width();
                    //let window_h = window.height();

                    window.set(Color::rgb(255, 255, 255));

                    let title = font.render(&format!("{} - {} - {}", name, deck_i, deck.name), 24.0);
                    let title_x = (window_w - title.width()) as i32/2;
                    title.draw(&mut window, title_x, 0, Color::rgb(0, 0, 0));

                    window.rect(0, 26, window_w, 2, Color::rgb(0, 0, 0));

                    for block in deck.blocks.iter() {
                        let x = block.x as i32 * 32;
                        let y = block.y as i32 * 32 + 32;
                        if let Some(image) = block_kinds.get(&block.kind) {
                            image.draw(&mut window, x, y);
                        } else {
                            window.rect(x, y, 32, 32, Color::rgb(128, 128, 128));
                            font.render(&block.kind, 16.0).draw(&mut window, x, y, Color::rgb(0, 0, 0));
                        }

                        if show_info {
                            if block.kind == "Tank" {
                                if let Some((name, resource)) = block.resources.iter().next() {
                                    let text = font.render(name, 16.0);
                                    text.draw(&mut window, x, y, Color::rgb(0, 0, 0));

                                    let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                    text.draw(&mut window, x, y + 16, Color::rgb(0, 0, 0));
                                }
                            } else if block.kind == "Vent" {
                                if let Some(resource) = block.resources.get("air") {
                                    let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                    text.draw(&mut window, x, y, Color::rgb(0, 0, 0));
                                }
                                if let Some(resource) = block.resources.get("free_air") {
                                    let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                    text.draw(&mut window, x, y + 16, Color::rgb(0, 0, 0));
                                }
                            } else if block.kind == "Deck" || block.kind == "Man" {
                                if let Some(resource) = block.resources.get("free_air") {
                                    let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                    text.draw(&mut window, x, y + 16, Color::rgb(0, 0, 0));
                                }
                            }
                        }
                    }

                    if let Some(i) = dragging {
                        if let Some(block) = deck.blocks.get(i) {
                            let x = block.x as i32 * 32;
                            let y = block.y as i32 * 32 + 32;

                            window.rect(x, y, 32, 2, Color::rgb(255, 0, 0));
                            window.rect(x, y, 2, 32, Color::rgb(255, 0, 0));
                            window.rect(x, y + 30, 32, 2, Color::rgb(255, 0, 0));
                            window.rect(x + 30, y, 2, 32, Color::rgb(255, 0, 0));
                        }
                    }

                    if let Some((block_x, block_y)) = editing {
                        let x = block_x as i32 * 32;
                        let y = block_y as i32 * 32 + 32;

                        window.rect(x, y, 32, 2, Color::rgb(0, 0, 255));
                        window.rect(x, y, 2, 32, Color::rgb(0, 0, 255));
                        window.rect(x, y + 30, 32, 2, Color::rgb(0, 0, 255));
                        window.rect(x + 30, y, 2, 32, Color::rgb(0, 0, 255));
                    }

                    window.sync();
                }

                let mut evented = true;
                while evented {
                    evented = false;

                    for event in window.events() {
                        evented = true;

                        match event.to_option() {
                            EventOption::Key(key_event) => if key_event.pressed {
                                match key_event.scancode {
                                    K_UP => if deck_i + 1 < deck_len {
                                        deck_i += 1;
                                    },
                                    K_DOWN => if deck_i > 0 {
                                        deck_i -= 1;
                                    },
                                    K_DEL => if let Some((block_x, block_y)) = editing.take() {
                                        let mut remove = None;
                                        for (i, block) in deck.blocks.iter().enumerate() {
                                            if block_x == block.x && block_y == block.y {
                                                remove = Some(i);
                                            }
                                        }
                                        if let Some(i) = remove {
                                            deck.blocks.remove(i);
                                            redraw.store(true, Ordering::SeqCst);
                                        }
                                    },
                                    K_ESC => if editing.take().is_some() {
                                        redraw.store(true, Ordering::SeqCst);
                                    },
                                    K_F1 => if ! show_info {
                                        show_info = true;
                                        redraw.store(true, Ordering::SeqCst);
                                    },
                                    K_F2 => if show_info {
                                        show_info = false;
                                        redraw.store(true, Ordering::SeqCst);
                                    },
                                    K_F5 => reload = true,
                                    K_F6 => save = true,
                                    _ => {
                                        match key_event.character {
                                            'A' | 'a' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("air".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'E' | 'e' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("electricity".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'F' | 'f' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("fuel".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'W' | 'w' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("water".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'C' | 'c' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Conduit".to_string());
                                                block.resources.insert("air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("electricity".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("fuel".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("water".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'D' | 'd' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Deck".to_string());
                                                block.resources.insert("free_air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'H' | 'h' => if let Some((block_x, block_y)) = editing.take() {
                                                deck.blocks.push(Block::new(block_x, block_y, "Hull".to_string()));
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'M' | 'm' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Man".to_string());
                                                block.resources.insert("free_air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'V' | 'v' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Vent".to_string());
                                                block.resources.insert("air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("free_air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            _ => ()
                                        }
                                    }
                                }
                            },
                            EventOption::Mouse(mouse_event) => {
                                if mouse_event.left_button {
                                    if let Some(i) = dragging {
                                        let x = max(mouse_event.x/32, 0) as usize;
                                        let y = max((mouse_event.y - 32)/32, 0) as usize;

                                        let block = &mut deck.blocks[i];
                                        if block.x != x || block.y != y {
                                            block.x = x;
                                            block.y = y;
                                            redraw.store(true, Ordering::SeqCst);
                                        }
                                    } else {
                                        println!("Left {}, {}", mouse_event.x, mouse_event.y);

                                        for (i, block) in deck.blocks.iter().enumerate() {
                                            let x = block.x as i32 * 32;
                                            let y = block.y as i32 * 32 + 32;
                                            if mouse_event.x >= x && mouse_event.x < x + 32 && mouse_event.y >= y && mouse_event.y < y + 32 {
                                                dragging = Some(i);
                                                redraw.store(true, Ordering::SeqCst);
                                                println!("    {:?}", block);
                                            }
                                        }
                                    }
                                } else {
                                    if dragging.take().is_some() {
                                        redraw.store(true, Ordering::SeqCst);
                                    }
                                }

                                if mouse_event.right_button {
                                    let x = max(mouse_event.x/32, 0) as usize;
                                    let y = max((mouse_event.y - 32)/32, 0) as usize;

                                    if editing != Some((x, y)) {
                                        println!("Right {}, {}", mouse_event.x, mouse_event.y);
                                        editing = Some((x, y));
                                        redraw.store(true, Ordering::SeqCst);

                                        for block in deck.blocks.iter() {
                                            let x = block.x as i32 * 32;
                                            let y = block.y as i32 * 32 + 32;
                                            if mouse_event.x >= x && mouse_event.x < x + 32 && mouse_event.y >= y && mouse_event.y < y + 32 {
                                                println!("    {:?}", block);
                                            }
                                        }
                                    }
                                }
                            },
                            EventOption::Quit(_quit_event) => running.store(false, Ordering::SeqCst),
                            _ => ()
                        }
                    }
                }
            }

            if deck_i != ship.current_deck {
                ship.current_deck = deck_i;
                redraw.store(true, Ordering::SeqCst);
            }

            if save {
                println!("Save");
                starship::save("res/ship.json", &*ship).unwrap();
            }

            if reload {
                println!("Reload");
                *ship = starship::load("res/ship.json").unwrap();
                redraw.store(true, Ordering::SeqCst);
            }
        }

        thread::sleep(Duration::from_millis(10));
    }

    handle.join().unwrap();
}
<commit_msg>Cleanup<commit_after>extern crate orbclient;
extern crate orbfont;
extern crate orbimage;
extern crate starship;

use orbclient::{Color, EventOption, Window, K_UP, K_DOWN, K_DEL, K_ESC, K_F1, K_F2, K_F5, K_F6};
use orbfont::Font;
use orbimage::Image;

use starship::block::{Block, BlockResource};

use std::collections::BTreeMap;
use std::cmp::max;
use std::fs;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::Duration;

fn main(){
    let mut window = Window::new_flags(100, 100, 1024, 768, "Frontier", true).unwrap();
    let font = Font::from_path("res/FiraMono-Regular.ttf").unwrap();

    let ship_lock = Arc::new(Mutex::new(starship::load("res/ship.json").unwrap()));

    let mut block_kinds: BTreeMap<String, Image> = BTreeMap::new();
    for entry_result in fs::read_dir("res/blocks/").unwrap() {
        let entry = entry_result.unwrap();
        let path = entry.path();
        if path.is_dir() {
            let mut image_path = path.clone();
            image_path.push("image.png");
            if image_path.is_file() {
                block_kinds.insert(entry.file_name().into_string().unwrap(), Image::from_path(&image_path).unwrap());
            }
        }
    }

    assert!(ship_lock.lock().unwrap().decks.len() > 0);

    let running = Arc::new(AtomicBool::new(true));
    let redraw = Arc::new(AtomicBool::new(true));

    let running_update = running.clone();
    let redraw_update = redraw.clone();
    let ship_update = ship_lock.clone();
    let handle = thread::spawn(move || {
        while running_update.load(Ordering::SeqCst) {
            {
                let mut ship = ship_update.lock().unwrap();
                if ship.update() {
                    redraw_update.store(true, Ordering::SeqCst);
                }
            }
            thread::sleep(Duration::from_millis(10));
        }
    });

    let mut dragging = None;
    let mut editing = None;
    let mut show_info = false;

    while running.load(Ordering::SeqCst) {
        {
            let mut ship = ship_lock.lock().unwrap();

            if redraw.load(Ordering::SeqCst) {
                redraw.store(false, Ordering::SeqCst);

                let window_w = window.width();
                //let window_h = window.height();

                let deck = &ship.decks[ship.current_deck];

                window.set(Color::rgb(255, 255, 255));

                let title = font.render(&format!("{} - {} - {}", ship.name, ship.current_deck, deck.name), 24.0);
                let title_x = (window_w - title.width()) as i32/2;
                title.draw(&mut window, title_x, 0, Color::rgb(0, 0, 0));

                window.rect(0, 26, window_w, 2, Color::rgb(0, 0, 0));

                for block in deck.blocks.iter() {
                    let x = block.x as i32 * 32;
                    let y = block.y as i32 * 32 + 32;
                    if let Some(image) = block_kinds.get(&block.kind) {
                        image.draw(&mut window, x, y);
                    } else {
                        window.rect(x, y, 32, 32, Color::rgb(128, 128, 128));
                        font.render(&block.kind, 16.0).draw(&mut window, x, y, Color::rgb(0, 0, 0));
                    }

                    if show_info {
                        if block.kind == "Tank" {
                            if let Some((name, resource)) = block.resources.iter().next() {
                                let text = font.render(name, 16.0);
                                text.draw(&mut window, x, y, Color::rgb(0, 0, 0));

                                let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                text.draw(&mut window, x, y + 16, Color::rgb(0, 0, 0));
                            }
                        } else if block.kind == "Vent" {
                            if let Some(resource) = block.resources.get("air") {
                                let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                text.draw(&mut window, x, y, Color::rgb(0, 0, 0));
                            }
                            if let Some(resource) = block.resources.get("free_air") {
                                let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                text.draw(&mut window, x, y + 16, Color::rgb(0, 0, 0));
                            }
                        } else if block.kind == "Deck" || block.kind == "Man" {
                            if let Some(resource) = block.resources.get("free_air") {
                                let text = font.render(&format!("{}", resource.amount as u32), 16.0);
                                text.draw(&mut window, x, y + 16, Color::rgb(0, 0, 0));
                            }
                        }
                    }
                }

                if let Some(i) = dragging {
                    if let Some(block) = deck.blocks.get(i) {
                        let x = block.x as i32 * 32;
                        let y = block.y as i32 * 32 + 32;

                        window.rect(x, y, 32, 2, Color::rgb(255, 0, 0));
                        window.rect(x, y, 2, 32, Color::rgb(255, 0, 0));
                        window.rect(x, y + 30, 32, 2, Color::rgb(255, 0, 0));
                        window.rect(x + 30, y, 2, 32, Color::rgb(255, 0, 0));
                    }
                }

                if let Some((block_x, block_y)) = editing {
                    let x = block_x as i32 * 32;
                    let y = block_y as i32 * 32 + 32;

                    window.rect(x, y, 32, 2, Color::rgb(0, 0, 255));
                    window.rect(x, y, 2, 32, Color::rgb(0, 0, 255));
                    window.rect(x, y + 30, 32, 2, Color::rgb(0, 0, 255));
                    window.rect(x + 30, y, 2, 32, Color::rgb(0, 0, 255));
                }

                window.sync();
            }

            let mut deck_i = ship.current_deck;
            let mut reload = false;
            let mut save = false;
            {
                let deck_len = ship.decks.len();
                let deck = &mut ship.decks[deck_i];

                let mut evented = true;
                while evented {
                    evented = false;

                    for event in window.events() {
                        evented = true;

                        match event.to_option() {
                            EventOption::Key(key_event) => if key_event.pressed {
                                match key_event.scancode {
                                    K_UP => if deck_i + 1 < deck_len {
                                        deck_i += 1;
                                    },
                                    K_DOWN => if deck_i > 0 {
                                        deck_i -= 1;
                                    },
                                    K_DEL => if let Some((block_x, block_y)) = editing.take() {
                                        let mut remove = None;
                                        for (i, block) in deck.blocks.iter().enumerate() {
                                            if block_x == block.x && block_y == block.y {
                                                remove = Some(i);
                                            }
                                        }
                                        if let Some(i) = remove {
                                            deck.blocks.remove(i);
                                            redraw.store(true, Ordering::SeqCst);
                                        }
                                    },
                                    K_ESC => if editing.take().is_some() {
                                        redraw.store(true, Ordering::SeqCst);
                                    },
                                    K_F1 => if ! show_info {
                                        show_info = true;
                                        redraw.store(true, Ordering::SeqCst);
                                    },
                                    K_F2 => if show_info {
                                        show_info = false;
                                        redraw.store(true, Ordering::SeqCst);
                                    },
                                    K_F5 => reload = true,
                                    K_F6 => save = true,
                                    _ => {
                                        match key_event.character {
                                            'A' | 'a' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("air".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'E' | 'e' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("electricity".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'F' | 'f' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("fuel".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'W' | 'w' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Tank".to_string());
                                                block.resources.insert("water".into(), BlockResource { amount: 100.0, capacity: 100.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'C' | 'c' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Conduit".to_string());
                                                block.resources.insert("air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("electricity".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("fuel".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("water".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'D' | 'd' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Deck".to_string());
                                                block.resources.insert("free_air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'H' | 'h' => if let Some((block_x, block_y)) = editing.take() {
                                                deck.blocks.push(Block::new(block_x, block_y, "Hull".to_string()));
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'M' | 'm' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Man".to_string());
                                                block.resources.insert("free_air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            'V' | 'v' => if let Some((block_x, block_y)) = editing.take() {
                                                let mut block = Block::new(block_x, block_y, "Vent".to_string());
                                                block.resources.insert("air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                block.resources.insert("free_air".into(), BlockResource { amount: 0.0, capacity: 5.0 });
                                                deck.blocks.push(block);
                                                redraw.store(true, Ordering::SeqCst);
                                            },
                                            _ => ()
                                        }
                                    }
                                }
                            },
                            EventOption::Mouse(mouse_event) => {
                                if mouse_event.left_button {
                                    if let Some(i) = dragging {
                                        let x = max(mouse_event.x/32, 0) as usize;
                                        let y = max((mouse_event.y - 32)/32, 0) as usize;

                                        let block = &mut deck.blocks[i];
                                        if block.x != x || block.y != y {
                                            block.x = x;
                                            block.y = y;
                                            redraw.store(true, Ordering::SeqCst);
                                        }
                                    } else {
                                        println!("Left {}, {}", mouse_event.x, mouse_event.y);

                                        for (i, block) in deck.blocks.iter().enumerate() {
                                            let x = block.x as i32 * 32;
                                            let y = block.y as i32 * 32 + 32;
                                            if mouse_event.x >= x && mouse_event.x < x + 32 && mouse_event.y >= y && mouse_event.y < y + 32 {
                                                dragging = Some(i);
                                                redraw.store(true, Ordering::SeqCst);
                                                println!("    {:?}", block);
                                            }
                                        }
                                    }
                                } else {
                                    if dragging.take().is_some() {
                                        redraw.store(true, Ordering::SeqCst);
                                    }
                                }

                                if mouse_event.right_button {
                                    let x = max(mouse_event.x/32, 0) as usize;
                                    let y = max((mouse_event.y - 32)/32, 0) as usize;

                                    if editing != Some((x, y)) {
                                        println!("Right {}, {}", mouse_event.x, mouse_event.y);
                                        editing = Some((x, y));
                                        redraw.store(true, Ordering::SeqCst);

                                        for block in deck.blocks.iter() {
                                            let x = block.x as i32 * 32;
                                            let y = block.y as i32 * 32 + 32;
                                            if mouse_event.x >= x && mouse_event.x < x + 32 && mouse_event.y >= y && mouse_event.y < y + 32 {
                                                println!("    {:?}", block);
                                            }
                                        }
                                    }
                                }
                            },
                            EventOption::Quit(_quit_event) => running.store(false, Ordering::SeqCst),
                            _ => ()
                        }
                    }
                }
            }

            if deck_i != ship.current_deck {
                ship.current_deck = deck_i;
                redraw.store(true, Ordering::SeqCst);
            }

            if save {
                println!("Save");
                starship::save("res/ship.json", &*ship).unwrap();
            }

            if reload {
                println!("Reload");
                *ship = starship::load("res/ship.json").unwrap();
                redraw.store(true, Ordering::SeqCst);
            }
        }

        thread::sleep(Duration::from_millis(10));
    }

    handle.join().unwrap();
}
<|endoftext|>