<commit_before>extern crate unicode_width;

mod args;
mod matching;
mod screen;
#[cfg(not(windows))] mod ansi;

use std::cmp::min;
use std::collections::HashSet;
use std::env;
use std::io::{stdin, BufRead};
use std::process;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] pub const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] pub const NEWLINE: &'static str = "\n";

const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
const TIMESTAMP: &'static str = include_str!(concat!(env!("OUT_DIR"), "/timestamp.txt"));
const TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/target.txt"));
const COMMIT: &'static str = include_str!(concat!(env!("OUT_DIR"), "/commit.txt"));

fn main() {
    env::set_var("RUST_BACKTRACE", "1");
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {} for {})", VERSION, TIMESTAMP, TARGET);
        } else {
            println!("heatseeker {}-{} (built {} for {})", VERSION, COMMIT, TIMESTAMP, TARGET);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search, args.filter_only);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        let desired_rows = if args.full_screen { 999 } else { 20 };
        let selections = event_loop(desired_rows, &choices, &initial_search, args.filter_only);
        print!("{}", selections);
    }
}

fn event_loop(desired_rows: u16, choices: &[&str], initial_search: &str, filter_only: bool) -> String {
    let mut search = Search::new(choices, initial_search.to_string(), filter_only);
    let mut screen = screen::new(desired_rows);

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(screen.as_mut(), &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in &keys {
            handle_key(&mut search, key, screen.visible_choices());
        }
    }

    screen.blank_screen();
    search.get_selections()
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace |
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('c') |
        Control('g') => search.cancel(),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('p') |
        Up |
        ShiftTab => search.up(visible_choices),
        Control('n') |
        Down |
        Tab => search.down(visible_choices),
        Home => search.home(),
        End => search.end(visible_choices),
        Enter => search.done(),
        PgUp => search.pgup(visible_choices),
        PgDown => search.pgdown(visible_choices),
        _ => {},
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    scroll_offset: usize,
    cursor_index: usize,
    state: SearchState,
    selections: HashSet<String>,
    filter_only: bool,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String, filter_only: bool) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            scroll_offset: 0,
            cursor_index: 0,
            state: InProgress,
            selections: HashSet::new(),
            filter_only: filter_only,
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.scroll_offset == 0;
        if self.cursor_index == 0 {
            if should_wrap {
                if match_count > visible_choices as usize {
                    self.scroll_offset = match_count - visible_choices as usize;
                    self.cursor_index = visible_choices as usize - 1;
                } else {
                    self.cursor_index = limit;
                }
            } else {
                self.scroll_offset -= 1;
            }
        } else {
            self.cursor_index -= 1;
        }
    }

    fn down(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.cursor_index + self.scroll_offset == match_count - 1;
        if self.cursor_index == limit {
            if should_wrap {
                self.cursor_index = 0;
                self.scroll_offset = 0;
            } else {
                self.scroll_offset += 1;
            }
        } else {
            self.cursor_index += 1;
        }
    }

    fn home(&mut self) {
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn end(&mut self, visible_choices: u16) {
        self.home();
        self.up(visible_choices);
    }

    fn pgup(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset == 0 && self.cursor_index == 0 {
                return;
            }
            self.up(visible_choices);
        }
    }

    fn pgdown(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset + self.cursor_index == self.matches.len() - 1 {
                return;
            }
            self.down(visible_choices);
        }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query, self.filter_only);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            for selection in &self.selections {
                ret.push_str(selection);
                ret.push_str(NEWLINE);
            }
            if ret.is_empty() {
                self.recompute_matches();
                let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
                ret.push_str(&selection);
            }
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut dyn Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.scroll_offset, search.cursor_index, &search.selections);

    let query_str: &str = &search.query;
    screen.move_cursor_to_prompt_line(2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut dyn Screen, matches: &[&str], query: &str, scroll_offset: usize, cursor_index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches[scroll_offset..].iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width();
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == cursor_index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else if highlight {
                screen.write_red(s);
            } else { screen.write(s); }
        });
        if i >= screen.visible_choices() as usize {
            return;
        }
        screen.write(NEWLINE);
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut dyn FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let mut chars_to_draw = min(chars_in_choice, max_width as usize);
    while UnicodeWidthStr::width(slice_chars(choice, 0, chars_to_draw)) > max_width as usize {
        chars_to_draw -= 1;
    }
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    let mut first_error = None;
    let mut suppressed = 0;
    loop {
        let mut s = String::new();
        match stdin.read_line(&mut s) {
            Ok(_) => {
                if s.is_empty() { break; }
                trim(&mut s);
                lines.push(s);
            },
            Err(e) => {
                if first_error.is_some() {
                    suppressed = suppressed + 1;
                } else {
                    first_error = Some(e);
                }
            }
        }
    }
    if first_error.is_some() {
        eprintln!("Warning: Failed to parse one or more lines (\"{}\"); {} additional error(s) suppressed", first_error.unwrap(), suppressed);
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' && x != '\r' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.get_unchecked(a..b) }
    }
}

#[cfg(test)]
mod tests {
    use super::{trim, delete_last_word};

    #[test]
    fn trim_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            trim(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("\n", "");
        should_become("\n\n", "");
        should_become("asdf", "asdf");
        should_become("asdf\n", "asdf");
        should_become("asdf\nasdf\n", "asdf\nasdf");
        should_become("asdf\r\n", "asdf");
    }

    #[test]
    fn delete_word_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            delete_last_word(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("a", "");
        should_become("asdf", "");
        should_become("asdf asdf asdf", "asdf asdf ");
        should_become("asdf asdf asdf ", "asdf asdf ");
        should_become("asdf asdf asdf  ", "asdf asdf ");
    }
}
<commit_msg>Add test panic feature<commit_after>extern crate unicode_width;

mod args;
mod matching;
mod screen;
#[cfg(not(windows))] mod ansi;

use std::cmp::min;
use std::collections::HashSet;
use std::env;
use std::io::{stdin, BufRead};
use std::process;
use screen::Screen;
use screen::Key;
use screen::Key::*;
use self::SearchState::*;
use unicode_width::UnicodeWidthStr;

#[cfg(windows)] pub const NEWLINE: &'static str = "\r\n";
#[cfg(not(windows))] pub const NEWLINE: &'static str = "\n";

const VERSION: &'static str = include_str!(concat!(env!("OUT_DIR"), "/version.txt"));
const TIMESTAMP: &'static str = include_str!(concat!(env!("OUT_DIR"), "/timestamp.txt"));
const TARGET: &'static str = include_str!(concat!(env!("OUT_DIR"), "/target.txt"));
const COMMIT: &'static str = include_str!(concat!(env!("OUT_DIR"), "/commit.txt"));

fn main() {
    env::set_var("RUST_BACKTRACE", "1");
    let args = match args::parse_args() {
        Some(args) => args,
        None => {
            process::exit(1);
        },
    };

    if args.help { return; }

    if args.version {
        if COMMIT == "" {
            println!("heatseeker {} (built {} for {})", VERSION, TIMESTAMP, TARGET);
        } else {
            println!("heatseeker {}-{} (built {} for {})", VERSION, COMMIT, TIMESTAMP, TARGET);
        }
        return;
    }

    let choices = read_choices();
    let initial_search = args.initial_search.clone();
    let choices = choices.iter().map(|x| &x[..]).collect::<Vec<&str>>();
    if args.use_first {
        let matches = matching::compute_matches(&choices, &initial_search, args.filter_only);
        println!("{}", matches.get(0).unwrap_or(&""));
        return;
    } else {
        let desired_rows = if args.full_screen { 999 } else { 20 };
        let selections = event_loop(desired_rows, &choices, &initial_search, args.filter_only);
        print!("{}", selections);
    }
}

fn event_loop(desired_rows: u16, choices: &[&str], initial_search: &str, filter_only: bool) -> String {
    let mut search = Search::new(choices, initial_search.to_string(), filter_only);
    let mut screen = screen::new(desired_rows);

    loop {
        search.recompute_matches();

        match search.state {
            InProgress => draw_screen(screen.as_mut(), &search),
            _ => break,
        }

        let keys = screen.get_buffered_keys();
        for key in &keys {
            handle_key(&mut search, key, screen.visible_choices());
        }
    }

    screen.blank_screen();
    search.get_selections()
}

fn handle_key(search: &mut Search, key: &Key, visible_choices: u16) {
    match *key {
        Char(x) => search.append(x),
        Backspace |
        Control('h') => search.backspace(),
        Control('w') => search.delete_word(),
        Control('u') => search.clear_query(),
        Control('r') => std::panic!("This is a test backtrace"),
        Control('c') |
        Control('g') => search.cancel(),
        Control('t') => { search.toggle_selection(); search.down(visible_choices); },
        Control('p') |
        Up |
        ShiftTab => search.up(visible_choices),
        Control('n') |
        Down |
        Tab => search.down(visible_choices),
        Home => search.home(),
        End => search.end(visible_choices),
        Enter => search.done(),
        PgUp => search.pgup(visible_choices),
        PgDown => search.pgdown(visible_choices),
        _ => {},
    }
}

struct Search<'a> {
    choices: &'a [&'a str],
    query: String,
    matches: Vec<&'a str>,
    stale: bool,
    scroll_offset: usize,
    cursor_index: usize,
    state: SearchState,
    selections: HashSet<String>,
    filter_only: bool,
}

#[derive(PartialEq, Eq)]
enum SearchState {
    InProgress,
    Done,
    Canceled,
}

