<commit_before>#[cfg(test)]
mod tests;

mod game;
mod ai;
mod ui;
mod game_view;
mod constants;
mod helpers;
mod thread_synchronisation;

// Command line argument parser
extern crate clap;
use clap::{App, Arg, SubCommand};

// UI dependencies
extern crate kiss3d;
extern crate glfw;
extern crate nalgebra as na;

extern crate rand;

use ai::StatelessAI;
use constants::LINES; //, PARALLELOGRAMS, PLUSSES};
use std::rc::Rc;

fn main() {
    let matches = parse_command_line_input();

    fn batch(arguments: &clap::ArgMatches) -> Result<(), String> {
        let ai1_params = arguments.values_of("ai1").map(ai_parser).unwrap()?;
        let ai2_params = arguments.values_of("ai2").map(ai_parser).unwrap()?;
        let count: usize = arguments
            .value_of("count")
            .unwrap()
            .parse::<usize>()
            .unwrap();

        let structure = Rc::new(game::Structure::new(&LINES));

        let mut ai1 = ai::AIBox::new(structure.clone(), ai1_params);
        let mut ai2 = ai::AIBox::new(structure.clone(), ai2_params);

        for i in 1..count+1 {
            println!("Match {} results in {:?}",
                     i,
                     ai::run_match(&structure, &mut ai1, &mut ai2).victory_state);
        }
        Ok(())
    }

    if let Some(batch_matches) = matches.subcommand_matches("batch") {

        batch(batch_matches).unwrap();

        return;
    }

    let ai_parameter_result = matches
        .values_of("opponent")
        .map(ai_parser)
        .unwrap_or(Ok(ai::Constructor::MonteCarlo { endurance: 1000 }));

    let ai_parameter = match ai_parameter_result {
        Ok(param) => param,
        Err(error) => {
            println!("Faulty AI specified: {}", error);
            return;
        }
    };

    let structure = Rc::new(game::Structure::new(&LINES));
    let player_2_ai = ai::AIBox::new(structure.clone(), ai_parameter);

    interactive(structure, player_2_ai);
}

fn parse_command_line_input<'clap>() -> clap::ArgMatches<'clap> {
    let validate_integer = |s: String| match s.parse::<u32>() {
        Ok(_) => Ok(()),
        Err(_) => Err("Needs to be an integer.".to_owned()),
    };

    let batch_run = SubCommand::with_name("batch")
        .about("Executes many AI matches at once.")
        .arg(Arg::with_name("count")
                 .short("n")
                 .long("count")
                 .help("How many matches should be played")
                 .takes_value(true)
                 .default_value("1")
                 .validator(validate_integer))
        .arg(Arg::with_name("ai1")
                 .short("p")
                 .required(true)
                 .help("Specify first AI.")
                 .min_values(1))
        .arg(Arg::with_name("ai2")
                 .short("q")
                 .required(true)
                 .help("Specify second AI.")
                 .min_values(1));

    let opponent = Arg::with_name("opponent")
        .short("p")
        .long("player")
        .help("Specify which AI you want to play against.")
        .min_values(1);

    App::new("Sogo - Play four in a row.")
        .version("0.0.1")
        .author("Rolf Sievers <rolf.sievers@posteo.de>")
        .about("UI and AIs for Sogo.")
        .subcommand(batch_run)
        .arg(opponent)
        .get_matches()
}

fn ai_parser(mut values: clap::Values) -> Result<ai::Constructor, String> {
    let ai_name: &str = values.next().unwrap();
    match ai_name {
        "random" => Ok(ai::Constructor::Random),
        "mc" => {
            let endurance = values
                .next()
                .unwrap_or("10000")
                .parse::<usize>()
                .map_err(|_| "The endurance needs to be a number.")?;
            Ok(ai::Constructor::MonteCarlo { endurance })
        }
        "tree" => {
            let depth = values
                .next()
                .unwrap_or("2")
                .parse::<u8>()
                .map_err(|_| "The depth needs to be a number.")?;

            let value_function = values
                .next()
                .unwrap_or("subsets")
                .parse::<ai::value::Simple>()
                .map_err(|_| "Invalid value function provided.")?;
            Ok(ai::Constructor::Tree { depth, value_function })
        }
        _ => Err("AI not recognized.")?,
    }
}

fn interactive(structure: Rc<game::Structure>, mut p2: ai::AIBox) {
    let ui_connector = ui::UiConnector::new();

    // let mut p2 = ai::tree::TreeJudgementAI::new(structure.clone(), 2);
    // let mut p2 = ai::mc::MonteCarloAI::new(structure.clone(), 10000);
    // let mut p2 = ai::random::RandomSogoAI::new();

    // Run a game, this should look synchronous.
    let mut state = game::State::new();

    loop {
        user_turn(&ui_connector, &mut state, &structure);

        // Check for victory.
        if !state.victory_state.active() {
            println!("The Human has won the game.");
            ui_connector.game_over(state.victory_state);
            ui_connector.wait_for_halt();
            break;
        }

        ai_turn(&ui_connector, &mut p2, &mut state, &structure);

        // Check for victory.
        if !state.victory_state.active() {
            println!("The AI has won the game.");
            ui_connector.game_over(state.victory_state);
            ui_connector.wait_for_halt();
            break;
        }
    }
}

fn user_turn(ui_connector: &ui::UiConnector,
             state: &mut game::State,
             structure: &game::Structure) {
    // Wait for the player to make the first action
    let action = ui_connector.wait_for_action().unwrap();

    let color = state.current_color;
    state.execute(&structure, action);
    ui_connector.confirmed_action(action, color).unwrap();
}

fn ai_turn<A: StatelessAI>(ui_connector: &ui::UiConnector,
                           ai: &mut A,
                           state: &mut game::State,
                           structure: &game::Structure) {
    // Let the AI take one action
    let action = ai.action(&state);

    let color = state.current_color;
    state.execute(&structure, action);
    ui_connector.confirmed_action(action, color).unwrap();
}
<commit_msg>Implement basic AI demo functionality.<commit_after>#[cfg(test)]
mod tests;

mod game;
mod ai;
mod ui;
mod game_view;
mod constants;
mod helpers;
mod thread_synchronisation;

// Command line argument parser
extern crate clap;
use clap::{App, Arg, SubCommand};

// UI dependencies
extern crate kiss3d;
extern crate glfw;
extern crate nalgebra as na;

extern crate rand;

use ai::StatelessAI;
use constants::LINES; //, PARALLELOGRAMS, PLUSSES};
use std::rc::Rc;

fn main() {
    let matches = parse_command_line_input();

    fn batch(arguments: &clap::ArgMatches) -> Result<(), String> {
        let ai1_params = arguments.values_of("ai1").map(ai_parser).unwrap()?;
        let ai2_params = arguments.values_of("ai2").map(ai_parser).unwrap()?;
        let count: usize = arguments
            .value_of("count")
            .unwrap()
            .parse::<usize>()
            .unwrap();

        let structure = Rc::new(game::Structure::new(&LINES));

        let mut ai1 = ai::AIBox::new(structure.clone(), ai1_params);
        let mut ai2 = ai::AIBox::new(structure.clone(), ai2_params);

        for i in 1..count+1 {
            println!("Match {} results in {:?}",
                     i,
                     ai::run_match(&structure, &mut ai1, &mut ai2).victory_state);
        }
        Ok(())
    }

    if let Some(batch_matches) = matches.subcommand_matches("batch") {
        batch(batch_matches).unwrap();
        return;
    }

    if let Some(demo_matches) = matches.subcommand_matches("demo") {
        demo(demo_matches).unwrap();
        return;
    }

    let ai_parameter_result = matches
        .values_of("opponent")
        .map(ai_parser)
        .unwrap_or(Ok(ai::Constructor::MonteCarlo { endurance: 1000 }));

    let ai_parameter = match ai_parameter_result {
        Ok(param) => param,
        Err(error) => {
            println!("Faulty AI specified: {}", error);
            return;
        }
    };

    let structure = Rc::new(game::Structure::new(&LINES));
    let player_2_ai = ai::AIBox::new(structure.clone(), ai_parameter);

    interactive(structure, player_2_ai);
}

fn parse_command_line_input<'clap>() -> clap::ArgMatches<'clap> {
    let validate_integer = |s: String| match s.parse::<u32>() {
        Ok(_) => Ok(()),
        Err(_) => Err("Needs to be an integer.".to_owned()),
    };

    let ai_1 = || Arg::with_name("ai1")
             .short("p")
             .required(true)
             .help("Specify first AI.")
             .min_values(1);
    let ai_2 = || Arg::with_name("ai2")
             .short("q")
             .required(true)
             .help("Specify second AI.")
             .min_values(1);

    let batch_run = SubCommand::with_name("batch")
        .about("Executes many AI matches at once.")
        .arg(Arg::with_name("count")
                 .short("n")
                 .long("count")
                 .help("How many matches should be played")
                 .takes_value(true)
                 .default_value("1")
                 .validator(validate_integer))
        .arg(ai_1())
        .arg(ai_2());

    let demo_match = SubCommand::with_name("demo")
        .about("Demonstration match with two AIs")
        .arg(ai_1())
        .arg(ai_2());

    let opponent = Arg::with_name("opponent")
        .short("p")
        .long("player")
        .help("Specify which AI you want to play against.")
        .min_values(1);

    App::new("Sogo - Play four in a row.")
        .version("0.0.1")
        .author("Rolf Sievers <rolf.sievers@posteo.de>")
        .about("UI and AIs for Sogo.")
        .subcommand(batch_run)
        .subcommand(demo_match)
        .arg(opponent)
        .get_matches()
}