impl<'a> Search<'a> {
    fn new(choices: &'a [&'a str], initial_search: String, filter_only: bool) -> Search<'a> {
        let matches = choices.to_vec();
        Search {
            choices: choices,
            query: initial_search,
            matches: matches,
            stale: true,
            scroll_offset: 0,
            cursor_index: 0,
            state: InProgress,
            selections: HashSet::new(),
            filter_only: filter_only,
        }
    }

    fn up(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.scroll_offset == 0;
        if self.cursor_index == 0 {
            if should_wrap {
                if match_count > visible_choices as usize {
                    self.scroll_offset = match_count - visible_choices as usize;
                    self.cursor_index = visible_choices as usize - 1;
                } else {
                    self.cursor_index = limit;
                }
            } else {
                self.scroll_offset -= 1;
            }
        } else {
            self.cursor_index -= 1;
        }
    }

    fn down(&mut self, visible_choices: u16) {
        let match_count = self.matches.len();
        let limit = min(visible_choices as usize - 1, match_count - 1);
        let should_wrap = self.cursor_index + self.scroll_offset == match_count - 1;
        if self.cursor_index == limit {
            if should_wrap {
                self.cursor_index = 0;
                self.scroll_offset = 0;
            } else {
                self.scroll_offset += 1;
            }
        } else {
            self.cursor_index += 1;
        }
    }

    fn home(&mut self) {
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn end(&mut self, visible_choices: u16) {
        self.home();
        self.up(visible_choices);
    }

    fn pgup(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset == 0 && self.cursor_index == 0 {
                return;
            }
            self.up(visible_choices);
        }
    }

    fn pgdown(&mut self, visible_choices: u16) {
        for _ in 0..visible_choices {
            if self.scroll_offset + self.cursor_index == self.matches.len() - 1 {
                return;
            }
            self.down(visible_choices);
        }
    }

    fn backspace(&mut self) {
        self.query.pop();
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn delete_word(&mut self) {
        self.stale = true;
        delete_last_word(&mut self.query);
        self.matches = self.choices.to_vec();
    }

    fn append(&mut self, c: char) {
        self.query.push(c);
        self.stale = true;
        self.cursor_index = 0;
        self.scroll_offset = 0;
    }

    fn clear_query(&mut self) {
        self.query.clear();
        self.cursor_index = 0;
        self.scroll_offset = 0;
        self.matches = self.choices.to_vec();
    }

    fn recompute_matches(&mut self) {
        if self.stale {
            self.matches = matching::compute_matches(&self.matches, &self.query, self.filter_only);
            self.stale = false;
        }
    }

    fn toggle_selection(&mut self) {
        self.recompute_matches();
        let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
        if self.selections.contains(&selection) {
            self.selections.remove(&selection);
        } else {
            self.selections.insert(selection);
        }
    }

    fn get_selections(&mut self) -> String {
        let mut ret = String::new();
        if self.state != Canceled {
            for selection in &self.selections {
                ret.push_str(selection);
                ret.push_str(NEWLINE);
            }
            if ret.is_empty() {
                self.recompute_matches();
                let selection = self.matches.get(self.scroll_offset + self.cursor_index).unwrap_or(&"").to_string();
                ret.push_str(&selection);
            }
        }
        ret
    }

    fn cancel(&mut self) {
        self.state = Canceled
    }

    fn done(&mut self) {
        self.state = Done
    }
}

fn draw_screen(screen: &mut dyn Screen, search: &Search) {
    screen.hide_cursor();
    screen.blank_screen();
    screen.write(&format!("> {} ({}/{} choices){}", search.query, search.matches.len(), search.choices.len(), NEWLINE));

    print_matches(screen, &search.matches, &search.query, search.scroll_offset, search.cursor_index, &search.selections);

    let query_str: &str = &search.query;
    screen.move_cursor_to_prompt_line(2 + UnicodeWidthStr::width(query_str) as u16);
    screen.show_cursor();
}

fn print_matches(screen: &mut dyn Screen, matches: &[&str], query: &str, scroll_offset: usize, cursor_index: usize, selections: &HashSet<String>) {
    let mut i = 1;
    for choice in matches[scroll_offset..].iter() {
        let indices = matching::visual_score(choice, query);
        let max_width = screen.width();
        let mut annotated_choice = choice.to_string();
        if selections.contains(&annotated_choice) {
            annotated_choice.push(' ');
            if cfg!(windows) {
                annotated_choice.push('√');
            } else {
                annotated_choice.push('✓');
            }
        }
        print_match(&annotated_choice, &indices, max_width, &mut |s, highlight| {
            if i == cursor_index + 1 {
                if highlight { screen.write_red_inverted(s); } else { screen.write_inverted(s); }
            } else if highlight {
                screen.write_red(s);
            } else { screen.write(s); }
        });
        if i >= screen.visible_choices() as usize {
            return;
        }
        screen.write(NEWLINE);
        i += 1;
    }
}

fn print_match(choice: &str, indices: &[usize], max_width: u16, writer: &mut dyn FnMut(&str, bool)) {
    #[cfg(windows)] const MARGIN: u16 = 1;
    #[cfg(not(windows))] const MARGIN: u16 = 0;
    let max_width = max_width - MARGIN;
    let chars_in_choice = choice.chars().count();
    let mut chars_to_draw = min(chars_in_choice, max_width as usize);
    while UnicodeWidthStr::width(slice_chars(choice, 0, chars_to_draw)) > max_width as usize {
        chars_to_draw -= 1;
    }
    let mut last_idx = 0;
    for &idx in indices {
        let idx = min(idx, chars_to_draw);
        if last_idx >= chars_to_draw {
            return;
        }
        writer(slice_chars(choice, last_idx, idx), false);
        if idx == chars_to_draw { return }
        writer(slice_chars(choice, idx, idx + 1), true);
        last_idx = idx + 1;
    }
    writer(slice_chars(choice, last_idx, chars_to_draw), false);
}

fn read_choices() -> Vec<String> {
    let stdin = stdin();
    let mut lines = Vec::new();

    let mut stdin = stdin.lock();
    let mut first_error = None;
    let mut suppressed = 0;
    loop {
        let mut s = String::new();
        match stdin.read_line(&mut s) {
            Ok(_) => {
                if s.is_empty() { break; }
                trim(&mut s);
                lines.push(s);
            },
            Err(e) => {
                if first_error.is_some() {
                    suppressed = suppressed + 1;
                } else {
                    first_error = Some(e);
                }
            }
        }
    }
    if first_error.is_some() {
        eprintln!("Warning: Failed to parse one or more lines (\"{}\"); {} additional error(s) suppressed", first_error.unwrap(), suppressed);
    }

    lines
}

pub fn trim(s: &mut String) {
    while let Some(x) = s.pop() {
        if x != '\n' && x != '\r' {
            s.push(x);
            return;
        }
    }
}

fn delete_last_word(s: &mut String) {
    let mut deleted_something = false;
    while let Some(x) = s.pop() {
        if x == ' ' {
            if deleted_something {
                s.push(x);
                return;
            }
        } else {
            deleted_something = true;
        }
    }
}

// This is technically a standard library function, but it's plastered with
// stability warnings and therefore only available on the nightly channel.
fn slice_chars(s: &str, begin: usize, end: usize) -> &str {
    assert!(begin <= end);
    let mut count = 0;
    let mut begin_byte = None;
    let mut end_byte = None;

    // This could be even more efficient by not decoding,
    // only finding the char boundaries
    for (idx, _) in s.char_indices() {
        if count == begin { begin_byte = Some(idx); }
        if count == end { end_byte = Some(idx); break; }
        count += 1;
    }
    if begin_byte.is_none() && count == begin { begin_byte = Some(s.len()) }
    if end_byte.is_none() && count == end { end_byte = Some(s.len()) }

    match (begin_byte, end_byte) {
        (None, _) => panic!("slice_chars: `begin` is beyond end of string"),
        (_, None) => panic!("slice_chars: `end` is beyond end of string"),
        (Some(a), Some(b)) => unsafe { s.get_unchecked(a..b) }
    }
}

#[cfg(test)]
mod tests {
    use super::{trim, delete_last_word};

    #[test]
    fn trim_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            trim(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("\n", "");
        should_become("\n\n", "");
        should_become("asdf", "asdf");
        should_become("asdf\n", "asdf");
        should_become("asdf\nasdf\n", "asdf\nasdf");
        should_become("asdf\r\n", "asdf");
    }

    #[test]
    fn delete_word_test() {
        fn should_become(before: &str, after: &str) {
            let mut x = before.to_string();
            delete_last_word(&mut x);
            assert_eq!(after.to_string(), x);
        }
        should_become("", "");
        should_become("a", "");
        should_become("asdf", "");
        should_become("asdf asdf asdf", "asdf asdf ");
        should_become("asdf asdf asdf ", "asdf asdf ");
        should_become("asdf asdf asdf  ", "asdf asdf ");
    }
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
        println!("Guess the number!");

        let secret_number = rand::thread_rng().gen_range(1, 101);

        println!("The secret number is: {}", secret_number);

        loop {
            println!("Please input your guess.");

            let mut guess = String::new();

            io::stdin().read_line(&mut guess)
                .ok()
                .expect("Failed to read line");

            let guess: u32 = guess.trim().parse()
                .ok()
                .expect("Please type a number!");

            println!("You guessed: {}", guess);

            match guess.cmp(&secret_number) {
                Ordering::Less      => println!("Too small!"),
                Ordering::Greater   => println!("Too big!"),
                Ordering::Equal     => {
                    println!("You win!");
                    break;
                }
            }
        }
}
<commit_msg>Continue after entering non-number as guess<commit_after>extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

fn main() {
        println!("Guess the number!");

        let secret_number = rand::thread_rng().gen_range(1, 101);

        println!("The secret number is: {}", secret_number);

        loop {
            println!("Please input your guess.");

            let mut guess = String::new();

            io::stdin().read_line(&mut guess)
                .ok()
                .expect("Failed to read line");

            let guess: u32 = match guess.trim().parse() {
                    Ok(num) => num,
                    Err(_)  => continue,
            };

            println!("You guessed: {}", guess);

            match guess.cmp(&secret_number) {
                Ordering::Less      => println!("Too small!"),
                Ordering::Greater   => println!("Too big!"),
                Ordering::Equal     => {
                    println!("You win!");
                    break;
                }
            }
        }
}
<|endoftext|>


<commit_before>// main.rs
// Copyright 2016 Alexander Altman
//
// 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.

extern crate konane;
use konane::{Game, Occupancy, Position};

#[macro_use]
extern crate error_chain;

extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{GlGraphics, OpenGL};

#[macro_use]
extern crate clap;

extern crate rand;
use rand::{Rng, StdRng};

const OPENGL_VERSIONS_STR: [&'static str; 12] = ["2.0", "2.1", "3.0", "3.1", "3.2", "3.3", "4.0", "4.1",
                                                 "4.2", "4.3", "4.4", "4.5"];
const OPENGL_VERSIONS_ENUM: [OpenGL; 12] = [OpenGL::V2_0,
                                            OpenGL::V2_1,
                                            OpenGL::V3_0,
                                            OpenGL::V3_1,
                                            OpenGL::V3_2,
                                            OpenGL::V3_3,
                                            OpenGL::V4_0,
                                            OpenGL::V4_1,
                                            OpenGL::V4_2,
                                            OpenGL::V4_3,
                                            OpenGL::V4_4,
                                            OpenGL::V4_5];
fn opengl_version_str_to_enum(value: &str) -> OpenGL {
  OPENGL_VERSIONS_ENUM[OPENGL_VERSIONS_STR.binary_search(&value).expect("impossible")]
}
fn opengl_version_enum_to_str(value: OpenGL) -> &'static str {
  OPENGL_VERSIONS_STR[OPENGL_VERSIONS_ENUM.binary_search(&value).expect("impossible")]
}
const OPENGL_VERSION_DEFAULT: OpenGL = OpenGL::V3_2;

fn main() {
  let matches = clap::App::new("kōnane")
    .version(crate_version!())
    .author("Alexander Ronald Altman <alexanderaltman@me.com>")
    .about("The ancient polynesian game of kōnane")
    .arg(clap::Arg::with_name("OpenGL version")
      .long("opengl")
      .short("g")
      .default_value(opengl_version_enum_to_str(OPENGL_VERSION_DEFAULT))
      .help("The version of OpenGL to use")
      .possible_values(&OPENGL_VERSIONS_STR))
    .setting(clap::AppSettings::ColoredHelp)
    .get_matches();
  let gl_version = opengl_version_str_to_enum(matches.value_of("OpenGL version").expect("impossible"));
  setup(matches, gl_version).expect("kōnane encountered an error");
}

mod errors {
  error_chain! {
    types {
      Error, ErrorKind, ChainErr, Result;
    }
    links {
      ::konane::errors::Error, ::konane::errors::ErrorKind, Game;
    }
    foreign_links {
      ::clap::Error, Clap, "clap error";
      ::std::io::Error, IO, "I/O error";
    }
    errors {
      OpenGL(inner: ::opengl_graphics::error::Error) {
        description("OpenGL graphics error")
        display("OpenGL graphics error: {}", inner)
      }
    }
  }

  impl From<::opengl_graphics::error::Error> for Error {
    fn from(inner: ::opengl_graphics::error::Error) -> Error { ErrorKind::OpenGL(inner).into() }
  }
}

struct Context<'a> {
  args: clap::ArgMatches<'a>,
  gl_version: OpenGL,
  window: &'a mut Window,
  gl: &'a mut GlGraphics,
  game: &'a mut Game,
  rng: &'a mut StdRng,
}

fn setup(matches: clap::ArgMatches, gl_version: OpenGL) -> errors::Result<()> {
  let rng = &mut try!(StdRng::new());
  let cxt = Context {
    args: matches,
    gl_version: gl_version,
    window: &mut try!(WindowSettings::new("kōnane", [1000, 1000])
      .opengl(gl_version)
      .exit_on_esc(true)
      .build()),
    gl: &mut GlGraphics::new(gl_version),
    game: &mut if rng.gen() { Game::new_white() } else { Game::new_black() },
    rng: rng,
  };
  run(cxt)
}

fn run(cxt: Context) -> errors::Result<()> {
  let mut events = cxt.window.events();
  while let Some(event) = events.next(cxt.window) {
    match event {
      Event::Render(arg) => (),
      Event::AfterRender(arg) => (),
      Event::Update(arg) => (),
      Event::Idle(arg) => (),
      Event::Input(arg) => (),
    }
  }
  Ok(())
}
<commit_msg>Basic renaming<commit_after>// main.rs
// Copyright 2016 Alexander Altman
//
// 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.

extern crate konane;
use konane::{Game, Occupancy, Position};

#[macro_use]
extern crate error_chain;

extern crate piston;
extern crate graphics;
extern crate glutin_window;
extern crate opengl_graphics;
use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use glutin_window::GlutinWindow as Window;
use opengl_graphics::{GlGraphics, OpenGL};

#[macro_use]
extern crate clap;

extern crate rand;
use rand::{Rng, StdRng};

const OPENGL_VERSIONS_STR: [&'static str; 12] = ["2.0", "2.1", "3.0", "3.1", "3.2", "3.3", "4.0", "4.1",
                                                 "4.2", "4.3", "4.4", "4.5"];
const OPENGL_VERSIONS_ENUM: [OpenGL; 12] = [OpenGL::V2_0,
                                            OpenGL::V2_1,
                                            OpenGL::V3_0,
                                            OpenGL::V3_1,
                                            OpenGL::V3_2,
                                            OpenGL::V3_3,
                                            OpenGL::V4_0,
                                            OpenGL::V4_1,
                                            OpenGL::V4_2,
                                            OpenGL::V4_3,
                                            OpenGL::V4_4,
                                            OpenGL::V4_5];
fn opengl_version_str_to_enum(value: &str) -> OpenGL {
  OPENGL_VERSIONS_ENUM[OPENGL_VERSIONS_STR.binary_search(&value).expect("impossible")]
}
fn opengl_version_enum_to_str(value: OpenGL) -> &'static str {
  OPENGL_VERSIONS_STR[OPENGL_VERSIONS_ENUM.binary_search(&value).expect("impossible")]
}
const OPENGL_VERSION_DEFAULT: OpenGL = OpenGL::V3_2;

fn main() {
  let matches = clap::App::new("kōnane")
    .version(crate_version!())
    .author("Alexander Ronald Altman <alexanderaltman@me.com>")
    .about("The ancient polynesian game of kōnane")
    .arg(clap::Arg::with_name("OpenGL version")
      .long("opengl")
      .short("g")
      .default_value(opengl_version_enum_to_str(OPENGL_VERSION_DEFAULT))
      .help("The version of OpenGL to use")
      .possible_values(&OPENGL_VERSIONS_STR))
    .setting(clap::AppSettings::ColoredHelp)
    .get_matches();
  let gl_version = opengl_version_str_to_enum(matches.value_of("OpenGL version").expect("impossible"));
  setup(matches, gl_version).expect("kōnane encountered an error");
}

mod errors {
  error_chain! {
    types {
      Error, ErrorKind, ChainErr, Result;
    }
    links {
      ::konane::errors::Error, ::konane::errors::ErrorKind, Game;
    }
    foreign_links {
      ::clap::Error, Clap, "clap error";
      ::std::io::Error, IO, "I/O error";
    }
    errors {
      OpenGL(inner: ::opengl_graphics::error::Error) {
        description("OpenGL graphics error")
        display("OpenGL graphics error: {}", inner)
      }
    }
  }

  impl From<::opengl_graphics::error::Error> for Error {
    fn from(inner: ::opengl_graphics::error::Error) -> Error { ErrorKind::OpenGL(inner).into() }
  }
}

struct Context<'a> {
  args: clap::ArgMatches<'a>,
  gl_version: OpenGL,
  window: &'a mut Window,
  gl: &'a mut GlGraphics,
  game: &'a mut Game,
  rng: &'a mut StdRng,
}

fn setup(matches: clap::ArgMatches, gl_version: OpenGL) -> errors::Result<()> {
  let rng = &mut try!(StdRng::new());
  let cxt = Context {
    args: matches,
    gl_version: gl_version,
    window: &mut try!(WindowSettings::new("kōnane", [1000, 1000])
      .opengl(gl_version)
      .exit_on_esc(true)
      .build()),
    gl: &mut GlGraphics::new(gl_version),
    game: &mut if rng.gen() { Game::new_white() } else { Game::new_black() },
    rng: rng,
  };
  run(cxt)
}

fn run(cxt: Context) -> errors::Result<()> {
  let mut events = cxt.window.events();
  while let Some(event) = events.next(cxt.window) {
    match event {
      Event::Render(params) => (),
      Event::AfterRender(params) => (),
      Event::Update(params) => (),
      Event::Idle(params) => (),
      Event::Input(params) => (),
    }
  }
  Ok(())
}
<|endoftext|>


<commit_before>#![feature(phase)]
#[phase(plugin, link)] extern crate log;

const U4_LOW:  u8 = 0b00001111;
const U4_HIGH: u8 = 0b11110000;

enum CpuState {
	Continue,
	Halt,
}