fn ai_parser(mut values: clap::Values) -> Result<ai::Constructor, String> {
    let ai_name: &str = values.next().unwrap();
    match ai_name {
        "random" => Ok(ai::Constructor::Random),
        "mc" => {
            let endurance = values
                .next()
                .unwrap_or("10000")
                .parse::<usize>()
                .map_err(|_| "The endurance needs to be a number.")?;
            Ok(ai::Constructor::MonteCarlo { endurance })
        }
        "tree" => {
            let depth = values
                .next()
                .unwrap_or("2")
                .parse::<u8>()
                .map_err(|_| "The depth needs to be a number.")?;

            let value_function = values
                .next()
                .unwrap_or("subsets")
                .parse::<ai::value::Simple>()
                .map_err(|_| "Invalid value function provided.")?;
            Ok(ai::Constructor::Tree { depth, value_function })
        }
        _ => Err("AI not recognized.")?,
    }
}

fn interactive(structure: Rc<game::Structure>, mut p2: ai::AIBox) {
    let ui_connector = ui::UiConnector::new();

    // Run a game, this should look synchronous.
    let mut state = game::State::new();

    loop {
        user_turn(&ui_connector, &mut state, &structure);

        // Check for victory.
        if !state.victory_state.active() {
            println!("The Human has won the game.");
            ui_connector.game_over(state.victory_state);
            ui_connector.wait_for_halt();
            break;
        }

        ai_turn(&ui_connector, &mut p2, &mut state, &structure);

        // Check for victory.
        if !state.victory_state.active() {
            println!("The AI has won the game.");
            ui_connector.game_over(state.victory_state);
            ui_connector.wait_for_halt();
            break;
        }
    }
}

fn user_turn(ui_connector: &ui::UiConnector,
             state: &mut game::State,
             structure: &game::Structure) {
    // Wait for the player to make the first action
    let action = ui_connector.wait_for_action().unwrap();

    let color = state.current_color;
    state.execute(&structure, action);
    ui_connector.confirmed_action(action, color).unwrap();
}

fn ai_turn<A: StatelessAI>(ui_connector: &ui::UiConnector,
                           ai: &mut A,
                           state: &mut game::State,
                           structure: &game::Structure) {
    // Let the AI take one action
    let action = ai.action(&state);

    let color = state.current_color;
    state.execute(&structure, action);
    ui_connector.confirmed_action(action, color).unwrap();
}

// This is simmilar to interactive, but the player isn't allowed to do any moves.
fn demo(arguments: &clap::ArgMatches) -> Result<(), String> {
    let ai1_params = arguments.values_of("ai1").map(ai_parser).unwrap()?;
    let ai2_params = arguments.values_of("ai2").map(ai_parser).unwrap()?;

    let structure = Rc::new(game::Structure::new(&LINES));

    let mut active_ai = ai::AIBox::new(structure.clone(), ai1_params);
    let mut waiting_ai = ai::AIBox::new(structure.clone(), ai2_params);

    let ui_connector = ui::UiConnector::new();

    let mut state = game::State::new();

    loop {
        ai_turn(&ui_connector, &mut active_ai, &mut state, &structure);

        // Check for victory.
        if !state.victory_state.active() {
            ui_connector.game_over(state.victory_state);
            ui_connector.wait_for_halt();
            break;
        }

        // Swap AIs.
        let temp = active_ai;
        active_ai = waiting_ai;
        waiting_ai = temp;
    }

    Ok(())
}
<|endoftext|>


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

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    return (rec.normal + Vec3::new(1.0, 1.0, 1.0)) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let ns = 100;
  let mut col = Vec3::origin();
  for s in 0..ns {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    let p = r.point_at_parameter(2.0);
    col += color(r, world);
  }

  col /= ns as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let col = random(i, j, nx, ny, cam, &world, &mut rng);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<commit_msg>Add stratified antialiasing<commit_after>use std::io::{Write, BufWriter};
use std::fs::File;

extern crate rand;
use rand::Rng;

mod vector;
mod ray;
mod sphere;
mod hitable;
mod hitable_list;
mod camera;

use vector::{Vec3, dot, cross, unit_vector};
use ray::Ray;
use sphere::{Sphere};
use hitable::{Hitable, hit_record};
use hitable_list::Hitable_list;
use camera::Camera;

fn color<T: Hitable>(ray : Ray, world : &T) -> Vec3 {
  let mut rec = hit_record::new(0.0, Vec3::origin(), Vec3::origin());
  if world.hit(ray, 0.0, std::f64::MAX, &mut rec) {
    return (rec.normal + Vec3::new(1.0, 1.0, 1.0)) * 0.5
  }
  else {
    let unit_direction = unit_vector(ray.direction());
    let t = (unit_direction.y() + 1.0) * 0.5;
    return Vec3::new(1.0, 1.0, 1.0) * (1.0 - t) + Vec3::new(0.5, 0.7, 1.0) * t;
  }
}

fn random<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let ns = 100;
  let mut col = Vec3::origin();
  for s in 0..ns {
    let u = (i as f64 + rng.gen::<f64>()) / nx as f64;
    let v = (j as f64 + rng.gen::<f64>()) / ny as f64;
    let r = cam.get_ray(u, v);

    let p = r.point_at_parameter(2.0);
    col += color(r, world);
  }

  col /= ns as f64;
  return col;
}

fn stratified<T: Hitable>(i : i32, j : i32, nx : i32, ny : i32, cam : Camera, world : &T, rng : &mut rand::ThreadRng) -> Vec3 {
  let mut col = Vec3::origin();
  let grid_size = 5;
  let step = 1.0 / grid_size as f64;
  let lowI = i as f64 - 0.5;
  let lowJ = j as f64 - 0.5;

  for ii in 0..grid_size {
    for jj in 0..grid_size {
      let u = ((lowI + ii as f64 * step) + rng.gen_range(0.0, step)) / nx as f64;
      let v = ((lowJ + jj as f64 * step) + rng.gen_range(0.0, step)) / ny as f64;
      let r = cam.get_ray(u, v);

      let p = r.point_at_parameter(2.0);
      col += color(r, world);
    }
  }

  col /= (grid_size * grid_size) as f64;
  return col;
}

fn main() {
  let nx = 200;
  let ny = 100;
  let data = format!("{}\n{} {}\n{}\n", "P3", nx, ny, 255);
  let f = File::create("target/image.ppm").expect("Unable to create file");
  let mut f = BufWriter::new(f);
  f.write_all(data.as_bytes()).expect("Unable to write data");

  let lower_left_corner = Vec3::new(-2.0, -1.0, -1.0);
  let horizontal = Vec3::new(4.0, 0.0, 0.0);
  let vertical = Vec3::new(0.0, 2.0, 0.0);
  let origin = Vec3::new(0.0, 0.0, 0.0);

  let cam = Camera::new(lower_left_corner, vertical, horizontal, origin);

  let mut list : Vec<Box<Hitable>> = Vec::new();
  list.push(Box::new(Sphere::new(Vec3::new(0.0,0.0,-1.0), 0.5)));
  list.push(Box::new(Sphere::new(Vec3::new(0.0,-100.5,-1.0), 100.0)));
  let world = Hitable_list::new(list);

  let mut rng = rand::thread_rng();

  for j in (0..ny).rev() {
    for i in 0..nx {
      let col = stratified(i, j, nx, ny, cam, &world, &mut rng);

      let ir = (255.99*col.r()) as i32;
      let ig = (255.99*col.g()) as i32;
      let ib = (255.99*col.b()) as i32;
      f.write_all(format!("{} {} {}\n", ir, ig, ib).as_bytes()).expect("Unable to write data");
    }
  }
}<|endoftext|>


<commit_before>use crate::exercise::{Exercise, ExerciseList};
use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::fs;
use std::io::BufRead;
use std::path::Path;
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;