/// The P150 virtual machine
struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	/// Initializes the P150 CPU
	///
	/// NOTE: This implementation 0s memory; but this is not guaranteed
	/// by the machine specification.
	///
	/// Programs must start at memory address 0x00
	fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	/// Prints the current machine state to the console window
	/// This includes the IP, IR, and all registers.
	/// (Registers will be formatted as 2s complement numbers.)
	fn dump(&self) {
		println!("IP: 0x{:02X}, IR: 0x{:04X}", self.ip, self.ir);

		println!("Registers")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{}: {}", addr, cell)
		}
	}

	/// Read an array of instructions into memory
	/// This reads two bytes at a time from the `memory` array
	/// and loads them into the P150s RAM bank, starting from address 0.
	fn init_mem(&mut self, memory: &[u16]) {
		let mut next_cell = 0x00;

		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	/// Runs the entire fetch, execute, decode cycle against the current IP
	fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // ADDB
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);   // first input: lower nibble of first byte
				let rloc_i1 = h_nibble(self.ir as u8);          // second input: upper nibble of second byte
				let rloc_o0 = l_nibble(self.ir as u8);          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] + self.reg[rloc_i1 as uint];
				Continue
			},

			0x3   => { // AND
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_i1 = h_nibble(self.ir as u8);
				let rloc_o0 = l_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] & self.reg[rloc_i1 as uint];
				Continue
			},

			0x4   => { // OR
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_i1 = h_nibble(self.ir as u8);
				let rloc_o0 = l_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] | self.reg[rloc_i1 as uint];
				Continue
			},

			0x5   => { // XOR
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_i1 = h_nibble(self.ir as u8);
				let rloc_o0 = l_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] ^ self.reg[rloc_i1 as uint];
				Continue
			},

			0x6   => { // MLOAD
				let rloc_o0 = l_nibble((self.ir >> 8) as u8);
				let mloc_i0 = self.ir as u8;

				self.reg[rloc_o0 as uint] = self.mem[mloc_i0 as uint];
				Continue
			},

			0x7   => { // MSTOR
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let mloc_o0 = self.ir as u8;

				self.mem[mloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x8   => { // RMOV
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_o0 = h_nibble(self.ir as u8);

				debug!("moving from {:02X} to {:02X}", rloc_i0, rloc_o0)
				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x9   => { // RSET
				let rloc = ((self.ir >> 8) as u8) & U4_LOW;  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte

				self.reg[rloc as uint] = rval;               // store value in register
				Continue
			},

			0xA   => { // JMPEQ
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let next_ip = self.ir as u8;

				if self.reg[rloc_i0 as uint] == self.reg[0] { self.ip = next_ip }
				Continue
			},

			0xB   => { Halt },
			_     => { debug!("halt, cpu on fire: {}", op); Halt },
		}
	}

	/// Load the instruction at `IP` and advance the pointer by two bytes.
	/// The instruction is packed into a single `u16` and stored in the instruction register.
	fn fetch(&mut self) {
		// load PC -> IR
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16);
		self.ip += 2;

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

/// Take the lower nibble of a byte
fn l_nibble(byte: u8) -> u8 {
	(byte & U4_LOW)
}

/// Take the upper nibble of a byte and shift it
/// towards the least significant bits.
fn h_nibble(byte: u8) -> u8 {
	(byte & U4_HIGH) >> 4
}

fn main() {
	let mut cpu = P150Cpu::new();
	let program = [0x902A, 0x911E, 0x920C, 0x0123, 0x8310, 0xA106, 0xB000];
	cpu.init_mem(program);

	loop {
		match cpu.tick() {
			Continue => { continue; },
			Halt => { println!("CPU halted."); cpu.dump(); break; },
		}
	}
}

<commit_msg>(Remove unnecessary whitespace.)<commit_after>#![feature(phase)]
#[phase(plugin, link)] extern crate log;

const U4_LOW:  u8 = 0b00001111;
const U4_HIGH: u8 = 0b11110000;

enum CpuState {
	Continue,
	Halt,
}

/// The P150 virtual machine
struct P150Cpu {
	ip:  u8,
	ir: u16,

	reg: [u8, ..16],
	mem: [u8, ..256],
}

impl P150Cpu {
	/// Initializes the P150 CPU
	///
	/// NOTE: This implementation 0s memory; but this is not guaranteed
	/// by the machine specification.
	///
	/// Programs must start at memory address 0x00
	fn new() -> P150Cpu {
		P150Cpu {
			ip:  0x00,
			ir:  0x0000,

			reg: [0u8, ..16],
			mem: [0u8, ..256],
		}
	}

	/// Prints the current machine state to the console window
	/// This includes the IP, IR, and all registers.
	/// (Registers will be formatted as 2s complement numbers.)
	fn dump(&self) {
		println!("IP: 0x{:02X}, IR: 0x{:04X}", self.ip, self.ir);

		println!("Registers")
		for (addr, cell) in self.reg.iter().enumerate() {
			println!("{}: {}", addr, cell)
		}
	}

	/// Read an array of instructions into memory
	/// This reads two bytes at a time from the `memory` array
	/// and loads them into the P150s RAM bank, starting from address 0.
	fn init_mem(&mut self, memory: &[u16]) {
		let mut next_cell = 0x00;

		for op in memory.iter() {
			let byte_1 = (*op >> 8) as u8;
			let byte_2 = *op as u8;

			self.mem[next_cell]     = byte_1;
			self.mem[next_cell + 1] = byte_2;
			next_cell += 2
		}
	}

	/// Runs the entire fetch, execute, decode cycle against the current IP
	fn tick(&mut self) -> CpuState {
		self.fetch();

		// decode
		let op = (self.ir >> 12) as u8;
		match op {
			0x0   => { // ADDB
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);   // first input: lower nibble of first byte
				let rloc_i1 = h_nibble(self.ir as u8);          // second input: upper nibble of second byte
				let rloc_o0 = l_nibble(self.ir as u8);          // output: lower nibble of second byte

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] + self.reg[rloc_i1 as uint];
				Continue
			},

			0x3   => { // AND
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_i1 = h_nibble(self.ir as u8);
				let rloc_o0 = l_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] & self.reg[rloc_i1 as uint];
				Continue
			},

			0x4   => { // OR
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_i1 = h_nibble(self.ir as u8);
				let rloc_o0 = l_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] | self.reg[rloc_i1 as uint];
				Continue
			},

			0x5   => { // XOR
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_i1 = h_nibble(self.ir as u8);
				let rloc_o0 = l_nibble(self.ir as u8);

				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint] ^ self.reg[rloc_i1 as uint];
				Continue
			},

			0x6   => { // MLOAD
				let rloc_o0 = l_nibble((self.ir >> 8) as u8);
				let mloc_i0 = self.ir as u8;

				self.reg[rloc_o0 as uint] = self.mem[mloc_i0 as uint];
				Continue
			},

			0x7   => { // MSTOR
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let mloc_o0 = self.ir as u8;

				self.mem[mloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x8   => { // RMOV
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let rloc_o0 = h_nibble(self.ir as u8);

				debug!("moving from {:02X} to {:02X}", rloc_i0, rloc_o0)
				self.reg[rloc_o0 as uint] = self.reg[rloc_i0 as uint];
				Continue
			},

			0x9   => { // RSET
				let rloc = ((self.ir >> 8) as u8) & U4_LOW;  // lower nibble of first byte
				let rval = self.ir as u8;                    // value is entire second byte

				self.reg[rloc as uint] = rval;               // store value in register
				Continue
			},

			0xA   => { // JMPEQ
				let rloc_i0 = l_nibble((self.ir >> 8) as u8);
				let next_ip = self.ir as u8;

				if self.reg[rloc_i0 as uint] == self.reg[0] { self.ip = next_ip }
				Continue
			},

			0xB   => { Halt },
			_     => { debug!("halt, cpu on fire: {}", op); Halt },
		}
	}

	/// Load the instruction at `IP` and advance the pointer by two bytes.
	/// The instruction is packed into a single `u16` and stored in the instruction register.
	fn fetch(&mut self) {
		// load PC -> IR
		let byte_1 = self.mem[(self.ip+0) as uint];
		let byte_2 = self.mem[(self.ip+1) as uint];

		self.ir  = (byte_1 as u16 << 8) | (byte_2 as u16);
		self.ip += 2;

		debug!("IR set to 0x{:04X} ({:02X},{:02X})", self.ir, byte_1, byte_2)
	}
}

/// Take the lower nibble of a byte
fn l_nibble(byte: u8) -> u8 {
	(byte & U4_LOW)
}

/// Take the upper nibble of a byte and shift it
/// towards the least significant bits.
fn h_nibble(byte: u8) -> u8 {
	(byte & U4_HIGH) >> 4
}

fn main() {
	let mut cpu = P150Cpu::new();
	let program = [0x902A, 0x911E, 0x920C, 0x0123, 0x8310, 0xA106, 0xB000];
	cpu.init_mem(program);

	loop {
		match cpu.tick() {
			Continue => { continue; },
			Halt => { println!("CPU halted."); cpu.dump(); break; },
		}
	}
}

<|endoftext|>


<commit_before>#![feature(os, io, fs, path, old_path, core, std_misc, box_syntax, collections)]
#![forbid(unused_typecasts)]
// #![allow(dead_code)]
// #![allow(unused_variables)]
// #![allow(unused_imports)]

extern crate rand;
extern crate toml;
extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;
extern crate window;
extern crate freetype;
extern crate "rustc-serialize" as rustc_serialize;

mod util;
mod config;
mod sprite;
mod spritesheet;
mod dungeon;
mod cell;
mod celloption;
mod genotype;
mod statistics;
mod mu_lambda;
mod evaluation;
mod random_seed;
mod list_of_walls;
mod wall_patterns;
mod text;
mod phenotype;

use opengl_graphics::{Gl};
use graphics::{color};
use sdl2_window::{Sdl2Window};
use window::{WindowSettings};
use input::Button::{Keyboard};
use input::keyboard::{Key};
//use event::{RenderEvent, Event};
use event::*;

use std::os::{num_cpus};
use std::cell::{RefCell};
use std::path::{Path};
use std::old_path::Path as OldPath;

use celloption::{CellOptions, CellOption, Tile, Item, Occupant};
use spritesheet::{SpriteSheet};
use sprite::{Sprite};
use dungeon::{DungeonCells};
use config::{Config};
use genotype::{Genotype};
use random_seed::{RandomSeed};
use list_of_walls::{ListOfWalls};
use wall_patterns::{WallPatterns};
use mu_lambda::{MuLambda};
use evaluation::{EvaluationFn, check_1x1_rooms, has_entrance_exit, doors_are_useful, rooms_are_accessible};
use text::{render_text};
use phenotype::{Seed};

const TOML_CONFIG: &'static str = "src/config.toml";

fn main() {

    let config_path = Path::new(TOML_CONFIG);
    let config = Config::new(config_path);
    let vars = config.get_table(None, "main");
    let window_width = config.get_default(vars, "window_width", 800);
    let window_height = config.get_default(vars, "window_height", 800);
    let tile_width = config.get_integer(vars, "tile_width") as i32;
    let tile_height = config.get_integer(vars, "tile_height") as i32;
    let tiles_width = config.get_default(vars, "tiles_width", 50);
    let tiles_height = config.get_default(vars, "tiles_height", 50);
    let threads = config.get_default(vars, "threads", num_cpus() * 2);
    let font_name = config.get_string(vars, "font");
    let font_size = config.get_default(vars, "font_size", 14);

    let opengl = shader_version::OpenGL::_3_2;
    let window = Sdl2Window::new(opengl,
                                 WindowSettings {
                                     title: "PCG".to_string(),
                                     size: [window_width, window_height],
                                     fullscreen: false,
                                     exit_on_esc: true,
                                     samples: 0,
                                 });
    let ref mut gl = Gl::new(opengl);

    let ft = freetype::Library::init().unwrap();
    let font = OldPath::new(font_name);
    let mut face = ft.new_face(&font, 0).unwrap();
    face.set_pixel_sizes(0, font_size).unwrap();

    let spritesheet_name = config.get_string(vars, "spritesheet");
    let spritesheets = config.get_table(None, "spritesheets");
    let spritesheet_config = config.get_table(Some(spritesheets), spritesheet_name);
    let spritesheet_location = config.get_string(spritesheet_config, "path");

    let cell_data = config.get_table(Some(spritesheet_config), "cells");
    let tiles: Vec<String> = config.get_array(cell_data, "tiles");
    let items: Vec<String> = config.get_array(cell_data, "items");
    let occupants: Vec<String> = config.get_array(cell_data, "occupants");
    let cell_tiles: CellOptions<Tile> = CellOptions::new(tiles.as_slice());
    let cell_items: CellOptions<Item> = CellOptions::new(items.as_slice());
    let cell_occupants: CellOptions<Occupant> = CellOptions::new(occupants.as_slice());
    let occupant_chance = config.get_float(spritesheet_config, "occupant_chance");

    let mulambda_vars = config.get_table(None, "mu-lambda");
    let mu = config.get_default(mulambda_vars, "mu", 100);
    let lambda = config.get_default(mulambda_vars, "lambda", 100);
    let mutation = config.get_default(mulambda_vars, "mutation", 0.33);
    let iterations = config.get_default(mulambda_vars, "iterations", 100);
    let strategy = config.get_string(mulambda_vars, "strategy");
    let evaluations: Vec<String> = config.get_array(mulambda_vars, "evaluations");
    let evaluation_fns: Vec<EvaluationFn> = evaluations.iter().map(|eval| {
        match eval.as_slice() {
            "check_1x1_rooms" => box check_1x1_rooms as EvaluationFn,
            "has_entrance_exit" => box has_entrance_exit as EvaluationFn,
            "doors_are_useful" => box doors_are_useful as EvaluationFn,
            "rooms_are_accessible" => box rooms_are_accessible as EvaluationFn,
            _ => panic!("Evaluation function {} could not be found.", eval)
        }
    }).collect();
    let evaluation_weights: Vec<f64> = config.get_array(mulambda_vars, "evaluation_weights");

    let seed = Seed::new(tiles_width, tiles_height, cell_tiles, cell_items, cell_occupants, occupant_chance);
    // We cannot have trait objects that implement Clone. So this is commented out for now.
    let genotype = match strategy {
        // "RandomSeed" => {
        //     box RandomSeed::new(&seed)
        // }
        "ListOfWalls" => {
            box ListOfWalls::new(&config, &seed)
        }
        // "WallPatterns" => {
        //     box WallPatterns::new(&config, &seed)
        // }
        _ => panic!("Strategy {} could not be found.", strategy)
    };

    let mut mulambda = MuLambda::new(threads,
                                     iterations,
                                     mu,
                                     lambda,
                                     mutation,
                                     *genotype.clone(),
                                     evaluation_fns,
                                     evaluation_weights);
    let winners = mulambda.run();

    let spritesheet_path = Path::new(spritesheet_location);
    let spritesheet = SpriteSheet::new(&spritesheet_path);

    let mut choice = 0;
    let window = RefCell::new(window);
    for e in event::events(&window) {
        graphics::clear(color::BLACK, gl);
        let ref current = winners[choice as usize];
        let &(ref individual, ref statistic) = current;
        let dungeon = individual.generate();
        e.render(|_| {
            let dc = DungeonCells::new(&dungeon);
            for cell in dc {
                let x = cell.x as i32 * tile_width;
                let y = cell.y as i32 * tile_height;
                match cell.tile {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y);
                    }
                    None => {
                         Sprite::missing(gl, x, y, tile_width, tile_height);
                    }
                }
                match cell.occupant {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y);
                    }
                    None => ()
                }
            }
            let info = format!("Dungeon no. #{} (born on iteration {}, ranking {})",
                               choice,
                               statistic.iteration,
                               statistic.fitness);
            render_text(&mut face, gl, 10, 10, info.as_slice());
        });

        if let Some(Keyboard(key)) = e.press_args() {
            if key == Key::Left {
                choice -= 1;
                if choice < 0 {
                    choice = (winners.len() - 1) as isize;
                }
            }
            else if key == Key::Right {
                choice += 1;
                choice %= winners.len() as isize;
            }
        };
    }
}
<commit_msg>Allow switching of traits at run time.<commit_after>#![feature(os, io, fs, path, old_path, core, std_misc, box_syntax, collections)]
#![forbid(unused_typecasts)]
// #![allow(dead_code)]
// #![allow(unused_variables)]
// #![allow(unused_imports)]

extern crate rand;
extern crate toml;
extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate opengl_graphics;
extern crate window;
extern crate freetype;
extern crate "rustc-serialize" as rustc_serialize;

mod util;
mod config;
mod sprite;
mod spritesheet;
mod dungeon;
mod cell;
mod celloption;
mod genotype;
mod statistics;
mod mu_lambda;
mod evaluation;
mod random_seed;
mod list_of_walls;
mod wall_patterns;
mod text;
mod phenotype;

use opengl_graphics::{Gl};
use graphics::{color};
use sdl2_window::{Sdl2Window};
use window::{WindowSettings};
use input::Button::{Keyboard};
use input::keyboard::{Key};
//use event::{RenderEvent, Event};
use event::*;

use std::os::{num_cpus};
use std::cell::{RefCell};
use std::path::{Path};
use std::old_path::Path as OldPath;

use celloption::{CellOptions, CellOption, Tile, Item, Occupant};
use spritesheet::{SpriteSheet};
use sprite::{Sprite};
use dungeon::{Dungeon, DungeonCells};
use config::{Config};
use genotype::{Genotype};
use random_seed::{RandomSeed};
use list_of_walls::{ListOfWalls};
use wall_patterns::{WallPatterns};
use mu_lambda::{MuLambda};
use evaluation::{EvaluationFn, check_1x1_rooms, has_entrance_exit, doors_are_useful, rooms_are_accessible};
use text::{render_text};
use phenotype::{Seed};
use statistics::{Statistic};

const TOML_CONFIG: &'static str = "src/config.toml";

fn main() {

    let config_path = Path::new(TOML_CONFIG);
    let config = Config::new(config_path);
    let vars = config.get_table(None, "main");
    let window_width = config.get_default(vars, "window_width", 800);
    let window_height = config.get_default(vars, "window_height", 800);
    let tile_width = config.get_integer(vars, "tile_width") as i32;
    let tile_height = config.get_integer(vars, "tile_height") as i32;
    let tiles_width = config.get_default(vars, "tiles_width", 50);
    let tiles_height = config.get_default(vars, "tiles_height", 50);
    let threads = config.get_default(vars, "threads", num_cpus() * 2);
    let font_name = config.get_string(vars, "font");
    let font_size = config.get_default(vars, "font_size", 14);

    let opengl = shader_version::OpenGL::_3_2;
    let window = Sdl2Window::new(opengl,
                                 WindowSettings {
                                     title: "PCG".to_string(),
                                     size: [window_width, window_height],
                                     fullscreen: false,
                                     exit_on_esc: true,
                                     samples: 0,
                                 });
    let ref mut gl = Gl::new(opengl);

    let ft = freetype::Library::init().unwrap();
    let font = OldPath::new(font_name);
    let mut face = ft.new_face(&font, 0).unwrap();
    face.set_pixel_sizes(0, font_size).unwrap();

    let spritesheet_name = config.get_string(vars, "spritesheet");
    let spritesheets = config.get_table(None, "spritesheets");
    let spritesheet_config = config.get_table(Some(spritesheets), spritesheet_name);
    let spritesheet_location = config.get_string(spritesheet_config, "path");

    let cell_data = config.get_table(Some(spritesheet_config), "cells");
    let tiles: Vec<String> = config.get_array(cell_data, "tiles");
    let items: Vec<String> = config.get_array(cell_data, "items");
    let occupants: Vec<String> = config.get_array(cell_data, "occupants");
    let cell_tiles: CellOptions<Tile> = CellOptions::new(tiles.as_slice());
    let cell_items: CellOptions<Item> = CellOptions::new(items.as_slice());
    let cell_occupants: CellOptions<Occupant> = CellOptions::new(occupants.as_slice());
    let occupant_chance = config.get_float(spritesheet_config, "occupant_chance");

    let mulambda_vars = config.get_table(None, "mu-lambda");
    let mu = config.get_default(mulambda_vars, "mu", 100);
    let lambda = config.get_default(mulambda_vars, "lambda", 100);
    let mutation = config.get_default(mulambda_vars, "mutation", 0.33);
    let iterations = config.get_default(mulambda_vars, "iterations", 100);
    let strategy = config.get_string(mulambda_vars, "strategy");
    let evaluations: Vec<String> = config.get_array(mulambda_vars, "evaluations");
    let evaluation_fns: Vec<EvaluationFn> = evaluations.iter().map(|eval| {
        match eval.as_slice() {
            "check_1x1_rooms" => box check_1x1_rooms as EvaluationFn,
            "has_entrance_exit" => box has_entrance_exit as EvaluationFn,
            "doors_are_useful" => box doors_are_useful as EvaluationFn,
            "rooms_are_accessible" => box rooms_are_accessible as EvaluationFn,
            _ => panic!("Evaluation function {} could not be found.", eval)
        }
    }).collect();
    let evaluation_weights: Vec<f64> = config.get_array(mulambda_vars, "evaluation_weights");

    let seed = Seed::new(tiles_width, tiles_height, cell_tiles, cell_items, cell_occupants, occupant_chance);

    // We cannot have trait objects that implement Clone or use
    // generic parameters. Instead, we use macros to make this section
    // a bit cleaner.
    macro_rules! mu_lambda_run (
        ($genotype:expr) => {{
            let mut mulambda = MuLambda::new(threads,
                                             iterations,
                                             mu,
                                             lambda,
                                             mutation,
                                             $genotype.clone(),
                                             evaluation_fns,
                                             evaluation_weights);
            let result = mulambda.run();
            result.into_iter().map(|(individual, statistic)| (individual.generate(), statistic)).collect()
        }}
    );
    let winners: Vec<(Dungeon, Statistic)> = match strategy {
        "RandomSeed" => {
            let genotype = RandomSeed::new(&seed);
            mu_lambda_run!(genotype)
        }
        "ListOfWalls" => {
            let genotype = ListOfWalls::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        "WallPatterns" => {
            let genotype = WallPatterns::new(&config, &seed);
            mu_lambda_run!(genotype)
        }
        _ => panic!("Strategy {} could not be found.", strategy)
    };

    let spritesheet_path = Path::new(spritesheet_location);
    let spritesheet = SpriteSheet::new(&spritesheet_path);

    let mut choice = 0;
    let window = RefCell::new(window);
    for e in event::events(&window) {
        graphics::clear(color::BLACK, gl);
        let ref current = winners[choice as usize];
        let &(ref dungeon, ref statistic) = current;
        e.render(|_| {
            let dc = DungeonCells::new(&dungeon);
            for cell in dc {
                let x = cell.x as i32 * tile_width;
                let y = cell.y as i32 * tile_height;
                match cell.tile {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y);
                    }
                    None => {
                         Sprite::missing(gl, x, y, tile_width, tile_height);
                    }
                }
                match cell.occupant {
                    Some(ref val) => {
                        let sprite = spritesheet.sprites.get(&val.name()).unwrap();
                        sprite.draw(gl, x, y);
                    }
                    None => ()
                }
            }
            let info = format!("Dungeon no. #{} (born on iteration {}, ranking {})",
                               choice,
                               statistic.iteration,
                               statistic.fitness);
            render_text(&mut face, gl, 10, 10, info.as_slice());
        });

        if let Some(Keyboard(key)) = e.press_args() {
            if key == Key::Left {
                choice -= 1;
                if choice < 0 {
                    choice = (winners.len() - 1) as isize;
                }
            }
            else if key == Key::Right {
                choice += 1;
                choice %= winners.len() as isize;
            }
        };
    }
}
<|endoftext|>