mod exercise;
mod run;
mod verify;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger, Carol Nichols")
        .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
        .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
        .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .about("Runs/Tests a single exercise")
                .arg(Arg::with_name("file").required(true).index(1))
                .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
        )
        .get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    if None == matches.subcommand_name() {
        println!();
        println!(r#"       welcome to...                      "#);
        println!(r#"                 _   _ _                  "#);
        println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
        println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
        println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
        println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
        println!(r#"                               |___/      "#);
        println!();
    }

    if !Path::new("info.toml").exists() {
        println!(
            "{} must be run from the rustlings directory",
            std::env::current_exe().unwrap().to_str().unwrap()
        );
        std::process::exit(1);
    }

    let toml_str = &fs::read_to_string("info.toml").unwrap();
    let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;

    if let Some(ref matches) = matches.subcommand_matches("run") {
        let filename = matches.value_of("file").unwrap_or_else(|| {
            println!("Please supply a file name!");
            std::process::exit(1);
        });

        let matching_exercise = |e: &&Exercise| {
            Path::new(filename)
                .canonicalize()
                .map(|p| p.ends_with(&e.path))
                .unwrap_or(false)
        };

        let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
            println!("No exercise found for your file name!");
            std::process::exit(1)
        });

        run(&exercise).unwrap_or_else(|_| std::process::exit(1));
    }

    if matches.subcommand_matches("verify").is_some() {
        verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
    }

    if matches.subcommand_matches("watch").is_some() {
        watch(&exercises).unwrap();
    }

    if matches.subcommand_name().is_none() {
        let mut highlighter =
            HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn watch(exercises: &[Exercise]) -> notify::Result<()> {
    let (tx, rx) = channel();

    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
    watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;

    let _ignored = verify(exercises.iter());

    loop {
        match rx.recv() {
            Ok(event) => match event {
                DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
                    if b.extension() == Some(OsStr::new("rs")) {
                        println!("----------**********----------\n");
                        let filepath = b.as_path().canonicalize().unwrap();
                        let exercise = exercises
                            .iter()
                            .skip_while(|e| !filepath.ends_with(&e.path));
                        let _ignored = verify(exercise);
                    }
                }
                _ => {}
            },
            Err(e) => println!("watch error: {:?}", e),
        }
    }
}
<commit_msg>add a slightly more helpful error message<commit_after>use crate::exercise::{Exercise, ExerciseList};
use crate::run::run;
use crate::verify::verify;
use clap::{crate_version, App, Arg, SubCommand};
use notify::DebouncedEvent;
use notify::{RecommendedWatcher, RecursiveMode, Watcher};
use std::ffi::OsStr;
use std::fs;
use std::io::BufRead;
use std::path::Path;
use std::sync::mpsc::channel;
use std::time::Duration;
use syntect::easy::HighlightFile;
use syntect::highlighting::{Style, ThemeSet};
use syntect::parsing::SyntaxSet;
use syntect::util::as_24_bit_terminal_escaped;

mod exercise;
mod run;
mod verify;

fn main() {
    let matches = App::new("rustlings")
        .version(crate_version!())
        .author("Olivia Hugger, Carol Nichols")
        .about("Rustlings is a collection of small exercises to get you used to writing and reading Rust code")
        .subcommand(SubCommand::with_name("verify").alias("v").about("Verifies all exercises according to the recommended order"))
        .subcommand(SubCommand::with_name("watch").alias("w").about("Reruns `verify` when files were edited"))
        .subcommand(
            SubCommand::with_name("run")
                .alias("r")
                .about("Runs/Tests a single exercise")
                .arg(Arg::with_name("file").required(true).index(1))
                .arg(Arg::with_name("test").short("t").long("test").help("Run the file as a test")),
        )
        .get_matches();

    let ss = SyntaxSet::load_defaults_newlines();
    let ts = ThemeSet::load_defaults();

    if None == matches.subcommand_name() {
        println!();
        println!(r#"       welcome to...                      "#);
        println!(r#"                 _   _ _                  "#);
        println!(r#"  _ __ _   _ ___| |_| (_)_ __   __ _ ___  "#);
        println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
        println!(r#" | |  | |_| \__ \ |_| | | | | | (_| \__ \ "#);
        println!(r#" |_|   \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
        println!(r#"                               |___/      "#);
        println!();
    }

    if !Path::new("info.toml").exists() {
        println!(
            "{} must be run from the rustlings directory",
            std::env::current_exe().unwrap().to_str().unwrap()
        );
        println!("Try `cd rustlings/`!");
        std::process::exit(1);
    }

    let toml_str = &fs::read_to_string("info.toml").unwrap();
    let exercises = toml::from_str::<ExerciseList>(toml_str).unwrap().exercises;

    if let Some(ref matches) = matches.subcommand_matches("run") {
        let filename = matches.value_of("file").unwrap_or_else(|| {
            println!("Please supply a file name!");
            std::process::exit(1);
        });

        let matching_exercise = |e: &&Exercise| {
            Path::new(filename)
                .canonicalize()
                .map(|p| p.ends_with(&e.path))
                .unwrap_or(false)
        };

        let exercise = exercises.iter().find(matching_exercise).unwrap_or_else(|| {
            println!("No exercise found for your file name!");
            std::process::exit(1)
        });

        run(&exercise).unwrap_or_else(|_| std::process::exit(1));
    }

    if matches.subcommand_matches("verify").is_some() {
        verify(&exercises).unwrap_or_else(|_| std::process::exit(1));
    }

    if matches.subcommand_matches("watch").is_some() {
        watch(&exercises).unwrap();
    }

    if matches.subcommand_name().is_none() {
        let mut highlighter =
            HighlightFile::new("default_out.md", &ss, &ts.themes["base16-eighties.dark"]).unwrap();
        for maybe_line in highlighter.reader.lines() {
            let line = maybe_line.unwrap();
            let regions: Vec<(Style, &str)> = highlighter.highlight_lines.highlight(&line, &ss);
            println!("{}", as_24_bit_terminal_escaped(&regions[..], true));
        }
    }

    println!("\x1b[0m");
}

fn watch(exercises: &[Exercise]) -> notify::Result<()> {
    let (tx, rx) = channel();

    let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(2))?;
    watcher.watch(Path::new("./exercises"), RecursiveMode::Recursive)?;

    let _ignored = verify(exercises.iter());

    loop {
        match rx.recv() {
            Ok(event) => match event {
                DebouncedEvent::Create(b) | DebouncedEvent::Chmod(b) | DebouncedEvent::Write(b) => {
                    if b.extension() == Some(OsStr::new("rs")) {
                        println!("----------**********----------\n");
                        let filepath = b.as_path().canonicalize().unwrap();
                        let exercise = exercises
                            .iter()
                            .skip_while(|e| !filepath.ends_with(&e.path));
                        let _ignored = verify(exercise);
                    }
                }
                _ => {}
            },
            Err(e) => println!("watch error: {:?}", e),
        }
    }
}
<|endoftext|>


<commit_before>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate board_game_geom as geom;
#[macro_use]
extern crate conrod;
extern crate find_folder;
extern crate piston_window;
extern crate vecmath;

use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;

use geom::{Point, Size};

use conrod::{Canvas, Circle, Frameable, LineStyle, Rectangle, Sizeable, Text, Theme, Widget,
             WidgetMatrix};
use conrod::color::{self, Color, Colorable};
use conrod::Positionable;

use piston_window::{Glyphs, PistonWindow, UpdateEvent, WindowSettings};

use board::Board;
use othello_disk::OthelloDisk;

type Ui = conrod::Ui<Glyphs>;

mod board;
mod othello_disk;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Side {
    Black,
    White,
}

impl Side {
    fn flip(self) -> Side {
        match self {
            Side::Black => Side::White,
            Side::White => Side::Black,
        }
    }
}

#[derive(Clone, Debug)]
struct App {
    board: Board,
    view_config: ViewConfig,
}

#[derive(Copy, Clone, Debug)]
struct ViewConfig {
    frame_width: f64,
    cell_size: f64,
    disk_radius: f64,
    dot_radius: f64,
    board_margin: f64,
    indicator_text_width: f64,

    frame_color: Color,
    board_color: Color,
    white_color: Color,
    black_color: Color,
}

impl Default for ViewConfig {
    fn default() -> ViewConfig {
        ViewConfig {
            frame_width: 1.0,
            cell_size: 80.0,
            disk_radius: 32.0,
            dot_radius: 6.0,
            board_margin: 40.0,
            indicator_text_width: 90.0,

            frame_color: color::black(),
            board_color: color::rgba(0.0, 0.5, 0.0, 1.0),
            white_color: color::white(),
            black_color: color::black(),
        }
    }
}

impl Default for App {
    fn default() -> App {
        App {
            board: Board::new(Size(8, 8)),
            view_config: ViewConfig::default(),
        }
    }
}

fn main() {
    let app_ref = Rc::new(RefCell::new(App::default()));

    let window: PistonWindow = {
        WindowSettings::new("Othello", (1024, 768))
            .exit_on_esc(true)
            .vsync(true)
            .build()
            .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e))
    };

    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
                         .for_folder("assets")
                         .unwrap();
        let ref font_path = assets.join("FiraSans-Regular.ttf");
        let factory = window.factory.borrow().clone();
        let glyph_cache = Glyphs::new(font_path, factory).unwrap();
        let theme = Theme::default();
        Ui::new(glyph_cache, theme)
    };

    for event in window {
        ui.handle_event(&event);

        let _ = event.update(|_| ui.set_widgets(|ui| set_widgets(ui, app_ref.clone())));
        event.draw_2d(|c, g| ui.draw_if_changed(c, g));
    }
}

widget_ids! {
    CANVAS,
    OTHELLO_CANVAS,
    BOARD,
    DOT with 4,
    INDICATOR_LABEL_ICON with 2,
    INDICATOR_LABEL_TEXT with 2,
}

fn set_widgets(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let (Size(rows, cols), vc) = {
        let app = app_ref.deref().borrow();
        let size = app.board.size();
        (size, app.view_config)
    };

    Canvas::new().color(vc.board_color).scrolling(true).set(CANVAS, ui);

    let board_width = vc.cell_size * (cols as f64);
    let indicator_width = vc.cell_size + vc.indicator_text_width;
    let width = board_width + vc.board_margin * 2.0 + indicator_width + vc.board_margin;

    let board_height = vc.cell_size * (rows as f64);
    let indicator_height = vc.cell_size * 2.0;
    let height = vc.board_margin * 2.0 + f64::max(board_height, indicator_height);

    let style = LineStyle::new().thickness(0.0);
    let rect = Rectangle::outline_styled([width, height], style);

    match (ui.win_w < board_width, ui.win_h < board_height) {
        (true, true) => rect.top_left_of(CANVAS),
        (false, true) => rect.mid_top_of(CANVAS),
        (true, false) => rect.mid_left_of(CANVAS),
        (false, false) => rect.middle_of(CANVAS),
    }
    .set(OTHELLO_CANVAS, ui);

    WidgetMatrix::new(cols as usize, rows as usize)
        .top_left_with_margins_on(OTHELLO_CANVAS, vc.board_margin, vc.board_margin)
        .w_h(vc.cell_size * (cols as f64), vc.cell_size * (rows as f64))
        .each_widget(|_n, col, row| {
            let pt = Point(row as i32, col as i32);
            let disk = {
                let app_ref = app_ref.clone();
                let app = app_ref.deref().borrow();
                let mut disk = OthelloDisk::new()
                                   .background_color(vc.board_color)
                                   .frame(vc.frame_width)
                                   .frame_color(vc.frame_color)
                                   .white_color(vc.white_color)
                                   .black_color(vc.black_color)
                                   .radius(vc.disk_radius)
                                   .disk(app.board[pt]);
                if let Some(turn) = app.board.turn() {
                    if app.board.can_locate(pt) {
                        disk = disk.flow_disk(Some(turn));
                    }
                }
                disk
            };

            let app_ref = app_ref.clone();
            disk.react(move || {
                app_ref.borrow_mut().board.locate(pt);
            })
        })
        .set(BOARD, ui);

    let x = vc.cell_size * ((cols / 4) as f64);
    let y = vc.cell_size * ((rows / 4) as f64);
    let signs = &[(-1.0, 1.0), (1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)];
    for (i, &(sx, sy)) in signs.iter().enumerate() {
        Circle::fill(vc.dot_radius)
            .x_y_relative_to(BOARD, sx * x, sy * y)
            .color(vc.frame_color)
            .set(DOT + i, ui);
    }

    for (i, &side) in [Side::Black, Side::White].iter().enumerate() {
        let app = app_ref.deref().borrow();
        if side == Side::Black {
            OthelloDisk::new().right_from(BOARD, vc.board_margin)
        } else {
            OthelloDisk::new().down_from(INDICATOR_LABEL_ICON + (i - 1), 0.0)
        }
        .w_h(vc.cell_size, vc.cell_size)
        .background_color(vc.board_color)
        .frame(0.0)
        .white_color(vc.white_color)
        .black_color(vc.black_color)
        .radius(vc.disk_radius)
        .disk(Some(side))
        .react(|| {})
        .set(INDICATOR_LABEL_ICON + i, ui);

        let text = match side {
            Side::Black => app.board.num_black().to_string(),
            Side::White => app.board.num_white().to_string(),
        };
        Text::new(&text)
            .w(vc.indicator_text_width)
            .right_from(INDICATOR_LABEL_ICON + i, 0.0)
            .font_size(60)
            .align_text_right()
            .set(INDICATOR_LABEL_TEXT + i, ui);
    }
}
<commit_msg>support changing board size<commit_after>#![warn(bad_style)]
#![warn(missing_copy_implementations)]
#![warn(missing_debug_implementations)]
// #![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate board_game_geom as geom;
#[macro_use]
extern crate conrod;
extern crate find_folder;
extern crate piston_window;
extern crate vecmath;

use std::cell::RefCell;
use std::ops::Deref;
use std::rc::Rc;
use std::str::FromStr;

use geom::{Point, Size};

use conrod::{Button, Canvas, Circle, DropDownList, Frameable, Labelable, LineStyle, Rectangle,
             Sizeable, Text, Theme, Widget, WidgetMatrix};
use conrod::color::{self, Color, Colorable};
use conrod::Positionable;

use piston_window::{Glyphs, PistonWindow, UpdateEvent, WindowSettings};

use board::Board;
use othello_disk::OthelloDisk;

type Ui = conrod::Ui<Glyphs>;

mod board;
mod othello_disk;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Side {
    Black,
    White,
}

impl Side {
    fn flip(self) -> Side {
        match self {
            Side::Black => Side::White,
            Side::White => Side::Black,
        }
    }
}

#[derive(Clone, Debug)]
struct App {
    state: State,
    game_config: GameConfig,
    view_config: ViewConfig,
}

impl Default for App {
    fn default() -> App {
        App {
            state: State::Start(StartState::default()),
            game_config: GameConfig::default(),
            view_config: ViewConfig::default(),
        }
    }
}

#[derive(Clone, Debug)]
enum State {
    Start(StartState),
    Play(PlayState),
}

impl State {
    fn unwrap_start(&self) -> &StartState {
        match self {
            &State::Start(ref start_ref) => start_ref,
            _ => panic!(),
        }
    }

    fn unwrap_mut_start(&mut self) -> &mut StartState {
        match self {
            &mut State::Start(ref mut start_ref) => start_ref,
            _ => panic!(),
        }
    }

    fn unwrap_play(&self) -> &PlayState {
        match self {
            &State::Play(ref play_ref) => play_ref,
            _ => panic!(),
        }
    }

    fn unwrap_mut_play(&mut self) -> &mut PlayState {
        match self {
            &mut State::Play(ref mut play_ref) => play_ref,
            _ => panic!(),
        }
    }
}

#[derive(Clone, Debug)]
struct StartState {
    ddl_rows_selected_idx: Option<usize>,
    ddl_cols_selected_idx: Option<usize>,
    ddl_rows: Vec<String>,
    ddl_cols: Vec<String>,
}

impl Default for StartState {
    fn default() -> StartState {
        let ddl = (2..11).map(|n| n.to_string()).collect::<Vec<_>>();
        StartState {
            ddl_rows_selected_idx: ddl.iter().position(|x| x == "8"),
            ddl_cols_selected_idx: ddl.iter().position(|x| x == "8"),
            ddl_rows: ddl.clone(),
            ddl_cols: ddl,
        }

    }
}

#[derive(Clone, Debug)]
struct PlayState {
    board: Board,
}

impl PlayState {
    fn new(size: Size) -> PlayState {
        PlayState { board: Board::new(size) }
    }
}

#[derive(Copy, Clone, Debug)]
struct GameConfig {
    rows: i32,
    cols: i32,
}

impl Default for GameConfig {
    fn default() -> GameConfig {
        GameConfig { rows: 8, cols: 8 }
    }
}

#[derive(Copy, Clone, Debug)]
struct ViewConfig {
    frame_width: f64,
    cell_size: f64,
    disk_radius: f64,
    dot_radius: f64,
    board_margin: f64,
    indicator_text_width: f64,

    frame_color: Color,
    board_color: Color,
    white_color: Color,
    black_color: Color,
}

impl Default for ViewConfig {
    fn default() -> ViewConfig {
        ViewConfig {
            frame_width: 1.0,
            cell_size: 80.0,
            disk_radius: 32.0,
            dot_radius: 6.0,
            board_margin: 40.0,
            indicator_text_width: 90.0,

            frame_color: color::black(),
            board_color: color::rgba(0.0, 0.5, 0.0, 1.0),
            white_color: color::white(),
            black_color: color::black(),
        }
    }
}

fn main() {
    let window: PistonWindow = {
        WindowSettings::new("Othello", (1024, 768))
            .exit_on_esc(true)
            .vsync(true)
            .build()
            .unwrap_or_else(|e| panic!("Failed to build PistonWindow: {}", e))
    };

    let mut ui = {
        let assets = find_folder::Search::KidsThenParents(3, 5)
                         .for_folder("assets")
                         .unwrap();
        let ref font_path = assets.join("FiraSans-Regular.ttf");
        let factory = window.factory.borrow().clone();
        let glyph_cache = Glyphs::new(font_path, factory).unwrap();
        let theme = Theme::default();
        Ui::new(glyph_cache, theme)
    };

    let app_ref = Rc::new(RefCell::new(App::default()));
    for event in window {
        ui.handle_event(&event);

        let _ = event.update(|_| ui.set_widgets(|ui| set_widgets(ui, app_ref.clone())));
        event.draw_2d(|c, g| ui.draw_if_changed(c, g));
    }
}

widget_ids! {
    CANVAS,

    START_BUTTON,
    TIMES_LABEL,
    ROWS_DDL,
    COLS_DDL,

    PLAY_CANVAS,
    BOARD,
    DOT with 4,
    INDICATOR_LABEL_ICON with 2,
    INDICATOR_LABEL_TEXT with 2,
}

fn set_widgets(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let func: fn(ui: &mut Ui, Rc<RefCell<App>>) = {
        let app = app_ref.deref().borrow();
        match app.state {
            State::Start(_) => set_widgets_start,
            State::Play(_) => set_widgets_play,
        }
    };
    func(ui, app_ref.clone())
}

fn set_widgets_start(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let (gc, vc) = {
        let app = app_ref.deref().borrow();
        (app.game_config, app.view_config)
    };

    Canvas::new().color(vc.board_color).scrolling(true).set(CANVAS, ui);
    Text::new(&"x")
        .w_h(30.0, 50.0)
        .font_size(40)
        .align_text_middle()
        .mid_top_with_margin_on(CANVAS, 40.0)
        .set(TIMES_LABEL, ui);

    {
        let mut app = app_ref.deref().borrow_mut();
        let mut rows = app.game_config.rows;
        let mut cols = app.game_config.cols;
        {
            let start = app.state.unwrap_mut_start();
            DropDownList::new(&mut start.ddl_rows, &mut start.ddl_rows_selected_idx)
                .w_h(50.0, 50.0)
                .left_from(TIMES_LABEL, 30.0)
                .label("Rows")
                .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
                    *selected_idx = Some(new_idx);
                    rows = i32::from_str(string).unwrap();
                })
                .set(ROWS_DDL, ui);
            DropDownList::new(&mut start.ddl_cols, &mut start.ddl_cols_selected_idx)
                .w_h(50.0, 50.0)
                .right_from(TIMES_LABEL, 30.0)
                .label("Cols")
                .react(|selected_idx: &mut Option<usize>, new_idx, string: &str| {
                    *selected_idx = Some(new_idx);
                    cols = i32::from_str(string).unwrap();
                })
                .set(COLS_DDL, ui);
        }
        app.game_config.rows = rows;
        app.game_config.cols = cols;
    }

    Button::new()
        .w_h(200.0, 50.0)
        .down_from(TIMES_LABEL, 40.0)
        .align_middle_x_of(TIMES_LABEL)
        .label("start")
        .react(|| {
            let mut app = app_ref.deref().borrow_mut();
            app.state = State::Play(PlayState::new(Size(gc.rows, gc.cols)));
        })
        .set(START_BUTTON, ui);
}

fn set_widgets_play(ui: &mut Ui, app_ref: Rc<RefCell<App>>) {
    let (gc, vc) = {
        let app = app_ref.deref().borrow();
        (app.game_config, app.view_config)
    };

    Canvas::new().color(vc.board_color).scrolling(true).set(CANVAS, ui);

    let board_width = vc.cell_size * (gc.cols as f64);
    let indicator_width = vc.cell_size + vc.indicator_text_width;
    let width = board_width + vc.board_margin * 2.0 + indicator_width + vc.board_margin;

    let board_height = vc.cell_size * (gc.rows as f64);
    let indicator_height = vc.cell_size * 2.0;
    let height = vc.board_margin * 2.0 + f64::max(board_height, indicator_height);

    let style = LineStyle::new().thickness(0.0);
    let rect = Rectangle::outline_styled([width, height], style);

    match (ui.win_w < board_width, ui.win_h < board_height) {
        (true, true) => rect.top_left_of(CANVAS),
        (false, true) => rect.mid_top_of(CANVAS),
        (true, false) => rect.mid_left_of(CANVAS),
        (false, false) => rect.middle_of(CANVAS),
    }
    .set(PLAY_CANVAS, ui);

    WidgetMatrix::new(gc.cols as usize, gc.rows as usize)
        .top_left_with_margins_on(PLAY_CANVAS, vc.board_margin, vc.board_margin)
        .w_h(vc.cell_size * (gc.cols as f64),
             vc.cell_size * (gc.rows as f64))
        .each_widget(|_n, col, row| {
            let pt = Point(row as i32, col as i32);
            let disk = {
                let app_ref = app_ref.clone();
                let app = app_ref.deref().borrow();
                let play = app.state.unwrap_play();
                let mut disk = OthelloDisk::new()
                                   .background_color(vc.board_color)
                                   .frame(vc.frame_width)
                                   .frame_color(vc.frame_color)
                                   .white_color(vc.white_color)
                                   .black_color(vc.black_color)
                                   .radius(vc.disk_radius)
                                   .disk(play.board[pt]);
                if let Some(turn) = play.board.turn() {
                    if play.board.can_locate(pt) {
                        disk = disk.flow_disk(Some(turn));
                    }
                }
                disk
            };

            let app_ref = app_ref.clone();
            disk.react(move || {
                let mut app = app_ref.deref().borrow_mut();
                let play = app.state.unwrap_mut_play();
                play.board.locate(pt);
            })
        })
        .set(BOARD, ui);

    let x = vc.cell_size * ((gc.cols / 4) as f64);
    let y = vc.cell_size * ((gc.rows / 4) as f64);
    let signs = &[(-1.0, 1.0), (1.0, 1.0), (-1.0, -1.0), (1.0, -1.0)];
    for (i, &(sx, sy)) in signs.iter().enumerate() {
        Circle::fill(vc.dot_radius)
            .x_y_relative_to(BOARD, sx * x, sy * y)
            .color(vc.frame_color)
            .set(DOT + i, ui);
    }

    for (i, &side) in [Side::Black, Side::White].iter().enumerate() {
        let app = app_ref.deref().borrow();
        let play = app.state.unwrap_play();
        if side == Side::Black {
            OthelloDisk::new().right_from(BOARD, vc.board_margin)
        } else {
            OthelloDisk::new().down_from(INDICATOR_LABEL_ICON + (i - 1), 0.0)
        }
        .w_h(vc.cell_size, vc.cell_size)
        .background_color(vc.board_color)
        .frame(0.0)
        .white_color(vc.white_color)
        .black_color(vc.black_color)
        .radius(vc.disk_radius)
        .disk(Some(side))
        .react(|| {})
        .set(INDICATOR_LABEL_ICON + i, ui);

        let text = match side {
            Side::Black => play.board.num_black().to_string(),
            Side::White => play.board.num_white().to_string(),
        };
        Text::new(&text)
            .w(vc.indicator_text_width)
            .right_from(INDICATOR_LABEL_ICON + i, 0.0)
            .font_size(60)
            .align_text_right()
            .set(INDICATOR_LABEL_TEXT + i, ui);
    }
}
<|endoftext|>


<commit_before>#![feature(core, io)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) -> bool {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = self.index.wrapping_add(n);
            }
            &In => {
                let mut c = vec![0u8];
                if io::stdin().read(&mut c).unwrap() == 0 {
                    return false;
                }
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        return true;
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<commit_msg>chore: slice patterns are experimental now<commit_after>#![feature(core, io, slice_patterns)]
use std::fs;
use std::io;
use std::io::{Read, Write};
use std::path::Path;

const MEMSIZE: usize = 4096;

enum ParserResult {
    Something(Op),
    Nothing,
    EOF
}

use ParserResult::*;

#[derive(Debug)]
enum Op {
    Add(u8),
    Mov(usize),
    In,
    Out,
    Loop(OpStream)
}

use Op::*;

#[derive(Debug)]
struct OpStream {
    ops: Vec<Op>
}

impl OpStream {
    fn add(&mut self, op: Op) {
        self.ops.push(op);
    }

    fn optimize(&mut self) {
        let mut i = 0;
        while i < self.ops.len() {
            match &self.ops[i..] {
                [Add(a), Add(b), ..] => {
                    self.ops[i] = Add(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Mov(a), Mov(b), ..] => {
                    self.ops[i] = Mov(a.wrapping_add(b));
                    self.ops.remove(i + 1);
                }
                [Add(0), ..] | [Mov(0), ..] => {
                    self.ops.remove(i);
                }
                _ => i += 1
            }
        }
        for op in &mut self.ops[..] {
            if let &mut Loop(ref mut stream) = op {
                stream.optimize();
            }
        }
    }

    fn get(&self) -> &[Op] {
        &self.ops[..]
    }

    fn new() -> OpStream {
        OpStream { ops: Vec::new() }
    }
}

struct State {
    index: usize,
    memory: [u8; MEMSIZE]
}

impl State {
    fn new() -> State {
        State { index: 0, memory: [0; MEMSIZE] }
    }

    fn peek(&self) -> u8 {
        self.memory[self.index % MEMSIZE]
    }

    fn poke(&mut self, value: u8) {
        self.memory[self.index % MEMSIZE] = value;
    }

    fn step(&mut self, op: &Op) -> bool {
        match op {
            &Add(i) => {
                // XXX: Ugly expression due to lexical scoping of borrow,
                //      cf. https://github.com/rust-lang/rust/issues/6393
                let x = self.peek();
                self.poke(x.wrapping_add(i));
            }
            &Mov(n) => {
                self.index = self.index.wrapping_add(n);
            }
            &In => {
                let mut c = vec![0u8];
                if io::stdin().read(&mut c).unwrap() == 0 {
                    return false;
                }
                self.poke(c[0]);
            }
            &Out => {
                io::stdout().write(&vec![self.peek()]).unwrap();
            }
            &Loop(ref ops) => {
                while self.peek() != 0 {
                    if !self.run(ops.get()) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    fn run(&mut self, ops: &[Op]) -> bool {
        for op in ops {
            if !self.step(op) {
                return false;
            }
        }
        return true;
    }
}

fn main() {
    let filenames: Vec<String> = std::iter::FromIterator::from_iter(std::env::args());

    for filename in &filenames[1..] {
        match reader(&Path::new(filename)) {
            Ok(reader) => {
                let mut chars = reader.chars().peekable();

                let mut opstream = OpStream::new();
                loop {
                    match parse(&mut chars) {
                        Something(op) => opstream.add(op),
                        EOF => break,
                        _ => {}
                    }
                }

                opstream.optimize();

                State::new().run(opstream.get());
            }
            Err(e) => {
                writeln!(&mut io::stderr(), "Error while processing {}: {}", filename, e).unwrap();
            }
        }
    }
}

fn parse<T: io::Read>(mut chars: &mut std::iter::Peekable<io::Chars<T>>) -> ParserResult {
    match chars.next() {
        Some(Ok(c)) => match c {
            '+' => Something(Add(1)),
            '-' => Something(Add(-1)),
            '<' => Something(Mov(-1)),
            '>' => Something(Mov(1)),
            ',' => Something(In),
            '.' => Something(Out),
            '[' => {
                let mut childstream = OpStream::new();
                while chars.peek() != Some(&Ok(']')) {
                    match parse(&mut chars) {
                        Something(op) => childstream.add(op),
                        Nothing => {},
                        EOF => panic!()
                    }
                }
                chars.next();
                Something(Loop(childstream))
            },
            _ => Nothing  // other characters
        },
        _ => EOF  // XXX: really?
    }
}

fn reader(path: &Path) -> Result<io::BufReader<fs::File>, io::Error> {
    Ok(io::BufReader::new(try!(fs::File::open(path))))
}

#[cfg(test)]
mod tests {
    use super::{State, OpStream};
    use super::Op::*;

    #[test]
    fn state_peek() {
        let mut state = State::new();
        state.memory[state.index] = 23;
        assert_eq!(23, state.peek());
        state.index = 5;
        state.memory[state.index] = 42;
        assert_eq!(42, state.peek());
    }

    #[test]
    fn state_poke() {
        let mut state = State::new();
        state.poke(23);
        assert_eq!(23, state.memory[state.index]);
        state.index = 5;
        state.poke(42);
        assert_eq!(42, state.memory[state.index]);
    }

    #[test]
    fn state_step_add() {
        let mut state = State::new();
        state.step(&Add(23));
        assert_eq!(23, state.peek());
        state.step(&Add(42));
        assert_eq!(65, state.peek());
        state.step(&Add(-66));
        assert_eq!(-1, state.peek());
    }

    #[test]
    fn state_step_mov() {
        let mut state = State::new();
        state.step(&Mov(1));
        assert_eq!(1, state.index);
        state.step(&Mov(42));
        assert_eq!(43, state.index);
        state.step(&Mov(-1));
        assert_eq!(42, state.index);
    }

    #[test]
    fn state_step_loop() {
        let mut state = State::new();
        state.poke(23);
        state.step(&Loop(OpStream { ops: vec![Add(1)] }));
        assert_eq!(0, state.peek());
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate walkdir;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::{Command, Output};
use walkdir::WalkDirIterator;

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}", line);
    println!("{}", banner);
    println!("{}", line);
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn announce_path(path: PathBuf) -> PathBuf {
    path.file_name()
        .and_then(|p| p.to_str())
        .map(|p| println!("{}:", p));
    path
}

fn report_output(output: Output) {
    if output.status.success() {
        print_ident(output.stdout);
    } else {
        print_ident(output.stderr);
    }
    println!("");
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {
    let mut cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;
    for arg in env::args().skip(2) {
        cmd.arg(OsString::from(&arg));
        banner = banner + " " + &arg;
    }

    announce(&banner);

    let cwd = env::current_dir().unwrap();
    walkdir::WalkDir::new(cwd)
        .min_depth(MIN_DEPTH)
        .max_depth(MAX_DEPTH)
        .into_iter()
        .filter_entry(|e| e.path().join("Cargo.toml").exists())
        .filter_map(|e| e.ok())
        .map(|e| e.path().to_path_buf())
        .map(announce_path)
        .map(|p| cmd.current_dir(p).output().map(report_output))
        .last();
}
<commit_msg>Replace map(announce_path) with inspect()<commit_after>#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]

extern crate walkdir;

use std::ffi::OsString;
use std::env;
use std::path::PathBuf;
use std::process::{Command, Output};
use walkdir::WalkDirIterator;

fn announce(banner: &str) {
    let mut line = String::new();
    for _ in 0..banner.len() {
        line.push('-');
    }
    println!("{}", line);
    println!("{}", banner);
    println!("{}", line);
}

fn print_ident(buf: Vec<u8>) {
    for line in String::from_utf8_lossy(&buf[..]).lines() {
        println!("        {}", line);
    }
}

fn display_path(path: &PathBuf) {
    path.file_name()
        .and_then(|p| p.to_str())
        .map(|p| println!("{}:", p));
}

fn report_output(output: Output) {
    if output.status.success() {
        print_ident(output.stdout);
    } else {
        print_ident(output.stderr);
    }
    println!("");
}

const CARGO: &'static str = "cargo";
const MIN_DEPTH: usize = 1;
const MAX_DEPTH: usize = 1;

fn main() {
    let mut cmd = Command::new(CARGO);
    let mut banner = String::from("Executing ") + CARGO;
    for arg in env::args().skip(2) {
        cmd.arg(OsString::from(&arg));
        banner = banner + " " + &arg;
    }

    announce(&banner);

    let cwd = env::current_dir().unwrap();
    walkdir::WalkDir::new(cwd)
        .min_depth(MIN_DEPTH)
        .max_depth(MAX_DEPTH)
        .into_iter()
        .filter_entry(|e| e.path().join("Cargo.toml").exists())
        .filter_map(|e| e.ok())
        .map(|e| e.path().to_path_buf())
        .inspect(display_path)
        .map(|p| cmd.current_dir(p).output().map(report_output))
        .last();
}
<|endoftext|>


<commit_before>#![feature(slice_patterns)]
#![allow(dead_code)]

extern crate artificial_genome;
extern crate rand;
extern crate fixedbitset;

use artificial_genome::{Genome, ProteinRegulator, GeneNetwork, GeneNetworkState};
use artificial_genome::base4::{Base4, B0, B1};
use std::mem;
use std::io::{self, Write};
use std::collections::{BTreeMap, BTreeSet};
use fixedbitset::FixedBitSet;

#[derive(Debug, Clone)]
struct Edge {
    src_node: usize,
    dst_node: usize,
    length: f32,

    // there is a structural node, and each time it is activated,
    // this count is increased.
    type_count: usize,

    // Every edge has it's own regulatory network state embedded.
    network_state: GeneNetworkState,
}

const EDGE_DIFFERENTIATION: usize = 0;
const EDGE_SPLIT: usize = 1;
const EDGE_DUPLICATE: usize = 2;
const EDGE_SWAP: usize = 3;
const EDGE_GROW: usize = 4;
const EDGE_SHRINK: usize = 5;
const EDGE_TYPE: usize = 6;

const RESIZE_FACTOR: f32 = 0.25;

impl Edge {
    fn transition_state(&mut self, network: &GeneNetwork) {
        // create an empty new state.
        let mut new_state = network.new_state();

        for (i, node) in network.nodes().iter().enumerate() {
            // determine the new state of ```node``` (position i in new_state)
            if node.sum_edges(&self.network_state) > 0 {
                // node is enabled
                new_state.state.insert(i);
            }
        }
        self.network_state = new_state;
    }

    fn develop(&mut self,
               network: &GeneNetwork,
               next_node_id: &mut usize,
               new_edges: &mut Vec<Edge>) {

        // first perform the state transition.
        self.transition_state(network);

        // perform the actions of all active nodes in the gene network.

        // first node is used for differentiation.
        // in a split/duplicate node, this will be set 0 or 1 in the children.
        // starting from second node, the nodes are mapped to graph grammar rules.

        if self.network_state.state.contains(EDGE_SPLIT) {
            let new_node = *next_node_id;
            *next_node_id += 1;

            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(EDGE_DIFFERENTIATION,
                                  !self.network_state.state.contains(EDGE_DIFFERENTIATION));

            let new_edge = Edge {
                src_node: new_node,
                dst_node: self.dst_node,
                length: 0.5 * self.length,
                network_state: child_state,
                type_count: self.type_count, /* XXX: start with 0 or with the count of the current edge? */
            };
            self.dst_node = new_node;
            self.length /= 2.0;
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(EDGE_DUPLICATE) {
            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(EDGE_DIFFERENTIATION,
                                  !self.network_state.state.contains(EDGE_DIFFERENTIATION));

            let new_edge = Edge {
                src_node: self.dst_node,
                dst_node: self.src_node,
                length: self.length,
                network_state: child_state,
                type_count: self.type_count, /* XXX: start with 0 or with the count of the current edge? */
            };
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(EDGE_SWAP) {
            mem::swap(&mut self.dst_node, &mut self.src_node);
        }

        if self.network_state.state.contains(EDGE_GROW) {
            self.length += RESIZE_FACTOR * self.length;
        }

        if self.network_state.state.contains(EDGE_SHRINK) {
            self.length -= RESIZE_FACTOR * self.length;
        }

        if self.network_state.state.contains(EDGE_TYPE) {
            self.type_count += 1;
        }
    }
}

struct NodeGraph {
    nodes: Vec<NodeInfo>,
    edges: BTreeSet<(usize, usize)>,
}

struct NodeInfo {
    length: f32,
    type_count: usize,
}

#[derive(Debug)]
struct FoundPath {
    target_node: usize,
    length: f32,
}

// Find all paths from current_node to connected nodes.
fn path_finder(current_node: usize,
               current_length: f32,
               neighborhood: &Vec<Vec<usize>>,
               lengths: &Vec<f32>,
               targets: &BTreeSet<usize>,
               visited: &mut FixedBitSet,
               paths: &mut Vec<FoundPath>) {
    assert!(visited.contains(current_node));

    for &ni in neighborhood[current_node].iter() {
        if targets.contains(&ni) {
            // we found a target
            paths.push(FoundPath {
                target_node: ni,
                length: current_length,
            });
        } else {
            // the node ``ni`` is not a target node.
            // let's see if we already have visited it.
            if visited.contains(ni) {
                // if we have, continue with next iteration
                continue;
            }

            // we haven't visited ```ni``` yet. recurse down
            visited.set(ni, true);
            path_finder(ni,
                        current_length + lengths[ni],
                        neighborhood,
                        lengths,
                        targets,
                        visited,
                        paths);
            visited.set(ni, false);
        }
    }
}

#[derive(Debug)]
struct StructuredNode {
    length: f32,
    type_count: usize,
    connections: Vec<FoundPath>,
}

// There are two types of nodes. Processing nodes (e.g. Neuron) or
// connecting nodes (e.g. Synapses). Keep the processing nodes as
// nodes in the graph, while the connecting nodes become edges.
#[derive(Debug)]
struct StructuredGraph {
    nodes: BTreeMap<usize, StructuredNode>,
}

impl NodeGraph {
    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        // the edges are nodes in this graph.
        for (i, node) in self.nodes.iter().enumerate() {
            try!(writeln!(wr,
                          "{} [label=\"{}:{:.2}:{}\"]",
                          i,
                          i,
                          node.length,
                          node.type_count));
        }

        // now connect them
        for &(src_edge, dst_edge) in self.edges.iter() {
            try!(writeln!(wr, "{} -> {}", src_edge, dst_edge));
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }

    fn into_structured_graph(&self, type_processing: usize) -> StructuredGraph {
        // determine max type_count.
        // lets say every type_count >= 3 is a neuron for now.
        // everything else is a synapse
        // If two synapses are directly connected to each other,
        // treat them as one synapse with the summation of it's lengths.
        // XXX: remove synapses which are too long.
        // If two neurons are next to each other, what to do?
        // a) Treat them as one big neuron
        // b) Connect them with a minimum synapse?
        // We do b) for now, because it's easier.

        let mut neighbors: BTreeMap<usize, BTreeSet<usize>> = BTreeMap::new();
        for &(src, dst) in self.edges.iter() {
            neighbors.entry(src).or_insert_with(|| BTreeSet::new()).insert(dst);
        }

        let mut processing_nodes: BTreeSet<usize> = BTreeSet::new();

        for (i, node) in self.nodes.iter().enumerate() {
            if node.type_count >= type_processing {
                processing_nodes.insert(i);
            }
        }

        let neighborhood: Vec<Vec<usize>> = self.nodes
                                                .iter()
                                                .enumerate()
                                                .map(|(i, _)| {
                                                    neighbors.get(&i)
                                                             .map(|v| v.iter().cloned().collect())
                                                             .unwrap_or(Vec::new())
                                                })
                                                .collect();

        let lengths: Vec<f32> = self.nodes
                                    .iter()
                                    .map(|n| n.length)
                                    .collect();

        // now follow all possible directed paths from each processing_node, until
        // we arrive at another processing_node.
        // (Or repetetively merge consecutive elements which have same type).

        let mut visited = FixedBitSet::with_capacity(self.nodes.len());

        let mut g = StructuredGraph { nodes: BTreeMap::new() };

        for &pnode in processing_nodes.iter() {
            // find all processing elements connected either directly or through intermediate
            // synapses.
            let mut snode = StructuredNode {
                length: self.nodes[pnode].length,
                type_count: self.nodes[pnode].type_count,
                connections: Vec::new(),
            };

            visited.clear();
            visited.set(pnode, true);
            path_finder(pnode,
                        0.0,
                        &neighborhood,
                        &lengths,
                        &processing_nodes,
                        &mut visited,
                        &mut snode.connections);

            g.nodes.insert(pnode, snode);
        }

        g
    }
}

impl StructuredGraph {
    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        for (&i, node) in self.nodes.iter() {
            try!(writeln!(wr,
                          "{} [label=\"{} {:.2} {}\"]",
                          i,
                          i,
                          node.length,
                          node.type_count));
        }

        // now connect them
        for (src, node) in self.nodes.iter() {
            for dst in node.connections.iter() {
                if dst.length == 0.0 {
                    // XXX
                    continue;
                }
                try!(writeln!(wr,
                              "{} -> {} [weight={} label=\"{}\"]",
                              src,
                              dst.target_node,
                              dst.length,
                              dst.length));
            }
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }
}

#[derive(Debug)]
struct GraphBuilder {
    edges: Vec<Edge>,
    next_node_id: usize,
    network: GeneNetwork,
}

impl GraphBuilder {
    fn new(network: GeneNetwork, zygote: GeneNetworkState) -> GraphBuilder {
        let initial_edge = Edge {
            src_node: 0,
            dst_node: 1,
            length: 1.0,
            type_count: 0,
            network_state: zygote,
        };

        GraphBuilder {
            edges: vec![initial_edge],
            next_node_id: 2,
            network: network,
        }
    }

    // During the process, some edges will be added (split), some others will be modified.
    fn next(&mut self) {
        let mut new_edges = Vec::new();
        for edge in self.edges.iter_mut() {
            edge.develop(&self.network, &mut self.next_node_id, &mut new_edges);
        }
        println!("next_node_id: {}", self.next_node_id);
        println!("new edges: {:?}", new_edges);
        self.edges.extend(new_edges);
    }

    // The result of the GraphBuilder is a graph where every edge represents an element (either a
    // Neuron or a Synapse), while the nodes represent connection points (they carry purely
    // structural information). Transform this "edged" graph into a graph where the edges become
    // nodes.
    fn into_node_graph(&self) -> NodeGraph {
        let mut node_out_edges: Vec<Vec<usize>> = (0..self.next_node_id)
                                                      .map(|_| Vec::new())
                                                      .collect();
        let mut node_in_edges: Vec<Vec<usize>> = (0..self.next_node_id)
                                                     .map(|_| Vec::new())
                                                     .collect();
        let mut node_graph = NodeGraph {
            nodes: Vec::with_capacity(self.edges.len()),
            edges: BTreeSet::new(),
        };

        // every edge becomes a node.
        // note that ```i``` matches the indices  we use for ```new_nodes```.
        for (i, edge) in self.edges.iter().enumerate() {
            let j = node_graph.nodes.len();
            node_graph.nodes.push(NodeInfo {
                length: edge.length,
                type_count: edge.type_count,
            });
            assert!(i == j);
            node_out_edges[edge.src_node].push(i);
            node_in_edges[edge.dst_node].push(i);
        }
        assert!(node_graph.nodes.len() == self.edges.len());

        for (i, edge) in self.edges.iter().enumerate() {
            // connect i with all outgoing edges of dst_node

            // if node_out_edges[edge.dst_node].is_empty() {
            // println!("Empty node");
            // XXX: turn it into an output-node
            // }
            // if node_in_edges[edge.src_node].is_empty() {
            // println!("Empty node");
            // XXX: turn it into an input-node
            // }
            //

            for &out_i in node_out_edges[edge.dst_node].iter() {
                node_graph.edges.insert((i, out_i));
            }
            // connect i with all incoming edges of src_node
            for &in_i in node_in_edges[edge.src_node].iter() {
                node_graph.edges.insert((in_i, i));
            }
        }

        node_graph
    }

    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        for edge in self.edges.iter() {
            try!(writeln!(wr,
                          "{} -> {} [weight={} label=\"{} / {}\"]",
                          edge.src_node,
                          edge.dst_node,
                          edge.length,
                          edge.length,
                          edge.type_count));
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }
}

fn main() {
    use std::fs::File;
    // let genome = Genome::<Base4>::from_str("...11 _0320_23 <0101> T:0311 2...3 _1022_ 133 <0101> \
    // W:3213 121...")
    let mut rng = rand::thread_rng();

    let genome = Genome::<Base4>::random(&mut rng, 10 * 256);

    // let promoter = BaseString::<Base4>::from_str("0101").unwrap();
    let promoter = [B0, B1, B0, B1];

    let genes: Vec<_> = genome.iter_genes(&promoter, 4).collect();
    println!("{:?}", genes);

    let network = genome.construct_network(&promoter,
                                           4,
                                           &|product| {
                                               if product.last() == Some(&B0) {
                                                   // Inhibitor
                                                   ProteinRegulator::inhibit()
                                               } else {
                                                   // Inhibitor
                                                   ProteinRegulator::enhance()
                                               }
                                           });

    println!("{:#?}", network);

    let mut zygote = network.new_state();
    zygote.state.set(0, true);
    // zygote.state.set(1, true);

    let mut gb = GraphBuilder::new(network, zygote);
    println!("{:#?}", gb);

    for _ in 0..5 {
        gb.next();
    }
    println!("{:#?}", gb);

    gb.write_dot(&mut File::create("example1.dot").unwrap()).unwrap();

    let node_graph = gb.into_node_graph();
    node_graph.write_dot(&mut File::create("example1_node.dot").unwrap()).unwrap();
    let g = node_graph.into_structured_graph(1);
    println!("g: {:?}", g);
    g.write_dot(&mut File::create("example1_struct.dot").unwrap()).unwrap();
}
<commit_msg>Refactor<commit_after>#![feature(slice_patterns)]
#![allow(dead_code)]

extern crate artificial_genome;
extern crate rand;
extern crate fixedbitset;

use artificial_genome::{Genome, ProteinRegulator, GeneNetwork, GeneNetworkState};
use artificial_genome::base4::{Base4, B0, B1};
use std::mem;
use std::io::{self, Write};
use std::collections::{BTreeMap, BTreeSet};
use fixedbitset::FixedBitSet;

#[derive(Debug, Clone)]
struct Edge {
    src_node: usize,
    dst_node: usize,
    length: f32,

    // there is a structural node, and each time it is activated,
    // this count is increased.
    type_count: usize,

    // Every edge has it's own regulatory network state embedded.
    network_state: GeneNetworkState,
}

const EDGE_DIFFERENTIATION: usize = 0;
const EDGE_SPLIT: usize = 1;
const EDGE_DUPLICATE: usize = 2;
const EDGE_SWAP: usize = 3;
const EDGE_GROW: usize = 4;
const EDGE_SHRINK: usize = 5;
const EDGE_TYPE: usize = 6;

const RESIZE_FACTOR: f32 = 0.25;

impl Edge {
    fn transition_state(&mut self, network: &GeneNetwork) {
        // create an empty new state.
        let mut new_state = network.new_state();

        for (i, node) in network.nodes().iter().enumerate() {
            // determine the new state of ```node``` (position i in new_state)
            if node.sum_edges(&self.network_state) > 0 {
                // node is enabled
                new_state.state.insert(i);
            }
        }
        self.network_state = new_state;
    }

    fn develop(&mut self,
               network: &GeneNetwork,
               next_node_id: &mut usize,
               new_edges: &mut Vec<Edge>) {

        // first perform the state transition.
        self.transition_state(network);

        // perform the actions of all active nodes in the gene network.

        // first node is used for differentiation.
        // in a split/duplicate node, this will be set 0 or 1 in the children.
        // starting from second node, the nodes are mapped to graph grammar rules.

        if self.network_state.state.contains(EDGE_SPLIT) {
            let new_node = *next_node_id;
            *next_node_id += 1;

            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(EDGE_DIFFERENTIATION,
                                  !self.network_state.state.contains(EDGE_DIFFERENTIATION));

            let new_edge = Edge {
                src_node: new_node,
                dst_node: self.dst_node,
                length: 0.5 * self.length,
                network_state: child_state,
                type_count: self.type_count, /* XXX: start with 0 or with the count of the current edge? */
            };
            self.dst_node = new_node;
            self.length /= 2.0;
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(EDGE_DUPLICATE) {
            // differentiate
            let mut child_state = self.network_state.clone();
            child_state.state.set(EDGE_DIFFERENTIATION,
                                  !self.network_state.state.contains(EDGE_DIFFERENTIATION));

            let new_edge = Edge {
                src_node: self.dst_node,
                dst_node: self.src_node,
                length: self.length,
                network_state: child_state,
                type_count: self.type_count, /* XXX: start with 0 or with the count of the current edge? */
            };
            new_edges.push(new_edge);
        }

        if self.network_state.state.contains(EDGE_SWAP) {
            mem::swap(&mut self.dst_node, &mut self.src_node);
        }

        if self.network_state.state.contains(EDGE_GROW) {
            self.length += RESIZE_FACTOR * self.length;
        }

        if self.network_state.state.contains(EDGE_SHRINK) {
            self.length -= RESIZE_FACTOR * self.length;
        }

        if self.network_state.state.contains(EDGE_TYPE) {
            self.type_count += 1;
        }
    }
}

struct NodeGraph {
    nodes: Vec<NodeInfo>,
    edges: BTreeSet<(usize, usize)>,
}

struct NodeInfo {
    length: f32,
    type_count: usize,
}

#[derive(Debug)]
struct FoundPath {
    target_node: usize,
    length: f32,
}

// Find all paths from current_node to connected nodes.
fn path_finder(current_node: usize,
               current_length: f32,
               neighborhood: &Vec<Vec<usize>>,
               lengths: &Vec<f32>,
               targets: &BTreeSet<usize>,
               visited: &mut FixedBitSet,
               paths: &mut Vec<FoundPath>) {
    for &ni in neighborhood[current_node].iter() {
        if targets.contains(&ni) {
            // we found a target
            paths.push(FoundPath {
                target_node: ni,
                length: current_length,
            });
        } else if !visited.contains(ni) {
            // the node ``ni`` is not a target node and we haven't
            // visited yet.

            // we haven't visited ```ni``` yet. recurse down
            visited.set(ni, true);
            path_finder(ni,
                        current_length + lengths[ni],
                        neighborhood,
                        lengths,
                        targets,
                        visited,
                        paths);
            visited.set(ni, false);
        }
    }
}

#[derive(Debug)]
struct StructuredNode {
    length: f32,
    type_count: usize,
    connections: Vec<FoundPath>,
}

// There are two types of nodes. Processing nodes (e.g. Neuron) or
// connecting nodes (e.g. Synapses). Keep the processing nodes as
// nodes in the graph, while the connecting nodes become edges.
#[derive(Debug)]
struct StructuredGraph {
    nodes: BTreeMap<usize, StructuredNode>,
}

impl NodeGraph {
    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        // the edges are nodes in this graph.
        for (i, node) in self.nodes.iter().enumerate() {
            try!(writeln!(wr,
                          "{} [label=\"{}:{:.2}:{}\"]",
                          i,
                          i,
                          node.length,
                          node.type_count));
        }

        // now connect them
        for &(src_edge, dst_edge) in self.edges.iter() {
            try!(writeln!(wr, "{} -> {}", src_edge, dst_edge));
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }

    fn into_structured_graph(&self, type_processing: usize) -> StructuredGraph {
        // determine max type_count.
        // lets say every type_count >= 3 is a neuron for now.
        // everything else is a synapse
        // If two synapses are directly connected to each other,
        // treat them as one synapse with the summation of it's lengths.
        // XXX: remove synapses which are too long.
        // If two neurons are next to each other, what to do?
        // a) Treat them as one big neuron
        // b) Connect them with a minimum synapse?
        // We do b) for now, because it's easier.

        let mut neighbors: BTreeMap<usize, BTreeSet<usize>> = BTreeMap::new();
        for &(src, dst) in self.edges.iter() {
            neighbors.entry(src).or_insert_with(|| BTreeSet::new()).insert(dst);
        }

        let mut processing_nodes: BTreeSet<usize> = BTreeSet::new();

        for (i, node) in self.nodes.iter().enumerate() {
            if node.type_count >= type_processing {
                processing_nodes.insert(i);
            }
        }

        let neighborhood: Vec<Vec<usize>> = self.nodes
                                                .iter()
                                                .enumerate()
                                                .map(|(i, _)| {
                                                    neighbors.get(&i)
                                                             .map(|v| v.iter().cloned().collect())
                                                             .unwrap_or(Vec::new())
                                                })
                                                .collect();

        let lengths: Vec<f32> = self.nodes
                                    .iter()
                                    .map(|n| n.length)
                                    .collect();

        // now follow all possible directed paths from each processing_node, until
        // we arrive at another processing_node.
        // (Or repetetively merge consecutive elements which have same type).

        let mut visited = FixedBitSet::with_capacity(self.nodes.len());

        let mut g = StructuredGraph { nodes: BTreeMap::new() };

        for &pnode in processing_nodes.iter() {
            // find all processing elements connected either directly or through intermediate
            // synapses.
            let mut snode = StructuredNode {
                length: self.nodes[pnode].length,
                type_count: self.nodes[pnode].type_count,
                connections: Vec::new(),
            };

            visited.clear();
            path_finder(pnode,
                        0.0,
                        &neighborhood,
                        &lengths,
                        &processing_nodes,
                        &mut visited,
                        &mut snode.connections);

            g.nodes.insert(pnode, snode);
        }

        g
    }
}

impl StructuredGraph {
    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        for (&i, node) in self.nodes.iter() {
            try!(writeln!(wr,
                          "{} [label=\"{} {:.2} {}\"]",
                          i,
                          i,
                          node.length,
                          node.type_count));
        }

        // now connect them
        for (src, node) in self.nodes.iter() {
            for dst in node.connections.iter() {
                if dst.length == 0.0 {
                    // XXX
                    continue;
                }
                try!(writeln!(wr,
                              "{} -> {} [weight={} label=\"{}\"]",
                              src,
                              dst.target_node,
                              dst.length,
                              dst.length));
            }
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }
}

#[derive(Debug)]
struct GraphBuilder {
    edges: Vec<Edge>,
    next_node_id: usize,
    network: GeneNetwork,
}

impl GraphBuilder {
    fn new(network: GeneNetwork, zygote: GeneNetworkState) -> GraphBuilder {
        let initial_edge = Edge {
            src_node: 0,
            dst_node: 1,
            length: 1.0,
            type_count: 0,
            network_state: zygote,
        };

        GraphBuilder {
            edges: vec![initial_edge],
            next_node_id: 2,
            network: network,
        }
    }

    // During the process, some edges will be added (split), some others will be modified.
    fn next(&mut self) {
        let mut new_edges = Vec::new();
        for edge in self.edges.iter_mut() {
            edge.develop(&self.network, &mut self.next_node_id, &mut new_edges);
        }
        println!("next_node_id: {}", self.next_node_id);
        println!("new edges: {:?}", new_edges);
        self.edges.extend(new_edges);
    }

    // The result of the GraphBuilder is a graph where every edge represents an element (either a
    // Neuron or a Synapse), while the nodes represent connection points (they carry purely
    // structural information). Transform this "edged" graph into a graph where the edges become
    // nodes.
    fn into_node_graph(&self) -> NodeGraph {
        let mut node_out_edges: Vec<Vec<usize>> = (0..self.next_node_id)
                                                      .map(|_| Vec::new())
                                                      .collect();
        let mut node_in_edges: Vec<Vec<usize>> = (0..self.next_node_id)
                                                     .map(|_| Vec::new())
                                                     .collect();
        let mut node_graph = NodeGraph {
            nodes: Vec::with_capacity(self.edges.len()),
            edges: BTreeSet::new(),
        };

        // every edge becomes a node.
        // note that ```i``` matches the indices  we use for ```new_nodes```.
        for (i, edge) in self.edges.iter().enumerate() {
            let j = node_graph.nodes.len();
            node_graph.nodes.push(NodeInfo {
                length: edge.length,
                type_count: edge.type_count,
            });
            assert!(i == j);
            node_out_edges[edge.src_node].push(i);
            node_in_edges[edge.dst_node].push(i);
        }
        assert!(node_graph.nodes.len() == self.edges.len());

        for (i, edge) in self.edges.iter().enumerate() {
            // connect i with all outgoing edges of dst_node

            // if node_out_edges[edge.dst_node].is_empty() {
            // println!("Empty node");
            // XXX: turn it into an output-node
            // }
            // if node_in_edges[edge.src_node].is_empty() {
            // println!("Empty node");
            // XXX: turn it into an input-node
            // }
            //

            for &out_i in node_out_edges[edge.dst_node].iter() {
                node_graph.edges.insert((i, out_i));
            }
            // connect i with all incoming edges of src_node
            for &in_i in node_in_edges[edge.src_node].iter() {
                node_graph.edges.insert((in_i, i));
            }
        }

        node_graph
    }

    fn write_dot<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        try!(writeln!(wr, "digraph artificial {{"));

        for edge in self.edges.iter() {
            try!(writeln!(wr,
                          "{} -> {} [weight={} label=\"{} / {}\"]",
                          edge.src_node,
                          edge.dst_node,
                          edge.length,
                          edge.length,
                          edge.type_count));
        }

        try!(writeln!(wr, "}}"));

        Ok(())
    }
}

fn main() {
    use std::fs::File;
    // let genome = Genome::<Base4>::from_str("...11 _0320_23 <0101> T:0311 2...3 _1022_ 133 <0101> \
    // W:3213 121...")
    let mut rng = rand::thread_rng();

    let genome = Genome::<Base4>::random(&mut rng, 10 * 256);

    // let promoter = BaseString::<Base4>::from_str("0101").unwrap();
    let promoter = [B0, B1, B0, B1];

    let genes: Vec<_> = genome.iter_genes(&promoter, 4).collect();
    println!("{:?}", genes);

    let network = genome.construct_network(&promoter,
                                           4,
                                           &|product| {
                                               if product.last() == Some(&B0) {
                                                   // Inhibitor
                                                   ProteinRegulator::inhibit()
                                               } else {
                                                   // Inhibitor
                                                   ProteinRegulator::enhance()
                                               }
                                           });

    println!("{:#?}", network);

    let mut zygote = network.new_state();
    zygote.state.set(0, true);
    // zygote.state.set(1, true);

    let mut gb = GraphBuilder::new(network, zygote);
    println!("{:#?}", gb);

    for _ in 0..5 {
        gb.next();
    }
    println!("{:#?}", gb);

    gb.write_dot(&mut File::create("example1.dot").unwrap()).unwrap();

    let node_graph = gb.into_node_graph();
    node_graph.write_dot(&mut File::create("example1_node.dot").unwrap()).unwrap();
    let g = node_graph.into_structured_graph(1);
    println!("g: {:?}", g);
    g.write_dot(&mut File::create("example1_struct.dot").unwrap()).unwrap();
}
<|endoftext|>