<commit_before>
#![feature(globs)]

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

use opengl_graphics::{
    Gl,
    Texture,
};
use sdl2_game_window::WindowSDL2;
use piston::{
    AssetStore,
    EventIterator,
    EventSettings,
    WindowSettings,
    Render,
};
use piston::graphics::*;

fn main() {
    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let mut window = WindowSDL2::new(
        opengl,
        WindowSettings {
            title: "Image".to_string(),
            size: [800,480],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let asset_store = AssetStore::from_folder("../bin/assets");

    let image = asset_store.path("rust-logo.png").unwrap();
    let image = Texture::from_path(&image).unwrap();
    let event_settings = EventSettings {
            updates_per_second: 120,
            max_frames_per_second: 60,
        };
    let ref mut gl = Gl::new(opengl);
    for e in EventIterator::new(&mut window, &event_settings) {
        match e {
            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(1.0, 1.0, 1.0).draw(gl);
                    c.image(&image).draw(gl);
            },
            _ => {},
        }
    }
}

<commit_msg>Playing with game loop<commit_after>#![feature(globs)]

// Load external crates provided via cargo.
extern crate graphics;
extern crate piston;
extern crate sdl2_game_window;
extern crate opengl_graphics;

// Texture is used for images; Gl for accessing OpenGL
use opengl_graphics::{
    Gl,
    Texture,
};

// For creating a window
use sdl2_game_window::WindowSDL2;

use piston::{
    AssetStore,                     // Managing assets
    EventIterator,                  // Used for the game loop
    EventSettings,                  // Struct used for setting and updates
    WindowSettings,                 // Struct defines window config
    Render,                         // Called each iteration of the game loop
};

use piston::graphics::*;

// Game Constants
pub static WIN_HEIGHT: int = 480;
pub static WIN_WIDTH: int = 800;

fn run( config: GameConfig ) {

    // Values for Window Creation
    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let window_settings = WindowSettings {
            title: "Centipede-RS".to_string(),
            size: [config.window_width, config.window_height],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        };

    // Create SDL Window
    let mut window = WindowSDL2::new(
        opengl,
        window_settings
    );

    // Create Asset Store
    let asset_store = AssetStore::from_folder("../bin/assets");

    // Load Logo from Asset Store
    let image = asset_store.path("rust-logo.png").unwrap();
    let image = Texture::from_path(&image).unwrap();

    // Create Settings for Game loop
    let event_settings = EventSettings {
            updates_per_second: config.updates_per_second,
            max_frames_per_second: config.max_frames_per_second,
        };

    // Create new OpenGL Handle
    let ref mut gl = Gl::new(opengl);

    let mut yellow = 0.0;

    // For each e in Event Iterator (whose range is 0 to infinity)
    // e becomes a new Event by passing our window and event settings
    for e in EventIterator::new(&mut window, &event_settings) {

        // If e is Render(args) do something, else return ()?
        match e {
            Render(args) => {

                yellow = yellow + 0.001;

                // Creates viewport at 0,0 with width and height of window.
                gl.viewport(0, 0, args.width as i32, args.height as i32);

                // graphics::context a new drawing context (think html5)
                let c = Context::abs(args.width as f64, args.height as f64);

                // I'm guessing this draws white across the entire window
                c.rgb(1.0, 1.0, 1.0).draw(gl);

                let num_cols = config.window_width as int / config.tile_size as int;

                let num_rows = config.window_height as int / config.tile_size as int;

                let mut green = 0.0;

                // Draw a square
                for row in range(0i, num_rows ) {

                    let mut red = 0.0;

                    green = green + 0.02;

                    let row_shift: f64 = row as f64 * config.tile_size as f64;

                    for col in range(0i, num_cols ) {

                        let col_shift: f64 = col as f64 * config.tile_size as f64;

                        red = red + 0.02;

                        c.square(
                            col_shift,
                            row_shift,
                            config.tile_size as f64
                        ).rgb(red, green, yellow).draw(gl);

                    }

                }

                // Draws the texture we loaded previously in the screen.
                // Next question: how do I draw this somewhere else?
                //c.image(&image).draw(gl);
            },
            _ => {},
        }
    }

}

struct GameConfig {
    window_height: u32,
    window_width: u32,
    updates_per_second: u64,
    max_frames_per_second: u64,
    tile_size: uint
}

fn main() {

    let config = GameConfig {
            window_height: 480,
            window_width: 800,
            updates_per_second: 120,
            max_frames_per_second: 60,
            tile_size: 32,
        };

    run( config );

}

<|endoftext|>


<commit_before>#![allow(unused_variables, unused_imports)]

#[macro_use]
extern crate ecs;
use ecs::*;

extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate window;
extern crate opengl_graphics;
extern crate quack;

use window::WindowSettings;

use std::collections::HashMap;
use std::default::Default;
use std::rand::Rng;
use event::{Event, ReleaseEvent, UpdateEvent, PressEvent, RenderEvent};
use quack::Set;

use opengl_graphics::{
    Gl,
};
use sdl2_window::Sdl2Window;

static WINDOW_W: f64 = 800.0;
static WINDOW_H: f64 = 600.0;
static WINDOW_PADDING: i32 = 20;

//fn draw_system(event: &Event,
//              gl: &mut Gl,
//              positions: &mut Components<Position>,
//              shapes: &mut Components<Shape>,
//              colors: &mut Components<Color>) {
//    use graphics::*;
//    if let Some(args) = event.update_args() {
//        let w = args.width as f64;
//        let h = args.height as f64;
//
//        let pad = WINDOW_PADDING;
//        gl.viewport(pad, pad, w as i32 - 2 * pad, h as i32 - 2 * pad);
//
//        gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
//            graphics::clear([0.2, 0.2, 0.0, 1.0], gl);
//            let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
//            r.draw([0.0, 0.0, WINDOW_W, WINDOW_H], &c, gl);
//        });
//
////        c.rgb(0.7, 0.7, 0.7).rect(0.0, 0.0, WINDOW_W, WINDOW_H).border_radius(1.0).draw(gl);
////
////        for (eid, pos) in positions.iter_mut() {
////          let mut shape = Point;
////          let mut border = None;
////          if shapes.contains_key(eid) {
////            shape = shapes.get_mut(eid).varient;
////            border = shapes.get_mut(eid).border;
////          }
////          let (r, g, b) = if colors.contains_key(eid) {
////              (colors.get_mut(eid).r, colors.get_mut(eid).g, colors.get_mut(eid).b)
////          } else {
////              (1.0, 1.0, 1.0)
////          };
////          let drawing = c.rgb(r, g, b);
////          match (shape, border) {
////              (Point, None)    => drawing.rect(1.0, 1.0, w, h).draw(gl),
////              (Point, Some(b)) => drawing.rect(1.0, 1.0, w, h).border_radius(b).draw(gl),
////
////              (Circle(rad), None)    => drawing.ellipse(pos.x, pos.y, rad, rad).draw(gl),
////              (Circle(rad), Some(b)) => drawing.ellipse(pos.x, pos.y, rad, rad).border_radius(b).draw(gl),
////
////              (Square(w,h), None)    => drawing.rect(pos.x, pos.y, w, h).draw(gl),
////              (Square(w,h), Some(b)) => drawing.rect(pos.x, pos.y, w, h).border_radius(b).draw(gl),
////          };
////        }
//    }
//}

//fn shimmer_system(shimmers: &mut Components<Shimmer>,
//                 colors: &mut Components<Color>) {
//    for (eid, _) in shimmers.iter_mut() {
//        if !colors.contains_key(eid) {
//            continue;
//        }
//        let color = colors.get_mut(eid);
//        let ref mut rng = rand::thread_rng();
//        color.r = rng.gen_range(0.5, 1.0);
//        color.g = rng.gen_range(0.5, 1.0);
//        color.b = rng.gen_range(0.5, 1.0);
//    }
//}
//
//fn move_system(event: &Event,
//               to_delete: &mut Vec<u32>,
//              positions: &mut Components<Position>,
//              shapes: &mut Components<Shape>,
//              clamps: &mut Components<WindowClamp>,
//              velocities: &mut Components<Velocity>) {
//    if let Some(args) = event.update_args {
//        let dt = args.dt;
////
////        for (eid, position) in positions.iter_mut() {
////            if !velocities.contains_key(eid) {
////                continue;
////            }
////
////            // If we have both a position and a velocity, integrate.
////            let velocity = velocities.get_mut(eid);
////            position.x += velocity.x * dt;
////            position.y += velocity.y * dt;
////
////            if !clamps.contains_key(eid) {
////              continue;
////            }
////            let (w, h) = match shapes.find(eid) {
////                Some(&s) =>
////                  match s.varient {
////                    Circle(r) => (r, r),
////                    Square(w,h) => (w, h),
////                    Point => (0.0, 0.0)
////                  },
////                None => (0.0, 0.0)
////            };
////
////            let clamp = clamps.get_mut(eid);
////            let velocity_mult = match clamp.varient {
////              Bounce => -1.0,
////              Stop => 0.0,
////              _ => 1.0
////            };
////            match clamp.varient {
////              Bounce | Stop => {
////                if position.x + w > WINDOW_W {
////                  position.x = WINDOW_W - w;
////                  velocity.x *= velocity_mult;
////                } else if position.x < 0.0 {
////                  position.x = 0.0;
////                  velocity.x *= velocity_mult;
////                }
////                if position.y + h > WINDOW_H {
////                  position.y = WINDOW_H - h;
////                  velocity.y *= velocity_mult;
////                } else if position.y < 0.0 {
////                  position.y = 0.0;
////                  velocity.y *= velocity_mult;
////                }
////              },
////              Remove => {
////                if position.x > WINDOW_W
////                || position.x + w < 0.0 {
////                  to_delete.push(*eid);
////                }
////                if position.y > WINDOW_H
////                || position.y + h < 0.0 {
////                  to_delete.push(*eid);
////                }
////              }
////            }
////        }
//    }
//}
//
//fn control_system(event: &Event,
//              controllers: &mut Components<PlayerController>,
//              velocities: &mut Components<Velocity>) {
//
//    const PADDLE_V: f64 = 800.0;
//
////    for (eid, controller) in controllers.iter_mut() {
////        event.press(|button| {
////            if button == Keyboard(controller.up) {
////                velocities.get_mut(eid).y = -PADDLE_V;
////            } else if button == Keyboard(controller.down) {
////                velocities.get_mut(eid).y = PADDLE_V;
////            }
////        });
////        event.release(|button| {
////            if button == Keyboard(controller.up)
////            || button == Keyboard(controller.down) {
////                velocities.get_mut(eid).y = 0.0;
////            }
////        });
////    }
//}

#[derive(Clone, PartialEq, Debug)]
pub enum ClampVarient {
    Bounce,
    Stop,
    Remove // Acts when item leaves window.
}

#[derive(Clone, PartialEq, Debug)]
pub struct WindowClamp {
    varient: ClampVarient
}

#[derive(Clone, PartialEq, Debug)]
pub struct PlayerController {
    up: input::Button,
    down: input::Button
}

#[derive(Clone, PartialEq, Debug)]
pub struct Position {
    x: f64,
    y: f64
}

#[derive(Clone, PartialEq, Debug)]
pub struct Shimmer;

#[derive(Clone, PartialEq, Debug)]
pub struct Color {
    r: f32,
    g: f32,
    b: f32
}

#[derive(Clone, PartialEq, Debug)]
pub enum ShapeVarient {
    Point,
    Circle(f64), // radius
    Square(f64, f64), // width, height
}

impl Default for ShapeVarient {
    fn default() -> ShapeVarient { ShapeVarient::Point }
}

#[derive(Clone, PartialEq, Debug)]
pub struct Shape {
    varient: ShapeVarient,
    border: Option<f64>
}

#[derive(Clone, PartialEq, Debug)]
pub struct Velocity {
    x: f64,
    y: f64
}

components! {
    Components {
        #[hot] position: Position,
        #[hot] shape: Shape,
        #[hot] velocity: Velocity,
        #[hot] color: Color,
        #[hot] shimmer: Shimmer,
        #[hot] player_controller: PlayerController,
        #[hot] window_clamp: WindowClamp
    }
}

systems! {
    Systems<Components>;
}

fn make_ball(world: &mut World<Components, Systems>) {
    const BALL_R: f64 = 20.0;
    let x = (WINDOW_W - BALL_R) / 2.0;
    let y = (WINDOW_H - BALL_R) / 2.0;

    let entity = world.create_entity(Box::new(
        |entity: BuildData, data: &mut Components| {
        data.position.add(&entity,
            Position{
                x: x,
                y: y
            });
        data.shimmer.add(&entity, Shimmer);
        data.shape.add(&entity,
            Shape {
                varient: ShapeVarient::Circle(BALL_R)
                border: None
            });
        }
    ));

//    let e = world.create_entity(Box::new(
//            |entity: BuildData, data: &mut Components| {
//        data.color.add(&entity,
//            Color{
//                r: 1.0,
//                g: 0.5,
//                b: 0.2
//            });
//        data.window_clamp.add(&entity,
//            WindowClamp {
//               varient: ClampVarient::Bounce
//            });
//    }) as Box<EntityBuilder<Components>>);
}

//fn make_player(ents: &mut Entities, p1: bool) -> u32 {
//    const FROM_WALL: f64 = 20.0;
//    const PADDLE_W: f64 = 20.0;
//    const PADDLE_H: f64 = 150.0;
//    let x = if p1 {
//        FROM_WALL
//    } else {
//        WINDOW_W - FROM_WALL - PADDLE_W
//    };
//    let y = (WINDOW_H - PADDLE_H) / 2.0;
//    let e = Entity::new()
//        .with_player_controller(
//            PlayerController {
//                up: if p1 { keyboard::W } else { keyboard::I },
//                down: if p1 { keyboard::S } else { keyboard::K }
//            })
//        .with_velocity(Velocity { x: 0.0, y: 0.0 } )
//        .with_position(
//            Position{
//                x: x,
//                y: y
//            })
//        .with_shape(
//            Shape {
//                varient: Square(PADDLE_W, PADDLE_H),
//                border: None
//            })
//        .with_color(
//            Color{
//                r: 0.5,
//                g: 0.2,
//                b: 0.8
//            })
//        .with_window_clamp(
//            WindowClamp {
//               varient: Stop
//            });
//    ents.add(e)
//}

fn main() {
    let opengl = shader_version::OpenGL::_3_2;
    let mut window = Sdl2Window::new(
        opengl,
        WindowSettings {
            title: "Pong".to_string(),
            size: [WINDOW_W as u32, WINDOW_H as u32],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

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

    let mut world = World::<Components, Systems>::new();
    make_ball(&mut world);

    for e in event::events(window) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            //(args.dt as f32);
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
//            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
//                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
//                let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
//                let off = Color([0.0, 0.0, 0.0, 1.0]);
//                let on = Color([1.0, 1.0, 1.0, 1.0]);
//
//                let w = args.width as f64 / 64.0;
//                let h = args.height as f64 / 32.0;
//
//                for (y,row) in vm.screen_rows().enumerate() {
//                    for (x,byte) in row.iter().enumerate() {
//                        let x = x as f64 * w;
//                        let y = y as f64 * h;
//                        r.set(match *byte { 0 => off, _ => on })
//                        .draw([x, y, w, h], &c, gl);
//                    }
//                }
//            });
        }
    }
}
<commit_msg>Update make_ball fn<commit_after>#![allow(unused_variables, unused_imports)]

#[macro_use]
extern crate ecs;
use ecs::*;

extern crate shader_version;
extern crate input;
extern crate event;
extern crate graphics;
extern crate sdl2_window;
extern crate window;
extern crate opengl_graphics;
extern crate quack;

use window::WindowSettings;

use std::collections::HashMap;
use std::default::Default;
use std::rand::Rng;
use event::{Event, ReleaseEvent, UpdateEvent, PressEvent, RenderEvent};
use quack::Set;

use opengl_graphics::{
    Gl,
};
use sdl2_window::Sdl2Window;

static WINDOW_W: f64 = 800.0;
static WINDOW_H: f64 = 600.0;
static WINDOW_PADDING: i32 = 20;

//fn draw_system(event: &Event,
//              gl: &mut Gl,
//              positions: &mut Components<Position>,
//              shapes: &mut Components<Shape>,
//              colors: &mut Components<Color>) {
//    use graphics::*;
//    if let Some(args) = event.update_args() {
//        let w = args.width as f64;
//        let h = args.height as f64;
//
//        let pad = WINDOW_PADDING;
//        gl.viewport(pad, pad, w as i32 - 2 * pad, h as i32 - 2 * pad);
//
//        gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
//            graphics::clear([0.2, 0.2, 0.0, 1.0], gl);
//            let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
//            r.draw([0.0, 0.0, WINDOW_W, WINDOW_H], &c, gl);
//        });
//
////        c.rgb(0.7, 0.7, 0.7).rect(0.0, 0.0, WINDOW_W, WINDOW_H).border_radius(1.0).draw(gl);
////
////        for (eid, pos) in positions.iter_mut() {
////          let mut shape = Point;
////          let mut border = None;
////          if shapes.contains_key(eid) {
////            shape = shapes.get_mut(eid).varient;
////            border = shapes.get_mut(eid).border;
////          }
////          let (r, g, b) = if colors.contains_key(eid) {
////              (colors.get_mut(eid).r, colors.get_mut(eid).g, colors.get_mut(eid).b)
////          } else {
////              (1.0, 1.0, 1.0)
////          };
////          let drawing = c.rgb(r, g, b);
////          match (shape, border) {
////              (Point, None)    => drawing.rect(1.0, 1.0, w, h).draw(gl),
////              (Point, Some(b)) => drawing.rect(1.0, 1.0, w, h).border_radius(b).draw(gl),
////
////              (Circle(rad), None)    => drawing.ellipse(pos.x, pos.y, rad, rad).draw(gl),
////              (Circle(rad), Some(b)) => drawing.ellipse(pos.x, pos.y, rad, rad).border_radius(b).draw(gl),
////
////              (Square(w,h), None)    => drawing.rect(pos.x, pos.y, w, h).draw(gl),
////              (Square(w,h), Some(b)) => drawing.rect(pos.x, pos.y, w, h).border_radius(b).draw(gl),
////          };
////        }
//    }
//}

//fn shimmer_system(shimmers: &mut Components<Shimmer>,
//                 colors: &mut Components<Color>) {
//    for (eid, _) in shimmers.iter_mut() {
//        if !colors.contains_key(eid) {
//            continue;
//        }
//        let color = colors.get_mut(eid);
//        let ref mut rng = rand::thread_rng();
//        color.r = rng.gen_range(0.5, 1.0);
//        color.g = rng.gen_range(0.5, 1.0);
//        color.b = rng.gen_range(0.5, 1.0);
//    }
//}
//
//fn move_system(event: &Event,
//               to_delete: &mut Vec<u32>,
//              positions: &mut Components<Position>,
//              shapes: &mut Components<Shape>,
//              clamps: &mut Components<WindowClamp>,
//              velocities: &mut Components<Velocity>) {
//    if let Some(args) = event.update_args {
//        let dt = args.dt;
////
////        for (eid, position) in positions.iter_mut() {
////            if !velocities.contains_key(eid) {
////                continue;
////            }
////
////            // If we have both a position and a velocity, integrate.
////            let velocity = velocities.get_mut(eid);
////            position.x += velocity.x * dt;
////            position.y += velocity.y * dt;
////
////            if !clamps.contains_key(eid) {
////              continue;
////            }
////            let (w, h) = match shapes.find(eid) {
////                Some(&s) =>
////                  match s.varient {
////                    Circle(r) => (r, r),
////                    Square(w,h) => (w, h),
////                    Point => (0.0, 0.0)
////                  },
////                None => (0.0, 0.0)
////            };
////
////            let clamp = clamps.get_mut(eid);
////            let velocity_mult = match clamp.varient {
////              Bounce => -1.0,
////              Stop => 0.0,
////              _ => 1.0
////            };
////            match clamp.varient {
////              Bounce | Stop => {
////                if position.x + w > WINDOW_W {
////                  position.x = WINDOW_W - w;
////                  velocity.x *= velocity_mult;
////                } else if position.x < 0.0 {
////                  position.x = 0.0;
////                  velocity.x *= velocity_mult;
////                }
////                if position.y + h > WINDOW_H {
////                  position.y = WINDOW_H - h;
////                  velocity.y *= velocity_mult;
////                } else if position.y < 0.0 {
////                  position.y = 0.0;
////                  velocity.y *= velocity_mult;
////                }
////              },
////              Remove => {
////                if position.x > WINDOW_W
////                || position.x + w < 0.0 {
////                  to_delete.push(*eid);
////                }
////                if position.y > WINDOW_H
////                || position.y + h < 0.0 {
////                  to_delete.push(*eid);
////                }
////              }
////            }
////        }
//    }
//}
//
//fn control_system(event: &Event,
//              controllers: &mut Components<PlayerController>,
//              velocities: &mut Components<Velocity>) {
//
//    const PADDLE_V: f64 = 800.0;
//
////    for (eid, controller) in controllers.iter_mut() {
////        event.press(|button| {
////            if button == Keyboard(controller.up) {
////                velocities.get_mut(eid).y = -PADDLE_V;
////            } else if button == Keyboard(controller.down) {
////                velocities.get_mut(eid).y = PADDLE_V;
////            }
////        });
////        event.release(|button| {
////            if button == Keyboard(controller.up)
////            || button == Keyboard(controller.down) {
////                velocities.get_mut(eid).y = 0.0;
////            }
////        });
////    }
//}

#[derive(Clone, PartialEq, Debug)]
pub enum ClampVarient {
    Bounce,
    Stop,
    Remove // Acts when item leaves window.
}

#[derive(Clone, PartialEq, Debug)]
pub struct WindowClamp {
    varient: ClampVarient
}

#[derive(Clone, PartialEq, Debug)]
pub struct PlayerController {
    up: input::Button,
    down: input::Button
}

#[derive(Clone, PartialEq, Debug)]
pub struct Position {
    x: f64,
    y: f64
}

#[derive(Clone, PartialEq, Debug)]
pub struct Shimmer;

#[derive(Clone, PartialEq, Debug)]
pub struct Color {
    r: f32,
    g: f32,
    b: f32
}

#[derive(Clone, PartialEq, Debug)]
pub enum ShapeVarient {
    Point,
    Circle(f64), // radius
    Square(f64, f64), // width, height
}

impl Default for ShapeVarient {
    fn default() -> ShapeVarient { ShapeVarient::Point }
}

#[derive(Clone, PartialEq, Debug)]
pub struct Shape {
    varient: ShapeVarient,
    border: Option<f64>
}

#[derive(Clone, PartialEq, Debug)]
pub struct Velocity {
    x: f64,
    y: f64
}

components! {
    Components {
        #[hot] position: Position,
        #[hot] shape: Shape,
        #[hot] velocity: Velocity,
        #[hot] color: Color,
        #[hot] shimmer: Shimmer,
        #[hot] player_controller: PlayerController,
        #[hot] window_clamp: WindowClamp
    }
}

systems! {
    Systems<Components>;
}

fn make_ball(world: &mut World<Components, Systems>) {
    const BALL_R: f64 = 20.0;
    let x = (WINDOW_W - BALL_R) / 2.0;
    let y = (WINDOW_H - BALL_R) / 2.0;

    let entity = world.create_entity(Box::new(|entity: BuildData, data: &mut Components| {
        data.position.add(&entity,
            Position{
                x: x,
                y: y
        });
        data.shimmer.add(&entity, Shimmer);
        data.shape.add(&entity,
            Shape {
                varient: ShapeVarient::Circle(BALL_R),
                border: None
        });
        data.color.add(&entity,
            Color{
                r: 1.0,
                g: 0.5,
                b: 0.2
        });
        data.window_clamp.add(&entity,
            WindowClamp {
               varient: ClampVarient::Bounce
        });
    }));
}

//fn make_player(ents: &mut Entities, p1: bool) -> u32 {
//    const FROM_WALL: f64 = 20.0;
//    const PADDLE_W: f64 = 20.0;
//    const PADDLE_H: f64 = 150.0;
//    let x = if p1 {
//        FROM_WALL
//    } else {
//        WINDOW_W - FROM_WALL - PADDLE_W
//    };
//    let y = (WINDOW_H - PADDLE_H) / 2.0;
//    let e = Entity::new()
//        .with_player_controller(
//            PlayerController {
//                up: if p1 { keyboard::W } else { keyboard::I },
//                down: if p1 { keyboard::S } else { keyboard::K }
//            })
//        .with_velocity(Velocity { x: 0.0, y: 0.0 } )
//        .with_position(
//            Position{
//                x: x,
//                y: y
//            })
//        .with_shape(
//            Shape {
//                varient: Square(PADDLE_W, PADDLE_H),
//                border: None
//            })
//        .with_color(
//            Color{
//                r: 0.5,
//                g: 0.2,
//                b: 0.8
//            })
//        .with_window_clamp(
//            WindowClamp {
//               varient: Stop
//            });
//    ents.add(e)
//}

fn main() {
    let opengl = shader_version::OpenGL::_3_2;
    let window = Sdl2Window::new(
        opengl,
        WindowSettings {
            title: "Pong".to_string(),
            size: [WINDOW_W as u32, WINDOW_H as u32],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

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

    let mut world = World::<Components, Systems>::new();
    make_ball(&mut world);

    for e in event::events(window) {
        use event::{ ReleaseEvent, UpdateEvent, PressEvent, RenderEvent };

        if let Some(args) = e.update_args() {
            //(args.dt as f32);
        }
        if let Some(args) = e.render_args() {
            use graphics::*;
//            gl.draw([0, 0, args.width as i32, args.height as i32], |c, gl| {
//                graphics::clear([0.0, 0.0, 0.0, 1.0], gl);
//                let r = Rectangle::new([1.0, 1.0, 1.0, 1.0]);
//                let off = Color([0.0, 0.0, 0.0, 1.0]);
//                let on = Color([1.0, 1.0, 1.0, 1.0]);
//
//                let w = args.width as f64 / 64.0;
//                let h = args.height as f64 / 32.0;
//
//                for (y,row) in vm.screen_rows().enumerate() {
//                    for (x,byte) in row.iter().enumerate() {
//                        let x = x as f64 * w;
//                        let y = y as f64 * h;
//                        r.set(match *byte { 0 => off, _ => on })
//                        .draw([x, y, w, h], &c, gl);
//                    }
//                }
//            });
        }
    }
}
<|endoftext|>


<commit_before>extern crate rff;

use std::env;
use std::io::{self, Write, BufWriter};
use rff::{stdin, matcher, scorer};

fn main() {
    if let Some(search_term) = env::args().nth(1) {
        let lines = stdin::slurp();

        let mut lines: Vec<_> = lines.iter()
            .filter(|line| { matcher::matches(&search_term, line) })
            .map(|line| { (line, scorer::score(&search_term, line)) })
            .collect();

        lines.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());

        let stdout = io::stdout();
        let mut stdout = BufWriter::new(stdout.lock());

        for line in &lines {
            writeln!(stdout, "{}", line.0).unwrap();
        }
    }
}
<commit_msg>filter_map seems more efficient than filter + map<commit_after>extern crate rff;

use std::env;
use std::io::{self, Write, BufWriter};
use rff::{stdin, matcher, scorer};

fn main() {
    if let Some(search_term) = env::args().nth(1) {
        let lines = stdin::slurp();

        let mut lines: Vec<_> = lines.iter()
            .filter_map(|line| {
                if matcher::matches(&search_term, line) {
                    Some((line, scorer::score(&search_term, line)))
                } else {
                    None
                }
            })
            .collect();

        lines.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap().reverse());

        let stdout = io::stdout();
        let mut stdout = BufWriter::new(stdout.lock());

        for line in &lines {
            writeln!(stdout, "{}", line.0).unwrap();
        }
    }
}
<|endoftext|>


<commit_before>extern crate getopts;
extern crate "rust-nc" as rustnc;

use getopts::{Options};
use std::os;

use rustnc::{print_usage,nc};

fn main() {
    let args: Vec<String> = os::args();

    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("l", "listen", "Listen for incoming connections.");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(args.tail()) {
        Ok(m) => { m }
        Err(f) => {
            print_usage(program.as_slice(), opts);
            panic!(f.to_string())
        }
    };
    if matches.opt_present("h") {
        print_usage(program.as_slice(), opts);
        return;
    }

    nc(&matches);
}
<commit_msg>Fixing a couple warnings with arg getting.<commit_after>extern crate getopts;
extern crate "rust-nc" as rustnc;

use getopts::Options;
use std::os;

use rustnc::{print_usage,nc};

fn main() {
    let args: Vec<String> = os::args();

    let program = args[0].clone();

    let mut opts = Options::new();
    opts.optflag("l", "listen", "Listen for incoming connections.");
    opts.optflag("h", "help", "print this help menu");
    let matches = match opts.parse(args.tail()) {
        Ok(m) => { m }
        Err(f) => {
            print_usage(program.as_slice(), opts);
            panic!(f.to_string())
        }
    };
    if matches.opt_present("h") {
        print_usage(&program, opts);
        return;
    }

    nc(&matches);
}
<|endoftext|>