<commit_before>mod render;

extern crate piston;
extern crate graphics;
extern crate wrapped2d;
extern crate rand;
extern crate cgmath;

#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate genmesh;

use std::time::SystemTime;
use rand::Rng;

use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use piston::input::Input::*;

use gfx::Device;
use gfx::traits::FactoryExt;

use cgmath::{Point3, Vector3, Matrix4, EuclideanVector};
use cgmath::{Transform, AffineMatrix3};
use genmesh::generators::SphereUV;
use genmesh::{Triangulate, MapToVertices, Vertices};

use wrapped2d::b2;
use std::f64::consts;

pub struct Viewport {
	width: u32,
	height: u32,
	ratio: f32,
	scale: f32,
}

impl Viewport {
	fn rect(w: u32, h: u32, scale: f32) -> Viewport {
		Viewport {
			width: w,
			height: h,
			ratio: (w as f32 / h as f32),
			scale: scale,
		}
	}

	fn to_world(&self, x: u32, y: u32) -> (f32, f32) {
		let dx = self.width as f32 / self.scale;
		let tx = (x as f32 - (self.width as f32 * 0.5)) / dx;
		let ty = ((self.height as f32 * 0.5) - y as f32) / dx;
		(tx, ty)
	}
}

pub struct InputState {
	left_button_pressed: bool,
	mouse_position: b2::Vec2,
}

use render::VertexPosNormal as Vertex;
use render::ColorFormat;
use render::DepthFormat;

const QUAD: [Vertex; 6] = [Vertex {
	                           pos: [-1.0, -1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [0.0, 0.0],
                           },
                           Vertex {
	                           pos: [1.0, -1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [1.0, 0.0],
                           },
                           Vertex {
	                           pos: [1.0, 1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [1.0, 1.0],
                           },
                           Vertex {
	                           pos: [-1.0, -1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [0.0, 0.0],
                           },
                           Vertex {
	                           pos: [-1.0, 1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [0.0, 1.0],
                           },
                           Vertex {
	                           pos: [1.0, 1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [1.0, 1.0],
                           }];

fn new_ball(world: &mut b2::World, pos: b2::Vec2) {
	let mut rng = rand::thread_rng();
	let radius: f32 = (rng.gen::<f32>() * 1.0) + 1.0;

	let mut circle_shape = b2::CircleShape::new();
	circle_shape.set_radius(radius);

	let mut f_def = b2::FixtureDef::new();
	f_def.density = (rng.gen::<f32>() * 1.0) + 1.0;
	f_def.restitution = 0.2;
	f_def.friction = 0.3;

	let mut b_def = b2::BodyDef::new();
	b_def.body_type = b2::BodyType::Dynamic;
	b_def.position = pos;
	let handle = world.create_body(&b_def);
	world.get_body_mut(handle)
		.create_fixture(&circle_shape, &mut f_def);
}
struct App {
	viewport: Viewport,
	input_state: InputState,
	world: b2::World,
}

impl App {
	fn on_click(&mut self, btn: glutin::MouseButton, pos: b2::Vec2) {
		match btn {
			glutin::MouseButton::Left => {
				self.input_state.left_button_pressed = true;
				new_ball(&mut self.world, pos);
			}
			_ => (),
		}
	}

	fn on_drag(&mut self, pos: b2::Vec2) {
		new_ball(&mut self.world, pos);
	}

	fn on_release(&mut self, btn: glutin::MouseButton, _: b2::Vec2) {
		match btn {
			glutin::MouseButton::Left => {
				self.input_state.left_button_pressed = false;
			}
			_ => (),
		}
	}

	fn mouse_input(&mut self, e: glutin::Event) {
		match e {
			glutin::Event::MouseInput(glutin::ElementState::Released, b) => {
				let pos = self.input_state.mouse_position;
				self.on_release(b, pos);
			}
			glutin::Event::MouseInput(glutin::ElementState::Pressed, b) => {
				let pos = self.input_state.mouse_position;
				self.on_click(b, pos);
			}
			glutin::Event::MouseMoved(x, y) => {
				fn transform_pos(viewport: &Viewport, x: u32, y: u32) -> b2::Vec2 {
					let (tx, ty) = viewport.to_world(x, y);
					return b2::Vec2 { x: tx, y: ty };
				}
				let pos = transform_pos(&self.viewport, x as u32, y as u32);
				self.input_state.mouse_position = pos;
				if self.input_state.left_button_pressed {
					self.on_drag(pos);
				}
			}
			_ => (),
		}
	}

	fn on_resize(&mut self, width: u32, height: u32) {
		self.viewport = Viewport::rect(width, height, self.viewport.scale);
	}

	fn render<R: gfx::Resources, C: gfx::CommandBuffer<R>>(&self,
	                                                       renderer: &render::DrawShaded<R>,
	                                                       mut encoder: &mut gfx::Encoder<R, C>,
	                                                       vertices: &gfx::handle::Buffer<R, Vertex>,
	                                                       indices: &gfx::Slice<R>,
	                                                       color: &gfx::handle::RenderTargetView<R, ColorFormat>,
	                                                       depth: &gfx::handle::DepthStencilView<R, DepthFormat>) {
		for (_, b) in self.world.bodies() {
			let body = b.borrow();
			let position = (*body).position();
			let angle = (*body).angle() as f32;
			use cgmath::Rotation3;
			let body_rot = Matrix4::from(cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(),
			                                                                 cgmath::rad(angle)));
			let body_trans = Matrix4::from_translation(cgmath::Vector3::new(position.x, position.y, 0.0));

			for (_, f) in body.fixtures() {
				let fixture = f.borrow();
				let shape = (*fixture).shape();
				let density = (*fixture).density();

				match *shape {
					b2::UnknownShape::Circle(ref s) => {
						let p = s.position();
						let r = s.radius() as f32;

						let fixture_scale = Matrix4::from_scale(r);
						let fixture_trans = Matrix4::from_translation(cgmath::Vector3::new(p.x, p.y, 0.0));
						let transform = body_trans * body_rot * fixture_trans * fixture_scale;

						renderer.draw(&mut encoder,
						              &vertices,
						              &indices,
						              &transform.into(),
						              &color,
						              &depth);
					}
					b2::UnknownShape::Polygon(ref s) => {
						// TODO: need to draw fill poly
					}
					_ => (),
				}
			}
		}

	}

	fn update(&mut self, dt: f32) {
		let world = &mut self.world;
		world.step(dt, 8, 3);
		const MAX_RADIUS: f32 = 5.0;
		let (_, edge) = self.viewport.to_world(0, self.viewport.height);
		let mut v = Vec::new();
		for (h, b) in world.bodies() {
			let body = b.borrow();
			let position = (*body).position();
			if position.y < (edge - MAX_RADIUS) {
				v.push(h);
			}
		}
		for h in v {
			world.destroy_body(h);
		}
	}
}

fn new_world() -> b2::World {
	let mut world = b2::World::new(&b2::Vec2 { x: 0.0, y: -9.8 });

	let mut b_def = b2::BodyDef::new();
	b_def.body_type = b2::BodyType::Static;
	b_def.position = b2::Vec2 { x: 0.0, y: -20.0 };

	let mut ground_box = b2::PolygonShape::new();
	{
		ground_box.set_as_box(20.0, 1.0);
		let ground_handle = world.create_body(&b_def);
		let ground = &mut world.get_body_mut(ground_handle);
		ground.create_fast_fixture(&ground_box, 0.);

		ground_box.set_as_oriented_box(1.0,
		                               5.0,
		                               &b2::Vec2 { x: 21.0, y: 5.0 },
		                               (-consts::FRAC_PI_8) as f32);
		ground.create_fast_fixture(&ground_box, 0.);

		ground_box.set_as_oriented_box(1.0,
		                               5.0,
		                               &b2::Vec2 { x: -21.0, y: 5.0 },
		                               (consts::FRAC_PI_8) as f32);
		ground.create_fast_fixture(&ground_box, 0.);
	}
	world
}

fn main() {
	const WIDTH: u32 = 1280;
	const HEIGHT: u32 = 720;

	let builder = glutin::WindowBuilder::new()
		.with_title("Box2d + GFX".to_string())
		.with_dimensions(WIDTH, HEIGHT)
		.with_vsync();

	let (window, mut device, mut factory, mut main_color, mut main_depth) =
		gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
	let (w, h, _, _) = main_color.get_dimensions();

	let renderer = render::DrawShaded::new(&mut factory);

	// Create a new game and run it.
	let mut app = App {
		viewport: Viewport::rect(w as u32, h as u32, 100.0),
		input_state: InputState {
			left_button_pressed: false,
			mouse_position: b2::Vec2 { x: 0.0, y: 0.0 },
		},
		world: new_world(),
	};

	let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&QUAD, ());

	let lights: Vec<render::PointLight> = vec![render::PointLight {
		                                           propagation: [0.3, 0.5, 0.4, 0.0],
		                                           center: [-15.0, -5.0, 1.0, 1.0],
		                                           color: [1.0, 0.0, 0.0, 1.0],
	                                           },
	                                           render::PointLight {
		                                           propagation: [0.5, 0.5, 0.5, 0.0],
		                                           center: [10.0, 10.0, 2.0, 1.0],
		                                           color: [0.9, 0.9, 0.8, 1.0],
	                                           }];

	let mut elapsed = 0.0f32;
	let mut start = SystemTime::now();
	let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
	'main: loop {

		for event in window.poll_events() {
			match event {
				e @ glutin::Event::MouseMoved(_, _) |
				e @ glutin::Event::MouseInput(_, _) => app.mouse_input(e),

				glutin::Event::Resized(new_width, new_height) => {
					gfx_window_glutin::update_views(&window, &mut main_color, &mut main_depth);
					app.on_resize(new_width, new_height);
				}
				glutin::Event::Closed => break 'main,
				_ => {}
			}
		}

		let camera = render::Camera::ortho(cgmath::Point2::new(0.0f32, 0.0),
		                                   app.viewport.scale,
		                                   app.viewport.ratio);

		renderer.setup(&mut encoder, &camera, &lights);

		// update
		match start.elapsed() {
			Ok(dt) => {
				let frame = (dt.as_secs() as f32) + (dt.subsec_nanos() as f32) * 1e-9;
				app.update(frame);
				elapsed += frame;
			}
			Err(_) => {}
		}

		// draw a frame
		renderer.begin_frame(&mut encoder, &main_color, &main_depth);

		app.render(&renderer,
		           &mut encoder,
		           &vertex_buffer,
		           &slice,
		           &main_color,
		           &main_depth);

		renderer.end_frame(&mut encoder, &mut device);
		window.swap_buffers().unwrap();
		renderer.cleanup(&mut device);

		start = SystemTime::now();
	}

}
<commit_msg>Bigger bubbles<commit_after>mod render;

extern crate piston;
extern crate graphics;
extern crate wrapped2d;
extern crate rand;
extern crate cgmath;

#[macro_use]
extern crate gfx;
extern crate gfx_device_gl;
extern crate gfx_window_glutin;
extern crate glutin;
extern crate genmesh;

use std::time::SystemTime;
use rand::Rng;

use piston::window::WindowSettings;
use piston::event_loop::*;
use piston::input::*;
use piston::input::Input::*;

use gfx::Device;
use gfx::traits::FactoryExt;

use cgmath::{Point3, Vector3, Matrix4, EuclideanVector};
use cgmath::{Transform, AffineMatrix3};
use genmesh::generators::SphereUV;
use genmesh::{Triangulate, MapToVertices, Vertices};

use wrapped2d::b2;
use std::f64::consts;

pub struct Viewport {
	width: u32,
	height: u32,
	ratio: f32,
	scale: f32,
}

impl Viewport {
	fn rect(w: u32, h: u32, scale: f32) -> Viewport {
		Viewport {
			width: w,
			height: h,
			ratio: (w as f32 / h as f32),
			scale: scale,
		}
	}

	fn to_world(&self, x: u32, y: u32) -> (f32, f32) {
		let dx = self.width as f32 / self.scale;
		let tx = (x as f32 - (self.width as f32 * 0.5)) / dx;
		let ty = ((self.height as f32 * 0.5) - y as f32) / dx;
		(tx, ty)
	}
}

pub struct InputState {
	left_button_pressed: bool,
	mouse_position: b2::Vec2,
}

use render::VertexPosNormal as Vertex;
use render::ColorFormat;
use render::DepthFormat;

const QUAD: [Vertex; 6] = [Vertex {
	                           pos: [-1.0, -1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [0.0, 0.0],
                           },
                           Vertex {
	                           pos: [1.0, -1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [1.0, 0.0],
                           },
                           Vertex {
	                           pos: [1.0, 1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [1.0, 1.0],
                           },
                           Vertex {
	                           pos: [-1.0, -1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [0.0, 0.0],
                           },
                           Vertex {
	                           pos: [-1.0, 1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [0.0, 1.0],
                           },
                           Vertex {
	                           pos: [1.0, 1.0, 0.0],
	                           normal: [0.0, 0.0, 1.0],
	                           tangent: [1.0, 0.0, 0.0],
	                           tex_coord: [1.0, 1.0],
                           }];

fn new_ball(world: &mut b2::World, pos: b2::Vec2) {
	let mut rng = rand::thread_rng();
	let radius: f32 = (rng.gen::<f32>() * 1.0) + 1.0;

	let mut circle_shape = b2::CircleShape::new();
	circle_shape.set_radius(radius);

	let mut f_def = b2::FixtureDef::new();
	f_def.density = (rng.gen::<f32>() * 1.0) + 1.0;
	f_def.restitution = 0.2;
	f_def.friction = 0.3;

	let mut b_def = b2::BodyDef::new();
	b_def.body_type = b2::BodyType::Dynamic;
	b_def.position = pos;
	let handle = world.create_body(&b_def);
	world.get_body_mut(handle)
		.create_fixture(&circle_shape, &mut f_def);
}
struct App {
	viewport: Viewport,
	input_state: InputState,
	world: b2::World,
}

impl App {
	fn on_click(&mut self, btn: glutin::MouseButton, pos: b2::Vec2) {
		match btn {
			glutin::MouseButton::Left => {
				self.input_state.left_button_pressed = true;
				new_ball(&mut self.world, pos);
			}
			_ => (),
		}
	}

	fn on_drag(&mut self, pos: b2::Vec2) {
		new_ball(&mut self.world, pos);
	}

	fn on_release(&mut self, btn: glutin::MouseButton, _: b2::Vec2) {
		match btn {
			glutin::MouseButton::Left => {
				self.input_state.left_button_pressed = false;
			}
			_ => (),
		}
	}

	fn mouse_input(&mut self, e: glutin::Event) {
		match e {
			glutin::Event::MouseInput(glutin::ElementState::Released, b) => {
				let pos = self.input_state.mouse_position;
				self.on_release(b, pos);
			}
			glutin::Event::MouseInput(glutin::ElementState::Pressed, b) => {
				let pos = self.input_state.mouse_position;
				self.on_click(b, pos);
			}
			glutin::Event::MouseMoved(x, y) => {
				fn transform_pos(viewport: &Viewport, x: u32, y: u32) -> b2::Vec2 {
					let (tx, ty) = viewport.to_world(x, y);
					return b2::Vec2 { x: tx, y: ty };
				}
				let pos = transform_pos(&self.viewport, x as u32, y as u32);
				self.input_state.mouse_position = pos;
				if self.input_state.left_button_pressed {
					self.on_drag(pos);
				}
			}
			_ => (),
		}
	}

	fn on_resize(&mut self, width: u32, height: u32) {
		self.viewport = Viewport::rect(width, height, self.viewport.scale);
	}

	fn render<R: gfx::Resources, C: gfx::CommandBuffer<R>>(&self,
	                                                       renderer: &render::DrawShaded<R>,
	                                                       mut encoder: &mut gfx::Encoder<R, C>,
	                                                       vertices: &gfx::handle::Buffer<R, Vertex>,
	                                                       indices: &gfx::Slice<R>,
	                                                       color: &gfx::handle::RenderTargetView<R, ColorFormat>,
	                                                       depth: &gfx::handle::DepthStencilView<R, DepthFormat>) {
		for (_, b) in self.world.bodies() {
			let body = b.borrow();
			let position = (*body).position();
			let angle = (*body).angle() as f32;
			use cgmath::Rotation3;
			let body_rot = Matrix4::from(cgmath::Quaternion::from_axis_angle(cgmath::Vector3::unit_z(),
			                                                                 cgmath::rad(angle)));
			let body_trans = Matrix4::from_translation(cgmath::Vector3::new(position.x, position.y, 0.0));

			for (_, f) in body.fixtures() {
				let fixture = f.borrow();
				let shape = (*fixture).shape();
				let density = (*fixture).density();

				match *shape {
					b2::UnknownShape::Circle(ref s) => {
						let p = s.position();
						let r = s.radius() as f32;

						let fixture_scale = Matrix4::from_scale(r);
						let fixture_trans = Matrix4::from_translation(cgmath::Vector3::new(p.x, p.y, 0.0));
						let transform = body_trans * body_rot * fixture_trans * fixture_scale;

						renderer.draw(&mut encoder,
						              &vertices,
						              &indices,
						              &transform.into(),
						              &color,
						              &depth);
					}
					b2::UnknownShape::Polygon(ref s) => {
						// TODO: need to draw fill poly
					}
					_ => (),
				}
			}
		}

	}

	fn update(&mut self, dt: f32) {
		let world = &mut self.world;
		world.step(dt, 8, 3);
		const MAX_RADIUS: f32 = 5.0;
		let (_, edge) = self.viewport.to_world(0, self.viewport.height);
		let mut v = Vec::new();
		for (h, b) in world.bodies() {
			let body = b.borrow();
			let position = (*body).position();
			if position.y < (edge - MAX_RADIUS) {
				v.push(h);
			}
		}
		for h in v {
			world.destroy_body(h);
		}
	}
}

fn new_world() -> b2::World {
	let mut world = b2::World::new(&b2::Vec2 { x: 0.0, y: -9.8 });

	let mut b_def = b2::BodyDef::new();
	b_def.body_type = b2::BodyType::Static;
	b_def.position = b2::Vec2 { x: 0.0, y: -20.0 };

	let mut ground_box = b2::PolygonShape::new();
	{
		ground_box.set_as_box(20.0, 1.0);
		let ground_handle = world.create_body(&b_def);
		let ground = &mut world.get_body_mut(ground_handle);
		ground.create_fast_fixture(&ground_box, 0.);

		ground_box.set_as_oriented_box(1.0,
		                               5.0,
		                               &b2::Vec2 { x: 21.0, y: 5.0 },
		                               (-consts::FRAC_PI_8) as f32);
		ground.create_fast_fixture(&ground_box, 0.);

		ground_box.set_as_oriented_box(1.0,
		                               5.0,
		                               &b2::Vec2 { x: -21.0, y: 5.0 },
		                               (consts::FRAC_PI_8) as f32);
		ground.create_fast_fixture(&ground_box, 0.);
	}
	world
}

fn main() {
	const WIDTH: u32 = 1280;
	const HEIGHT: u32 = 720;

	let builder = glutin::WindowBuilder::new()
		.with_title("Box2d + GFX".to_string())
		.with_dimensions(WIDTH, HEIGHT)
		.with_vsync();

	let (window, mut device, mut factory, mut main_color, mut main_depth) =
		gfx_window_glutin::init::<ColorFormat, DepthFormat>(builder);
	let (w, h, _, _) = main_color.get_dimensions();

	let renderer = render::DrawShaded::new(&mut factory);

	// Create a new game and run it.
	let mut app = App {
		viewport: Viewport::rect(w as u32, h as u32, 50.0),
		input_state: InputState {
			left_button_pressed: false,
			mouse_position: b2::Vec2 { x: 0.0, y: 0.0 },
		},
		world: new_world(),
	};

	let (vertex_buffer, slice) = factory.create_vertex_buffer_with_slice(&QUAD, ());

	let lights: Vec<render::PointLight> = vec![render::PointLight {
		                                           propagation: [0.3, 0.5, 0.4, 0.0],
		                                           center: [-15.0, -5.0, 1.0, 1.0],
		                                           color: [1.0, 0.0, 0.0, 1.0],
	                                           },
	                                           render::PointLight {
		                                           propagation: [0.5, 0.5, 0.5, 0.0],
		                                           center: [10.0, 10.0, 2.0, 1.0],
		                                           color: [0.9, 0.9, 0.8, 1.0],
	                                           }];

	let mut elapsed = 0.0f32;
	let mut start = SystemTime::now();
	let mut encoder: gfx::Encoder<_, _> = factory.create_command_buffer().into();
	'main: loop {

		for event in window.poll_events() {
			match event {
				e @ glutin::Event::MouseMoved(_, _) |
				e @ glutin::Event::MouseInput(_, _) => app.mouse_input(e),

				glutin::Event::Resized(new_width, new_height) => {
					gfx_window_glutin::update_views(&window, &mut main_color, &mut main_depth);
					app.on_resize(new_width, new_height);
				}
				glutin::Event::Closed => break 'main,
				_ => {}
			}
		}

		let camera = render::Camera::ortho(cgmath::Point2::new(0.0f32, 0.0),
		                                   app.viewport.scale,
		                                   app.viewport.ratio);

		renderer.setup(&mut encoder, &camera, &lights);

		// update
		match start.elapsed() {
			Ok(dt) => {
				let frame = (dt.as_secs() as f32) + (dt.subsec_nanos() as f32) * 1e-9;
				app.update(frame);
				elapsed += frame;
			}
			Err(_) => {}
		}

		// draw a frame
		renderer.begin_frame(&mut encoder, &main_color, &main_depth);

		app.render(&renderer,
		           &mut encoder,
		           &vertex_buffer,
		           &slice,
		           &main_color,
		           &main_depth);

		renderer.end_frame(&mut encoder, &mut device);
		window.swap_buffers().unwrap();
		renderer.cleanup(&mut device);

		start = SystemTime::now();
	}

}
<|endoftext|>


<commit_before>#![allow(dead_code)]
extern crate rand;
use rand::Rng;
use std::collections::*;

type Player = [i8; 7];

#[derive(Clone, Debug, Hash, PartialEq, Eq)]
struct Game {
    p: [Player; 2],
    t: i8,
}

fn new_player() -> Player {
    [4,4,4,4,4,4,0]
}

#[derive(Debug, PartialEq, Clone)]
enum State {
    InProgress,
    Draw,
    Win(i8),
}

impl Game {
    fn new() -> Game {
        Game{p: [new_player(), new_player()], t: 0}
    }

    fn print(&self) {
        print!("|{:2}|", self.p[1][6]);
        for i in 0..6 {
            print!(" [{:2}]", self.p[1][5 - i])
        }
        print!(" /--\\");
        if self.t == 1 {
            print!(" <-- turn");
        }
        println!();
        print!("\\--/ ");
        for i in 0..6 {
            print!("[{:2}] ", self.p[0][i])
        }
        print!("|{:2}|", self.p[0][6]);
        if self.t == 0 {
            print!(" <-- turn");
        }
        println!();
    }

    fn state(&self) -> State {
        let p0full: i8 = self.p[0].iter().sum();
        let p1full: i8 = self.p[1].iter().sum();
        let p0 = p0full - self.p[0][6];
        let p1 = p1full - self.p[1][6];
        if p0 != 0 && p1 != 0 {
            State::InProgress
        } else {
            if p0full < p1full {
                State::Win(1)
            } else if p0full > p1full {
                State::Win(0)
            } else {
                State::Draw
            }
        }
    }

    fn step(&self, s: usize) -> Option<Game> {
        if s >= 6 { panic!("wrong start index"); }
        let mut n: Game = self.clone();
        let mut leftover = n.p[n.t as usize][s];
        if leftover == 0 { return None; }

        let mut side: usize = n.t as usize;
        let mut pos: usize = s + 1;
        n.p[side][s] = 0;

        loop {
            n.p[side][pos] += 1;
            leftover -= 1;
            if leftover == 0 { break; }
            if (pos == 5 && side != self.t as usize) || (pos == 6) {
                // pos == 6 => we have reached the super bucket and have to switch sides
                // pos == 5 => we have reached opponents 0 bucket and have to return home
                side = 1 - side;
                pos = 0;
            } else {
                pos += 1;
            }
        }

        if pos < 6 { // if we have reached the super bucket, we don't give up turn
            // check for take-over
            if side == self.t as usize && n.p[side][pos] == 1 {
                let opp = 5 - pos;
                n.p[side][6] += n.p[1 - side][opp];
                n.p[1 - side][opp] = 0;
            }
            n.t = 1 - n.t; // switch the turn
        }
        Some(n)
    }

    fn possible(&self) -> Vec<usize> {
        let side = self.t as usize;
        let mut res: Vec<usize> = Vec::new();
        for i in 0..6 {
            if self.p[side][i] != 0 {
                res.push(i);
            }
        }
        res
    }
}

// next computes all the posible games for the next turn
fn next(g: &Game) -> Vec<Game> {
    let mut res: Vec<Game> = Vec::new();
    let turn = g.t;
    for i in 0..6 {
        if let Some(cand) = g.step(i) {
            if cand.t == turn && cand.state() == State::InProgress {
                for elem in next(&cand).into_iter() {
                    res.push(elem);
                }
            } else {
                res.push(cand);
            }
        }
    }
    res
}

fn show_first_row() {
    let g = Game::new();
    g.print();
    println!("{:?}", g.state());
    for t in next(&g).into_iter() {
        t.print();
    }
}

fn play_random_game() {
    let mut g = Game::new();
    let mut rng = rand::thread_rng();
    loop {
        println!("-----------------------------");
        println!("{:?}", g);
        g.print();
        let state = g.state();
        if state != State::InProgress {
            println!("{:?}", state);
            return;
        }

        let possibilities = next(&g);
        let n = possibilities.len();
        g = possibilities[rng.gen_range(0, n)].clone();
    }
}

fn find_outcome(g: &Game, cache: &mut HashMap<Game, (State, i8)>) -> (State, i8) {
    let gstate = g.state();
    if gstate != State::InProgress {
        return (gstate, -1);
    }
    if let Some(ans) = cache.get(&g) {
        return ans.clone();
    }

    let player = g.t;
    let mut best = State::Win(1 - player); // initialize the best with worst-case scenario -- winning of the other player
    let mut step: i8 = -1;

    for i in 0..6 {
        if let Some(ng) = g.step(i) {
            let outcome = find_outcome(&ng, cache);
            match outcome.0 {
                State::InProgress => panic!(),
                State::Draw => {
                    if best != State::Draw {
                        best = State::Draw;
                        step = i as i8;
                    }
                },
                State::Win(p) => {
                    if p == player { // that's the best outcome
                        best = outcome.0;
                        step = i as i8;
                        break; // no need to search further
                    } else {
                        // that's the worst outcome
                        if best != State::Draw {
                            step = i as i8; // only update the step
                        }
                    }
                }
            }
        }
    }

    debug_assert!(step >= 0, "best case must always be found");

    let ans = (best, step);
    cache.insert(g.clone(), ans.clone());
    ans
}

fn experiment_with_outcomes() {
    let mut g = Game { p: [[3, 5, 2, 1, 6, 1, 10], [4, 0, 2, 2, 2, 1, 9]], t: 0 };
    let mut cache: HashMap<Game, (State, i8)> = HashMap::with_capacity(10_000_000);
    let mut outcome = find_outcome(&g, &mut cache);
    println!("Outcome: {:?}", outcome);
    println!("Positions in cache: {}", cache.len());

    loop {
        g.print();
        if g.state() == State::InProgress {
            g = g.step(outcome.1 as usize).unwrap();
            outcome = find_outcome(&g, &mut cache);
        } else {
            break;
        }
    }
}

fn main() {
    //play_random_game();
    experiment_with_outcomes();
}
<commit_msg>a step towards map of knowledge<commit_after>#![allow(dead_code)]
extern crate rand;
use rand::Rng;
use std::collections::*;

type Player = [i8; 7];

#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
struct Game {
    p: [Player; 2],
    t: i8,
}

fn new_player() -> Player {
//  [4,4,4,4,4,4,0]
    [2,2,2,2,2,2,0]
}

#[derive(Debug, PartialEq, Clone)]
enum State {
    InProgress,
    Draw,
    Win(i8),
}

impl Game {
    fn new() -> Game {
        Game{p: [new_player(), new_player()], t: 0}
    }

    fn print(&self) {
        print!("|{:2}|", self.p[1][6]);
        for i in 0..6 {
            print!(" [{:2}]", self.p[1][5 - i])
        }
        print!(" /--\\");
        if self.t == 1 {
            print!(" <-- turn");
        }
        println!();
        print!("\\--/ ");
        for i in 0..6 {
            print!("[{:2}] ", self.p[0][i])
        }
        print!("|{:2}|", self.p[0][6]);
        if self.t == 0 {
            print!(" <-- turn");
        }
        println!();
    }

    fn state(&self) -> State {
        let p0full: i8 = self.p[0].iter().sum();
        let p1full: i8 = self.p[1].iter().sum();
        let p0 = p0full - self.p[0][6];
        let p1 = p1full - self.p[1][6];
        if p0 != 0 && p1 != 0 {
            State::InProgress
        } else {
            if p0full < p1full {
                State::Win(1)
            } else if p0full > p1full {
                State::Win(0)
            } else {
                State::Draw
            }
        }
    }

    fn step(&self, s: usize) -> Option<Game> {
        if s >= 6 { panic!("wrong start index"); }
        let mut n: Game = self.clone();
        let mut leftover = n.p[n.t as usize][s];
        if leftover == 0 { return None; }

        let mut side: usize = n.t as usize;
        let mut pos: usize = s + 1;
        n.p[side][s] = 0;

        loop {
            n.p[side][pos] += 1;
            leftover -= 1;
            if leftover == 0 { break; }
            if (pos == 5 && side != self.t as usize) || (pos == 6) {
                // pos == 6 => we have reached the super bucket and have to switch sides
                // pos == 5 => we have reached opponents 0 bucket and have to return home
                side = 1 - side;
                pos = 0;
            } else {
                pos += 1;
            }
        }

        if pos < 6 { // if we have reached the super bucket, we don't give up turn
            // check for take-over
            if side == self.t as usize && n.p[side][pos] == 1 {
                let opp = 5 - pos;
                n.p[side][6] += n.p[1 - side][opp];
                n.p[1 - side][opp] = 0;
            }
            n.t = 1 - n.t; // switch the turn
        }
        Some(n)
    }

    fn possible(&self) -> Vec<usize> {
        let side = self.t as usize;
        let mut res: Vec<usize> = Vec::new();
        for i in 0..6 {
            if self.p[side][i] != 0 {
                res.push(i);
            }
        }
        res
    }
}

// next computes all the posible games for the next turn
fn next(g: &Game) -> Vec<Game> {
    let mut res: Vec<Game> = Vec::new();
    let turn = g.t;
    for i in 0..6 {
        if let Some(cand) = g.step(i) {
            if cand.t == turn && cand.state() == State::InProgress {
                for elem in next(&cand).into_iter() {
                    res.push(elem);
                }
            } else {
                res.push(cand);
            }
        }
    }
    res
}

fn show_first_row() {
    let g = Game::new();
    g.print();
    println!("{:?}", g.state());
    for t in next(&g).into_iter() {
        t.print();
    }
}

fn play_random_game() {
    let mut g = Game::new();
    let mut rng = rand::thread_rng();
    loop {
        println!("-----------------------------");
        println!("{:?}", g);
        g.print();
        let state = g.state();
        if state != State::InProgress {
            println!("{:?}", state);
            return;
        }

        let possibilities = next(&g);
        let n = possibilities.len();
        g = possibilities[rng.gen_range(0, n)].clone();
    }
}

fn find_outcome(g: &Game, cache: &mut HashMap<Game, (State, i8)>) -> (State, i8) {
    let gstate = g.state();
    if gstate != State::InProgress {
        return (gstate, -1);
    }
    if let Some(ans) = cache.get(&g) {
        return ans.clone();
    }

    let player = g.t;
    let mut best = State::Win(1 - player); // initialize the best with worst-case scenario -- winning of the other player
    let mut step: i8 = -1;

    for i in 0..6 {
        if let Some(ng) = g.step(i) {
            let outcome = find_outcome(&ng, cache);
            match outcome.0 {
                State::InProgress => panic!(),
                State::Draw => {
                    if best != State::Draw {
                        best = State::Draw;
                        step = i as i8;
                    }
                },
                State::Win(p) => {
                    if p == player { // that's the best outcome
                        best = outcome.0;
                        step = i as i8;
                        break; // no need to search further
                    } else {
                        // that's the worst outcome
                        if best != State::Draw {
                            step = i as i8; // only update the step
                        }
                    }
                }
            }
        }
    }

    debug_assert!(step >= 0, "best case must always be found");

    let ans = (best, step);
    cache.insert(g.clone(), ans.clone());
    ans
}

fn play_random_game2() {
    let mut rng = rand::thread_rng();
    let mut games = Vec::new();
    let mut g = Game::new();
    loop {
        println!("-----------------------------");
        println!("{:?}", g);
        g.print();
        games.push(g);
        let state = g.state();
        if state != State::InProgress {
            println!("{:?}", state);
            break;
        }

        let possibilities = next(&g);
        let n = possibilities.len();
        g = possibilities[rng.gen_range(0, n)].clone();
    }
    println!("---  ---  ---  ---  ---  ---  ---  ---  ---  ---");
    let mut cache: HashMap<Game, (State, i8)> = HashMap::with_capacity(2_000_000);
    while cache.len() < 700_000 {
        if let Some(last) = games.pop() {
            let outcome = find_outcome(&last, &mut cache);
            last.print();
            println!("Outcome: {:?}", outcome);
            println!("Positions in cache: {}", cache.len());
        }
        else {
            println!("---  ---  ---  ---  ---  ---  ---  ---  ---  ---");
            println!("GAME SOLVED");
            println!("---  ---  ---  ---  ---  ---  ---  ---  ---  ---");
            return;
        }
    }
}

fn experiment_with_outcomes() {
    let mut g = Game { p: [[0, 0, 0, 1, 2, 1, 20], [0, 0, 2, 1, 1, 0, 20]], t: 0 };
    let mut cache: HashMap<Game, (State, i8)> = HashMap::with_capacity(2_000_000);
    let mut outcome = find_outcome(&g, &mut cache);
    println!("Outcome: {:?}", outcome);
    println!("Positions in cache: {}", cache.len());

    loop {
        g.print();
        if g.state() == State::InProgress {
            g = g.step(outcome.1 as usize).unwrap();
            outcome = find_outcome(&g, &mut cache);
        } else {
            break;
        }
    }
}

fn main() {
    play_random_game2();
    //experiment_with_outcomes();
}
<|endoftext|>


<commit_before>extern crate rand;
mod game;
use game::{Game, State};
mod user_interface;
use user_interface::UserInterface;
mod dictionary;
use dictionary::Dict;
mod image;
use image::RewardingScheme;

use std::env;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;

const COMMANDLINE_HELP: &str = "\
Hangman is a paper and pencil guessing game for two or more players.  One player
thinks of a word, phrase or sentence and the other tries to guess it by
suggesting letters or numbers, within a certain number of guesses. In this
version for children the computer selects a word, phrase or sentence randomly
out of a word-list defined in a configuration file. In the course of the game
Ascii-Art images - designed for children - are progressively disclosed.

===================================
-----------------------------------
HANGMAN GAME
         ,.
        (_|,.
       ,' /, )_______
    __j o``-'        `
   (\")
    `-j                |
      `-._(           /
         |_\\  |--^.  /
        /_]'|_| /_)_/
           /_]'  /_]'

Lives:  1       Last guess: 3

 g o o _ _ l _ _ k

Type a letter then type [Enter]:
-----------------------------------
===================================

 Usage: hangman [FILE]...
        hangman (-c|--help)
        hangman

`[FILE]` are configuration files containing word-lists and optionally Ascii-Art
images.

When no `[FILE]` argument is given, `[FILE]` defaults to 'hangman-words.txt'. In
case no `[FILE]` is found, a template configuration file 'hangman-words.txt' is
written into the current working directory. Multiple `[FILE]`s are concatted.

`[FILE]` is an Ascii file containing 4 different line-types:

- lines starting with `#` is ignored.

- lines starting with `|` are part of an optional Ascii-Art image shown
  progressively in the course of the game. If not defined here, built in
  Ascii-Art images are used instead.

- lines starting with `:` are game modifier. They change the logic how the image
  is progressively disclosed:
   `:success-rewarding`       Every guessed character shows a bit more of the
                              image. This mode is default.
   `:traditional-rewarding`   Every lost live discloses a bit more of the
                  image. Choose this mode together with a
                              traditional gallows image (not built in).

- lines starting with `-` are _guessing strings_. At the beginning of the game
  one line is randomly chosen and all characters are hidden.  In
  order to give additional hints it is possible to enclose some characters with
  `+*+`.  These words are then displayed in clear. For example a config line:
  `+- Guess *me*+` is shown in the game as: `_ _ _ _ _ _ m e`.

";

const LIVES: u8 = 7;
const PATHSTR: &str = "hangman-words.txt";
const OFFSET: (usize, usize) = (1, 1);

const CONF_TEMPLATE: &str = "\
### This is a sample word-list for the hangman game

### Sample word-list
#   ----------------
#
# Before every game one line is randomly chosen.
# Empty lines and lines starting with # are ignored.
# Lines with guessing strings must start with '-'.
# Words enclosed with * are not hidden when the game starts:
#   - *guess *me
# shows in the game:
#   g u e s s   _ _
#

- *guess* me
- hang*man*
- good luck

# Lines starting with ':' are game modifier. They change
# the logic how the image is progressively disclosed:
#   ':success-rewarding'       Every guessed character shows a bit more of the
#                              image. This mode is default.
#   ':traditional-rewarding'   Every lost live discloses a bit more of the
#                  image. Choose this mode together with a
#                              traditional gallows image (not built in).

### Sample custom image
#   -------------------
#
# Instead of built in images a word list can use a
# custom image. Lines starting with '|' are interpreted
# as image-lines. Delete '#' in the following lines to
# try out this feature.

#:traditional-rewarding
#|  ______
#|  |    |
#|  |    O
#|  |   /|\\
#|  |    |
#|  |   / \\
#|__|_____
#||      |___
#||_________|
";

const CONF_DEMO: &str = "- *Demo: add own words to config file and *start* again!*";

// ------------------ MAIN ---------------------------------------------

pub fn read_config(pathstr: &PathBuf) -> Result<String, io::Error> {
    let mut f = File::open(pathstr)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

pub fn write_config_template(pathstr: &PathBuf) -> Result<(), io::Error> {
    let mut file = File::create(&pathstr)?;
    file.write_all(CONF_TEMPLATE.as_bytes())?;
    Ok(())
}

fn main() {
    // SHOW HELP TEXT
    match env::args().nth(1) {
        Some(ref a) if a == "-h" || a == "--help" => {
            println!("{}", COMMANDLINE_HELP);
            return ();
        }
        Some(_) => {}
        None => {}
    };

    // READ CONFIG

    // Read all config files given on command line
    let mut conf_file_paths: Vec<PathBuf> = env::args().skip(1).map(|s| PathBuf::from(s)).collect();

    // if no conf_file_paths are given then use default config path
    if conf_file_paths.len() == 0 {
        conf_file_paths.push(PathBuf::from(PATHSTR))
    };

    // read and concat all config files given on command line
    let cwd = env::current_dir().unwrap();

    let mut config: String = String::new();
    for conf_file_path in &conf_file_paths {
        let path = conf_file_path;
        let c = match read_config(&path) {
            Ok(s) => s,
            Err(_) => {
                match write_config_template(&path) {
                    Ok(_) => {
                        println!(
                            "As no config-file :\n\
                             \t{:?}\n\
                             was found a template file is written in the \
                             current working directory.\n\
                             \t{:?}\n\n\nPress [Enter] to enter demo mode.",
                            path, cwd
                        );
                        // wait for [Enter] key
                        let input = &mut String::new();
                        io::stdin().read_line(input).unwrap();
                        CONF_DEMO.to_string()
                    }
                    Err(why) => {
                        println!(
                            "Couldn't write hangman template \
                             config-file:\n\t{:?}\n({})\n\n\
                             Current working directory is:\n\t{:?}\n\n\
                             Press [Enter] to enter demo mode.",
                            path,
                            Error::description(&why),
                            cwd
                        );
                        // wait for [Enter] key
                        let input = &mut String::new();
                        io::stdin().read_line(input).unwrap();
                        CONF_DEMO.to_string()
                    }
                }
            }
        };
        config.push_str(&c);
    }

    // INITIALISE GAME

    let mut ui = UserInterface::new(&config, OFFSET);

    let mut dict = Dict::new(&config);
    if dict.len() == 0 {
        println!(
            "No guessing words in config-file(s):\n\
             \t{:?}\n\
             were found. Current working directory is:\n\
             \t{:?}\n\n\nPress [Enter] to enter demo mode.",
            conf_file_paths, cwd
        );
        // wait for [Enter] key
        let input = &mut String::new();
        io::stdin().read_line(input).unwrap();
        dict = Dict::new(CONF_DEMO);
    };

    // PLAY

    'playing: loop {
        let mut game = Game::new(&(dict.get_random_word()), LIVES);
        let chars_to_guess = game.visible_chars();

        // The game loop
        let mut line_buffer = String::new();
        let reader = io::stdin();
        print!("\x1b[2J"); // clear screen
        'running_game: loop {
            if game.lives > 0 || ui.image.rewarding_scheme == RewardingScheme::UnhideWhenLostLife {
                ui.image.disclose(
                    (game.lives as usize, LIVES as usize),
                    (game.visible_chars(), chars_to_guess),
                );
            }
            ui.message = format!("{}", game);
            println!("{}", ui);

            match game.get_state() {
                State::Victory => {
                    println!("Congratulations! You won!");
                    break 'running_game;
                }
                State::Defeat => {
                    println!("Sorry, you lost! Better luck next time!");
                    break 'running_game;
                }
                _ => {}
            }

            print!("Type a letter then type [Enter]: ");
            io::stdout().flush().unwrap();

            // Read next char and send it
            line_buffer.clear();
            reader.read_line(&mut line_buffer).unwrap();

            game.guess(match line_buffer.chars().next() {
                Some(char_) => char_,
                None => continue 'running_game,
            });
        }

        print!("New game? Type [Y]es or [n]o: ");
        io::stdout().flush().unwrap();

        // Read next char
        line_buffer.clear();
        reader.read_line(&mut line_buffer).unwrap();
        println! {"(c) Jens Getreu, 2016."};

        match line_buffer.trim_end().chars().next() {
            Some(char_) if char_ == 'N' || char_ == 'n' => break 'playing,
            Some(_) => {}
            None => {}
        }
    }
}
<commit_msg>remove unneeded return value<commit_after>extern crate rand;
mod game;
use game::{Game, State};
mod user_interface;
use user_interface::UserInterface;
mod dictionary;
use dictionary::Dict;
mod image;
use image::RewardingScheme;

use std::env;
use std::error::Error;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::PathBuf;

const COMMANDLINE_HELP: &str = "\
Hangman is a paper and pencil guessing game for two or more players.  One player
thinks of a word, phrase or sentence and the other tries to guess it by
suggesting letters or numbers, within a certain number of guesses. In this
version for children the computer selects a word, phrase or sentence randomly
out of a word-list defined in a configuration file. In the course of the game
Ascii-Art images - designed for children - are progressively disclosed.

===================================
-----------------------------------
HANGMAN GAME
         ,.
        (_|,.
       ,' /, )_______
    __j o``-'        `
   (\")
    `-j                |
      `-._(           /
         |_\\  |--^.  /
        /_]'|_| /_)_/
           /_]'  /_]'

Lives:  1       Last guess: 3

 g o o _ _ l _ _ k

Type a letter then type [Enter]:
-----------------------------------
===================================

 Usage: hangman [FILE]...
        hangman (-c|--help)
        hangman

`[FILE]` are configuration files containing word-lists and optionally Ascii-Art
images.

When no `[FILE]` argument is given, `[FILE]` defaults to 'hangman-words.txt'. In
case no `[FILE]` is found, a template configuration file 'hangman-words.txt' is
written into the current working directory. Multiple `[FILE]`s are concatted.

`[FILE]` is an Ascii file containing 4 different line-types:

- lines starting with `#` is ignored.

- lines starting with `|` are part of an optional Ascii-Art image shown
  progressively in the course of the game. If not defined here, built in
  Ascii-Art images are used instead.

- lines starting with `:` are game modifier. They change the logic how the image
  is progressively disclosed:
   `:success-rewarding`       Every guessed character shows a bit more of the
                              image. This mode is default.
   `:traditional-rewarding`   Every lost live discloses a bit more of the
                  image. Choose this mode together with a
                              traditional gallows image (not built in).

- lines starting with `-` are _guessing strings_. At the beginning of the game
  one line is randomly chosen and all characters are hidden.  In
  order to give additional hints it is possible to enclose some characters with
  `+*+`.  These words are then displayed in clear. For example a config line:
  `+- Guess *me*+` is shown in the game as: `_ _ _ _ _ _ m e`.

";

const LIVES: u8 = 7;
const PATHSTR: &str = "hangman-words.txt";
const OFFSET: (usize, usize) = (1, 1);

const CONF_TEMPLATE: &str = "\
### This is a sample word-list for the hangman game

### Sample word-list
#   ----------------
#
# Before every game one line is randomly chosen.
# Empty lines and lines starting with # are ignored.
# Lines with guessing strings must start with '-'.
# Words enclosed with * are not hidden when the game starts:
#   - *guess *me
# shows in the game:
#   g u e s s   _ _
#

- *guess* me
- hang*man*
- good luck

# Lines starting with ':' are game modifier. They change
# the logic how the image is progressively disclosed:
#   ':success-rewarding'       Every guessed character shows a bit more of the
#                              image. This mode is default.
#   ':traditional-rewarding'   Every lost live discloses a bit more of the
#                  image. Choose this mode together with a
#                              traditional gallows image (not built in).

### Sample custom image
#   -------------------
#
# Instead of built in images a word list can use a
# custom image. Lines starting with '|' are interpreted
# as image-lines. Delete '#' in the following lines to
# try out this feature.

#:traditional-rewarding
#|  ______
#|  |    |
#|  |    O
#|  |   /|\\
#|  |    |
#|  |   / \\
#|__|_____
#||      |___
#||_________|
";

const CONF_DEMO: &str = "- *Demo: add own words to config file and *start* again!*";

// ------------------ MAIN ---------------------------------------------

pub fn read_config(pathstr: &PathBuf) -> Result<String, io::Error> {
    let mut f = File::open(pathstr)?;
    let mut s = String::new();
    f.read_to_string(&mut s)?;
    Ok(s)
}

pub fn write_config_template(pathstr: &PathBuf) -> Result<(), io::Error> {
    let mut file = File::create(&pathstr)?;
    file.write_all(CONF_TEMPLATE.as_bytes())?;
    Ok(())
}

fn main() {
    // SHOW HELP TEXT
    match env::args().nth(1) {
        Some(ref a) if a == "-h" || a == "--help" => {
            println!("{}", COMMANDLINE_HELP);
            return;
        }
        Some(_) => {}
        None => {}
    };

    // READ CONFIG

    // Read all config files given on command line
    let mut conf_file_paths: Vec<PathBuf> = env::args().skip(1).map(|s| PathBuf::from(s)).collect();

    // if no conf_file_paths are given then use default config path
    if conf_file_paths.len() == 0 {
        conf_file_paths.push(PathBuf::from(PATHSTR))
    };

    // read and concat all config files given on command line
    let cwd = env::current_dir().unwrap();

    let mut config: String = String::new();
    for conf_file_path in &conf_file_paths {
        let path = conf_file_path;
        let c = match read_config(&path) {
            Ok(s) => s,
            Err(_) => {
                match write_config_template(&path) {
                    Ok(_) => {
                        println!(
                            "As no config-file :\n\
                             \t{:?}\n\
                             was found a template file is written in the \
                             current working directory.\n\
                             \t{:?}\n\n\nPress [Enter] to enter demo mode.",
                            path, cwd
                        );
                        // wait for [Enter] key
                        let input = &mut String::new();
                        io::stdin().read_line(input).unwrap();
                        CONF_DEMO.to_string()
                    }
                    Err(why) => {
                        println!(
                            "Couldn't write hangman template \
                             config-file:\n\t{:?}\n({})\n\n\
                             Current working directory is:\n\t{:?}\n\n\
                             Press [Enter] to enter demo mode.",
                            path,
                            Error::description(&why),
                            cwd
                        );
                        // wait for [Enter] key
                        let input = &mut String::new();
                        io::stdin().read_line(input).unwrap();
                        CONF_DEMO.to_string()
                    }
                }
            }
        };
        config.push_str(&c);
    }

    // INITIALISE GAME

    let mut ui = UserInterface::new(&config, OFFSET);

    let mut dict = Dict::new(&config);
    if dict.len() == 0 {
        println!(
            "No guessing words in config-file(s):\n\
             \t{:?}\n\
             were found. Current working directory is:\n\
             \t{:?}\n\n\nPress [Enter] to enter demo mode.",
            conf_file_paths, cwd
        );
        // wait for [Enter] key
        let input = &mut String::new();
        io::stdin().read_line(input).unwrap();
        dict = Dict::new(CONF_DEMO);
    };

    // PLAY

    'playing: loop {
        let mut game = Game::new(&(dict.get_random_word()), LIVES);
        let chars_to_guess = game.visible_chars();

        // The game loop
        let mut line_buffer = String::new();
        let reader = io::stdin();
        print!("\x1b[2J"); // clear screen
        'running_game: loop {
            if game.lives > 0 || ui.image.rewarding_scheme == RewardingScheme::UnhideWhenLostLife {
                ui.image.disclose(
                    (game.lives as usize, LIVES as usize),
                    (game.visible_chars(), chars_to_guess),
                );
            }
            ui.message = format!("{}", game);
            println!("{}", ui);

            match game.get_state() {
                State::Victory => {
                    println!("Congratulations! You won!");
                    break 'running_game;
                }
                State::Defeat => {
                    println!("Sorry, you lost! Better luck next time!");
                    break 'running_game;
                }
                _ => {}
            }

            print!("Type a letter then type [Enter]: ");
            io::stdout().flush().unwrap();

            // Read next char and send it
            line_buffer.clear();
            reader.read_line(&mut line_buffer).unwrap();

            game.guess(match line_buffer.chars().next() {
                Some(char_) => char_,
                None => continue 'running_game,
            });
        }

        print!("New game? Type [Y]es or [n]o: ");
        io::stdout().flush().unwrap();

        // Read next char
        line_buffer.clear();
        reader.read_line(&mut line_buffer).unwrap();
        println! {"(c) Jens Getreu, 2016."};

        match line_buffer.trim_end().chars().next() {
            Some(char_) if char_ == 'N' || char_ == 'n' => break 'playing,
            Some(_) => {}
            None => {}
        }
    }
}
<|endoftext|>


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

// import local modules
extern crate demod;
use demod::usage;
use demod::usage::DataType::{I16, F32};

// import external modules
use std::process::exit;
use std::io;
use std::io::Read;
use std::io::Write;
use std::mem;
use std::slice;

extern crate liquid_dsp;
use liquid_dsp::firfilt;
use liquid_dsp::msresamp;
use liquid_dsp::freqdem;
use liquid_dsp::{Complex32};

const BUFFER_SIZE: usize = 8192;

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

fn main() {
    let args = usage::args();

    println_stderr!("demod {} andres.vahter@gmail.com\n\n", env!("CARGO_PKG_VERSION"));

    // filter options
    let filter_len = 64;
    let filter_cutoff_freq = args.bandwidth.unwrap() as f32 / args.samplerate.unwrap() as f32;
    let filter_attenuation = 70.0f32;

    let filter = firfilt::FirFilterCrcf::kaiser(filter_len, filter_cutoff_freq, filter_attenuation, 0.0f32);
    filter.set_scale(2.0f32 * filter_cutoff_freq);

    // resampler options
    let resampler_rate = if args.resamplerate.is_some() {
                            args.resamplerate.unwrap() as f32 / args.samplerate.unwrap() as f32
                        }
                        else {
                            1.0_f32
                        };

    let resampler = msresamp::MsresampCrcf::new(resampler_rate, filter_attenuation);
	let resampler_delay = resampler.get_delay();

    // TODO, is it so?????
    let num_samples = match args.inputtype.unwrap() {
        I16 => {BUFFER_SIZE as u32 / 2},
        F32 => {BUFFER_SIZE as u32 / 4},
    };

    // number of input samples (zero-padded)
    let resampler_input_len = num_samples + resampler_delay.ceil() as u32 + 10;
	// output buffer with extra padding
	let resampler_output_len = (2f32 * resampler_input_len as f32 * resampler_rate as f32) as u32;

    let mut input = vec![Complex32{real:0.0f32, imag:0.0f32}; resampler_input_len as usize];
	let mut output = vec![Complex32{real:0.0f32, imag:0.0f32}; resampler_output_len as usize];
	let mut resampler_output_count = 0;

    // FM demodulator
    let modulation_factor = if args.resamplerate.is_some() {
                                args.fmargs.deviation.unwrap() as f32 / args.resamplerate.unwrap() as f32
                            }
                            else {
                                args.fmargs.deviation.unwrap() as f32 / args.samplerate.unwrap() as f32
                            };

    let fm_demod = freqdem::Freqdem::new(modulation_factor);
    let mut demod_out = vec![0_f32; resampler_output_len as usize];

    let mut stdin = io::stdin();
    let mut stdout = io::stdout();
    let mut inbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];

    loop {
        match stdin.read(&mut inbuf) {
            Ok(size) => {
                let mut sample_count: usize = 0;

                match args.inputtype.unwrap() {
                    I16 => {
                        for b in inbuf.chunks(4) {
                            let i: f32 = ((b[1] as i16) << 8 | b[0] as i16) as f32 / 32768.;
                            let q: f32 = ((b[3] as i16) << 8 | b[2] as i16) as f32 / 32768.;

                            input[sample_count] = Complex32{real:i, imag:q};
                            filter.push(input[sample_count]);
                            filter.execute(&mut input[sample_count]);
                            sample_count += 1;
                        }
                    }
                    F32 => {
                        for b in inbuf.chunks(8) {
                            let i: f32 = unsafe {mem::transmute::<u32, f32>(((b[3] as u32) << 24) | ((b[2] as u32) << 16) | ((b[1] as u32) << 8) | b[0] as u32)};
                            let q: f32 = unsafe {mem::transmute::<u32, f32>(((b[7] as u32) << 24) | ((b[6] as u32) << 16) | ((b[5] as u32) << 8) | b[4] as u32)};

                            input[sample_count] = Complex32{real:i, imag:q};
                            filter.push(input[sample_count]);
                            filter.execute(&mut input[sample_count]);
                            sample_count += 1;
                        }
                    }
                }

                //let slice = unsafe {slice::from_raw_parts(input.as_ptr() as *const _, size * 2)};
                //stdout.write(&slice).unwrap();

                // resample
                resampler.execute(&mut input, sample_count as u32, &mut output, &mut resampler_output_count);

                //let slice = unsafe {slice::from_raw_parts(output.as_ptr() as *const _, (resampler_output_count * 8) as usize)};
                //stdout.write(&slice).unwrap();

                // demodulate
                fm_demod.demodulate_block(&mut output, resampler_output_count, &mut demod_out);

                match args.outputtype.unwrap() {
                    I16 => {
                        for i in 0 .. resampler_output_count as usize {
                            if args.fmargs.squarewave.unwrap() {
                                // make output square like, multimon-ng likes it more
                                if demod_out[i] > 0.0 {
                                    demod_out[i] = 1.0;
                                }
                                if demod_out[i] < 0.0 {
                                    demod_out[i] = -1.0;
                                }

                            }
                            else {
                                // clamp output
                                if demod_out[i] > 1.0 {
                                    demod_out[i] = 1.0;
                                }
                                if demod_out[i] < -1.0 {
                                    demod_out[i] = -1.0;
                                }
                            }

                            let sample: [i16; 1] = [(demod_out[i] * 32767_f32) as i16];
                            let slice = unsafe {slice::from_raw_parts(sample.as_ptr() as *const _, 2)};
                            stdout.write(&slice).map_err(|e|{println_stderr!("stdout.write error: {:?}", e); exit(1);});
                            stdout.flush().map_err(|e|{println_stderr!("stdout.write error: {:?}", e); exit(1);});
                        }
                    }
                    F32 => {
                        let slice = unsafe {slice::from_raw_parts(demod_out.as_ptr() as *const _, (resampler_output_count * 4) as usize)};
                        stdout.write(&slice).map_err(|e|{println_stderr!("stdout.write error: {:?}", e); exit(1);});
                        stdout.flush().map_err(|e|{println_stderr!("stdout.write error: {:?}", e); exit(1);});
                    }
                }

                if size < BUFFER_SIZE {
                    break;
                }
            }
            Err(e) => {
                println_stderr!("err: {:?}", e);
                break;
            }
        }
    }
}
<commit_msg>fix #1, where writing i16 data to stdout was slow<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Andres Vahter (andres.vahter@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

// import local modules
extern crate demod;
use demod::usage;
use demod::usage::DataType::{I16, F32};

// import external modules
use std::process::exit;
use std::io;
use std::io::Read;
use std::io::Write;
use std::mem;
use std::slice;

extern crate liquid_dsp;
use liquid_dsp::firfilt;
use liquid_dsp::msresamp;
use liquid_dsp::freqdem;
use liquid_dsp::{Complex32};

const BUFFER_SIZE: usize = 8192;

macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
    )
);

fn main() {
    let args = usage::args();

    println_stderr!("demod {} andres.vahter@gmail.com\n\n", env!("CARGO_PKG_VERSION"));

    // filter options
    let filter_len = 64;
    let filter_cutoff_freq = args.bandwidth.unwrap() as f32 / args.samplerate.unwrap() as f32;
    let filter_attenuation = 70.0f32;

    let filter = firfilt::FirFilterCrcf::kaiser(filter_len, filter_cutoff_freq, filter_attenuation, 0.0f32);
    filter.set_scale(2.0f32 * filter_cutoff_freq);

    // resampler options
    let resampler_rate = if args.resamplerate.is_some() {
                            args.resamplerate.unwrap() as f32 / args.samplerate.unwrap() as f32
                        }
                        else {
                            1.0_f32
                        };

    let resampler = msresamp::MsresampCrcf::new(resampler_rate, filter_attenuation);
	let resampler_delay = resampler.get_delay();

    // TODO, is it so?????
    let num_samples = match args.inputtype.unwrap() {
        I16 => {BUFFER_SIZE as u32 / 2},
        F32 => {BUFFER_SIZE as u32 / 4},
    };

    // number of input samples (zero-padded)
    let resampler_input_len = num_samples + resampler_delay.ceil() as u32 + 10;
	// output buffer with extra padding
	let resampler_output_len = (2f32 * resampler_input_len as f32 * resampler_rate as f32) as u32;

    let mut input = vec![Complex32{real:0.0f32, imag:0.0f32}; resampler_input_len as usize];
	let mut output = vec![Complex32{real:0.0f32, imag:0.0f32}; resampler_output_len as usize];
	let mut resampler_output_count = 0;

    // FM demodulator
    let modulation_factor = if args.resamplerate.is_some() {
                                args.fmargs.deviation.unwrap() as f32 / args.resamplerate.unwrap() as f32
                            }
                            else {
                                args.fmargs.deviation.unwrap() as f32 / args.samplerate.unwrap() as f32
                            };

    let fm_demod = freqdem::Freqdem::new(modulation_factor);
    let mut demod_f32_out = vec![0_f32; resampler_output_len as usize];
    let mut demod_i16_out = vec![0_i16; resampler_output_len as usize];

    let mut stdin = io::stdin();
    let mut stdout = io::stdout();
    let mut inbuf: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];

    loop {
        match stdin.read(&mut inbuf) {
            Ok(size) => {
                let mut sample_count: usize = 0;

                match args.inputtype.unwrap() {
                    I16 => {
                        for b in inbuf.chunks(4) {
                            let i: f32 = ((b[1] as i16) << 8 | b[0] as i16) as f32 / 32768.;
                            let q: f32 = ((b[3] as i16) << 8 | b[2] as i16) as f32 / 32768.;

                            input[sample_count] = Complex32{real:i, imag:q};
                            filter.push(input[sample_count]);
                            filter.execute(&mut input[sample_count]);
                            sample_count += 1;
                        }
                    }
                    F32 => {
                        for b in inbuf.chunks(8) {
                            let i: f32 = unsafe {mem::transmute::<u32, f32>(((b[3] as u32) << 24) | ((b[2] as u32) << 16) | ((b[1] as u32) << 8) | b[0] as u32)};
                            let q: f32 = unsafe {mem::transmute::<u32, f32>(((b[7] as u32) << 24) | ((b[6] as u32) << 16) | ((b[5] as u32) << 8) | b[4] as u32)};

                            input[sample_count] = Complex32{real:i, imag:q};
                            filter.push(input[sample_count]);
                            filter.execute(&mut input[sample_count]);
                            sample_count += 1;
                        }
                    }
                }

                //let slice = unsafe {slice::from_raw_parts(input.as_ptr() as *const _, size * 2)};
                //stdout.write(&slice).unwrap();

                // resample
                resampler.execute(&mut input, sample_count as u32, &mut output, &mut resampler_output_count);

                //let slice = unsafe {slice::from_raw_parts(output.as_ptr() as *const _, (resampler_output_count * 8) as usize)};
                //stdout.write(&slice).unwrap();

                // demodulate
                fm_demod.demodulate_block(&mut output, resampler_output_count, &mut demod_f32_out);

                match args.outputtype.unwrap() {
                    I16 => {
                        for i in 0 .. resampler_output_count as usize {
                            if args.fmargs.squarewave.unwrap() {
                                // make output square like, multimon-ng likes it more
                                if demod_f32_out[i] > 0.0 {
                                    demod_f32_out[i] = 1.0;
                                }
                                if demod_f32_out[i] < 0.0 {
                                    demod_f32_out[i] = -1.0;
                                }

                            }
                            else {
                                // clamp output
                                if demod_f32_out[i] > 1.0 {
                                    demod_f32_out[i] = 1.0;
                                }
                                if demod_f32_out[i] < -1.0 {
                                    demod_f32_out[i] = -1.0;
                                }
                            }

                            demod_i16_out[i] = (demod_f32_out[i] * 32767_f32) as i16;
                        }

                        let slice = unsafe {slice::from_raw_parts(demod_i16_out.as_ptr() as *const _, (resampler_output_count * 2) as usize)};
                        stdout.write(&slice).map_err(|e|{println_stderr!("demod stdout.write error: {}", e); exit(1);});
                        stdout.flush().map_err(|e|{println_stderr!("demod stdout.flush error: {}", e); exit(1);});
                    }
                    F32 => {
                        let slice = unsafe {slice::from_raw_parts(demod_f32_out.as_ptr() as *const _, (resampler_output_count * 4) as usize)};
                        stdout.write(&slice).map_err(|e|{println_stderr!("stdout.write error: {}", e); exit(1);});
                        stdout.flush().map_err(|e|{println_stderr!("stdout.flush error: {}", e); exit(1);});
                    }
                }

                if size < BUFFER_SIZE {
                    break;
                }
            }
            Err(e) => {
                println_stderr!("err: {:?}", e);
                break;
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::vec::Vec;

/**
 *
 * - struct for all question types
 * - input routine
 * - hash set as data structure
 * - export function
 *
 */

struct Answer {
    title: String,
    points: i32,
}

struct Question {
    question_type: QuestionType,
    title: String,
    answers: Vec<Answer>,
}

enum QuestionType {
    SingleChoice,
    MultipleChoice,
    Essay,
    TrueFalse,
    Matching,
    ShortAnswer,
    NumericalResponse,
}

fn main() {
    println!("Bitte Fragetyp eingeben: [1-7], 0 for help");
    let mut input = String::new();
    match io::stdin().read_line(&mut input) {
        Ok(n) => {}
        Err(error) => println!("error: {}", error),
    }

    if input == "1" {
        println!("SingleChoice");
    }
    println!("{}", input);
}

fn new_question(question_type: &str, name: &str) {
    println!("{}", question_type);
    println!("{}", name);
}
<commit_msg>Implemented rudimentary question and answer adding<commit_after>use std::io;
use std::vec::Vec;

/**
 *
 * - struct for all question types
 * - input routine
 * - hash set as data structure
 * - export function
 *
 */

struct Answer {
    title: String,
    points: i32,
}

struct Question {
    question_type: QuestionType,
    title: String,
    answers: Vec<Answer>,
}

enum QuestionType {
    SingleChoice,
    MultipleChoice,
    Essay,
    TrueFalse,
    Matching,
    ShortAnswer,
    NumericalResponse,
}

fn main() {
    println!("Bitte Fragetyp eingeben: [1-7], 0 for help");

    let mut question_type = String::new();
    get_input(&mut question_type);

    match question_type.trim() {
        "1" => println!("Single Choice"),
        "2" => println!("Multiple Choice"),
        "3" => println!("Essay"),
        "4" => println!("True/False"),
        "5" => println!("Matching"),
        "6" => println!("Short Answer"),
        "7" => println!("NumericalResponse"),
        _ => println!("else"),
    }

    println!("Type in the question text");
    let mut question_text = String::new();
    get_input(&mut question_text);

    println!("You typed: {}", question_text);

    let mut answers: Vec<Answer> = Vec::new();
    loop {
        println!("Insert Answer {}: [0] to exit", answers.len() + 1);
        let mut answer = String::new();
        get_input(&mut answer);
        println!("{}", answer);
        match answer.trim() {
            "0" => break,
            _ => {
                answers.push(Answer {
                    title: answer.to_string(),
                    points: 0,
                })
            }
        }
    }

    for answer in &answers {
        println!("{}", answer.title);
    }
}

fn get_input(input: &mut String) -> () {
    let mut read_line = String::new();
    match io::stdin().read_line(&mut read_line) {
        Ok(n) => {
            if n > 0 {
                *input = read_line;
            }
        }
        Err(error) => println!("error: {}", error),
    }
}

fn new_question(question_type: &str, name: &str) {
    println!("{}", question_type);
    println!("{}", name);
}
<|endoftext|>


<commit_before>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate cargo_metadata;
extern crate docopt;
extern crate rustc_serialize;

use cargo_metadata::{metadata, Package};
use docopt::Docopt;
use std::{env, fs, io, path, process};
use std::io::Write;

const USAGE: &'static str = "
Cargo Fuzz

Usage:
  cargo fuzz --init
  cargo fuzz --fuzz-target TARGET
  cargo fuzz --add TARGET
  cargo fuzz (-h | --help)

Options:
  -h --help              Show this screen.
  --init                 Initialize fuzz folder
  --fuzz-target TARGET   Run with given fuzz target in fuzz/fuzzers
  --add TARGET           Add a new fuzz target
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_init: bool,
    flag_add: Option<String>,
    flag_fuzz_target: Option<String>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let result = if args.flag_init {
        init_fuzz()
    } else if let Some(target) = args.flag_add {
        add_target(target)
    } else if let Some(target) = args.flag_fuzz_target {
        let result = run_target(target);
        if let Ok(success) = result {
            if success {
                // Can this ever happen?
                Ok(())
            } else {
                println!("Fuzzing found errors!");
                process::exit(-1)
            }
        } else {
            result.map(|_| ())
        }
    } else {
        println!("Invalid arguments. Usage:\n{}", USAGE);
        return;
    };
    if let Err(error) = result {
        println!("Error: {:?}", error);
    }
}

/// Create all the files and folders we need to run
///
/// This will not clone libfuzzer-sys
fn init_fuzz() -> io::Result<()> {
    let me = get_package();

    fs::create_dir("./fuzz")?;
    fs::create_dir("./fuzz/fuzzers")?;

    let mut cargo = fs::File::create(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[package]
name = "{0}-fuzz"
version = "0.0.1"
authors = ["Automatically generated"]

[dependencies.{0}]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzzer_script_1"
path = "fuzzers/fuzzer_script_1.rs"
"#, me.name)?;

    let mut ignore = fs::File::create(path::Path::new("./fuzz/.gitignore"))?;

write!(ignore, r#"
target
libfuzzer
"#)?;

    let mut script = fs::File::create(path::Path::new("./fuzz/fuzzers/fuzzer_script_1.rs"))?;
    dummy_target(&mut script, &me)
}

/// Returns metadata for the Cargo package in the current directory
fn get_package() -> Package {
    // todo error handling
    let meta = metadata(None).unwrap();
    let mut p = env::current_dir().unwrap();
    p.push("Cargo.toml");
    let p = p.to_str().unwrap();
    meta.packages.into_iter().find(|package| package.manifest_path == p).unwrap()
}

/// If the package contains a library target, generate an `extern crate` line to link to it.
fn link_to_lib(pkg: &Package) -> Option<String> {
    pkg.targets.iter()
               .find(|target| target.kind.iter().any(|k| k == "lib"))
               .map(|target| format!("extern crate {};\n", target.name.replace("-", "_")))
}

/// Create a dummy fuzz target script at the given path
fn dummy_target(script: &mut fs::File, pkg: &Package) -> io::Result<()> {
write!(script, r#"#![no_main]
extern crate libfuzzer_sys;
{}
#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {{
    // fuzzed code goes here
}}"#, link_to_lib(pkg).unwrap_or(String::new()))
}

/// Add a new fuzz target script with a given name
fn add_target(target: String) -> io::Result<()> {
    let target_file = format!("fuzz/fuzzers/{}.rs", target);
    let mut script = fs::File::create(path::Path::new(&target_file))?;
    let me = get_package();
    dummy_target(&mut script, &me)?;

    let mut cargo = fs::OpenOptions::new().append(true).open(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[[bin]]
name = "{0}"
path = "fuzzers/{0}.rs"
"#, target)

}

/// Build or rebuild libFuzzer (rebuilds only if the compiler version changed)
///
/// We can't just use libFuzzer as a dependency since libgcc will
/// get compiled with sanitizer support. RUSTFLAGS does not discriminate
/// between build dependencies and regular ones.
///
/// https://github.com/rust-lang/cargo/issues/3739
fn rebuild_libfuzzer() -> io::Result<()> {
    if let Err(_) = env::set_current_dir("./libfuzzer") {
        let mut git = process::Command::new("git");
        let mut cmd = git.arg("clone")
                         .arg("https://github.com/rust-fuzz/libfuzzer-sys.git")
                         .arg("libfuzzer");
        let result = cmd.spawn()?.wait()?;
        if !result.success() {
            return Err(io::Error::new(io::ErrorKind::Other,
                                      "Failed to clone libfuzzer-sys"))
        }
        env::set_current_dir("./libfuzzer")?;
    }
    let mut cmd = process::Command::new("cargo");
    cmd.arg("build")
       .arg("--release")
       .spawn()?
       .wait()?;

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other,
                                  "Failed to build libfuzzer-sys"))
    }
    env::set_current_dir("..")
}

/// Fuzz a given fuzz target
fn run_target(target: String) -> io::Result<bool> {
    env::set_current_dir("./fuzz")?;
    rebuild_libfuzzer()?;
    let mut flags = env::var("RUSTFLAGS").unwrap_or("".into());
    if !flags.is_empty() {
        flags.push(' ');
    }
    flags.push_str("-Cpasses=sancov -Cllvm-args=-sanitizer-coverage-level=3 -Zsanitizer=address -Cpanic=abort");
    let mut cmd = process::Command::new("cargo");
    cmd.arg("rustc")
       .arg("--verbose")
       .arg("--bin")
       .arg(&target)
       .arg("--")
       .arg("-L")
       .arg("libfuzzer/target/release")
       .env("RUSTFLAGS", &flags);

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other, "Failed to build fuzz target"))
    }

    // can't use cargo run since we can't pass -L args to it
    let path = format!("target/debug/{}", target);
    let mut run_cmd = process::Command::new(path);
    let result = run_cmd.spawn()?.wait()?;
    Ok(result.success())
}
<commit_msg>Specify `publish = false` for generated crate.<commit_after>// Copyright 2016 rust-fuzz developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

extern crate cargo_metadata;
extern crate docopt;
extern crate rustc_serialize;

use cargo_metadata::{metadata, Package};
use docopt::Docopt;
use std::{env, fs, io, path, process};
use std::io::Write;

const USAGE: &'static str = "
Cargo Fuzz

Usage:
  cargo fuzz --init
  cargo fuzz --fuzz-target TARGET
  cargo fuzz --add TARGET
  cargo fuzz (-h | --help)

Options:
  -h --help              Show this screen.
  --init                 Initialize fuzz folder
  --fuzz-target TARGET   Run with given fuzz target in fuzz/fuzzers
  --add TARGET           Add a new fuzz target
";

#[derive(Debug, RustcDecodable)]
struct Args {
    flag_init: bool,
    flag_add: Option<String>,
    flag_fuzz_target: Option<String>,
}

fn main() {
    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    let result = if args.flag_init {
        init_fuzz()
    } else if let Some(target) = args.flag_add {
        add_target(target)
    } else if let Some(target) = args.flag_fuzz_target {
        let result = run_target(target);
        if let Ok(success) = result {
            if success {
                // Can this ever happen?
                Ok(())
            } else {
                println!("Fuzzing found errors!");
                process::exit(-1)
            }
        } else {
            result.map(|_| ())
        }
    } else {
        println!("Invalid arguments. Usage:\n{}", USAGE);
        return;
    };
    if let Err(error) = result {
        println!("Error: {:?}", error);
    }
}

/// Create all the files and folders we need to run
///
/// This will not clone libfuzzer-sys
fn init_fuzz() -> io::Result<()> {
    let me = get_package();

    fs::create_dir("./fuzz")?;
    fs::create_dir("./fuzz/fuzzers")?;

    let mut cargo = fs::File::create(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[package]
name = "{0}-fuzz"
version = "0.0.1"
authors = ["Automatically generated"]
publish = false

[dependencies.{0}]
path = ".."

# Prevent this from interfering with workspaces
[workspace]
members = ["."]

[[bin]]
name = "fuzzer_script_1"
path = "fuzzers/fuzzer_script_1.rs"
"#, me.name)?;

    let mut ignore = fs::File::create(path::Path::new("./fuzz/.gitignore"))?;

write!(ignore, r#"
target
libfuzzer
"#)?;

    let mut script = fs::File::create(path::Path::new("./fuzz/fuzzers/fuzzer_script_1.rs"))?;
    dummy_target(&mut script, &me)
}

/// Returns metadata for the Cargo package in the current directory
fn get_package() -> Package {
    // todo error handling
    let meta = metadata(None).unwrap();
    let mut p = env::current_dir().unwrap();
    p.push("Cargo.toml");
    let p = p.to_str().unwrap();
    meta.packages.into_iter().find(|package| package.manifest_path == p).unwrap()
}

/// If the package contains a library target, generate an `extern crate` line to link to it.
fn link_to_lib(pkg: &Package) -> Option<String> {
    pkg.targets.iter()
               .find(|target| target.kind.iter().any(|k| k == "lib"))
               .map(|target| format!("extern crate {};\n", target.name.replace("-", "_")))
}

/// Create a dummy fuzz target script at the given path
fn dummy_target(script: &mut fs::File, pkg: &Package) -> io::Result<()> {
write!(script, r#"#![no_main]
extern crate libfuzzer_sys;
{}
#[export_name="rust_fuzzer_test_input"]
pub extern fn go(data: &[u8]) {{
    // fuzzed code goes here
}}"#, link_to_lib(pkg).unwrap_or(String::new()))
}

/// Add a new fuzz target script with a given name
fn add_target(target: String) -> io::Result<()> {
    let target_file = format!("fuzz/fuzzers/{}.rs", target);
    let mut script = fs::File::create(path::Path::new(&target_file))?;
    let me = get_package();
    dummy_target(&mut script, &me)?;

    let mut cargo = fs::OpenOptions::new().append(true).open(path::Path::new("./fuzz/Cargo.toml"))?;

write!(cargo, r#"
[[bin]]
name = "{0}"
path = "fuzzers/{0}.rs"
"#, target)

}

/// Build or rebuild libFuzzer (rebuilds only if the compiler version changed)
///
/// We can't just use libFuzzer as a dependency since libgcc will
/// get compiled with sanitizer support. RUSTFLAGS does not discriminate
/// between build dependencies and regular ones.
///
/// https://github.com/rust-lang/cargo/issues/3739
fn rebuild_libfuzzer() -> io::Result<()> {
    if let Err(_) = env::set_current_dir("./libfuzzer") {
        let mut git = process::Command::new("git");
        let mut cmd = git.arg("clone")
                         .arg("https://github.com/rust-fuzz/libfuzzer-sys.git")
                         .arg("libfuzzer");
        let result = cmd.spawn()?.wait()?;
        if !result.success() {
            return Err(io::Error::new(io::ErrorKind::Other,
                                      "Failed to clone libfuzzer-sys"))
        }
        env::set_current_dir("./libfuzzer")?;
    }
    let mut cmd = process::Command::new("cargo");
    cmd.arg("build")
       .arg("--release")
       .spawn()?
       .wait()?;

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other,
                                  "Failed to build libfuzzer-sys"))
    }
    env::set_current_dir("..")
}

/// Fuzz a given fuzz target
fn run_target(target: String) -> io::Result<bool> {
    env::set_current_dir("./fuzz")?;
    rebuild_libfuzzer()?;
    let mut flags = env::var("RUSTFLAGS").unwrap_or("".into());
    if !flags.is_empty() {
        flags.push(' ');
    }
    flags.push_str("-Cpasses=sancov -Cllvm-args=-sanitizer-coverage-level=3 -Zsanitizer=address -Cpanic=abort");
    let mut cmd = process::Command::new("cargo");
    cmd.arg("rustc")
       .arg("--verbose")
       .arg("--bin")
       .arg(&target)
       .arg("--")
       .arg("-L")
       .arg("libfuzzer/target/release")
       .env("RUSTFLAGS", &flags);

    let result = cmd.spawn()?.wait()?;
    if !result.success() {
        return Err(io::Error::new(io::ErrorKind::Other, "Failed to build fuzz target"))
    }

    // can't use cargo run since we can't pass -L args to it
    let path = format!("target/debug/{}", target);
    let mut run_cmd = process::Command::new(path);
    let result = run_cmd.spawn()?.wait()?;
    Ok(result.success())
}
<|endoftext|>


<commit_before>use position::Position;
use cppn::Cppn;

/// Represents a node in the substrate. `T` is an arbitrary
/// type used to store additional information about that node.
pub struct Node<P: Position, T> {
    pub position: P,
    pub data: T,
}

pub struct Substrate<P: Position, T> {
    nodes: Vec<Node<P, T>>,
}

pub struct LinkIterator<'a, P: Position + 'a, T: 'a> {
    nodes: &'a [Node<P, T>],
    cppn: &'a mut Cppn,
    inner: usize,
    outer: usize,
    max_distance: Option<f64>,
}

#[derive(Copy, Clone)]
pub struct Link<'a, P: Position + 'a, T: 'a> {
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub weight: f64,
    pub distance: f64,
}

impl<'a, P: Position + 'a, T: 'a> Iterator for LinkIterator<'a, P, T> {
    type Item = Link<'a, P, T>;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.inner >= self.nodes.len() {
                self.inner = 0;
                self.outer += 1;
            }
            if self.outer >= self.nodes.len() {
                return None;
            }
            if self.inner == self.outer {
                self.inner += 1;
                continue;
            }

            assert!(self.inner < self.nodes.len() && self.outer < self.nodes.len() &&
                    self.inner != self.outer);
            let source = &self.nodes[self.inner];
            let target = &self.nodes[self.outer];
            let distance = source.position.distance(&target.position);

            // reject a pair of nodes based on `max_distance`.
            if let Some(max_d) = self.max_distance {
                if distance > max_d {
                    self.inner += 1;
                    continue;
                }
            }

            // Calculate the weight between source and target using the CPPN.
            let inputs_to_cppn = [source.position.coords(), target.position.coords()];
            let outputs_from_cppn = self.cppn.calculate(&inputs_to_cppn);
            assert!(outputs_from_cppn.len() == 1);
            let weight = outputs_from_cppn[0];

            self.inner += 1;
            return Some(Link {
                source: source,
                target: target,
                weight: weight,
                distance: distance,
            });
        }
    }
}

impl<P: Position, T> Substrate<P, T> {
    pub fn new() -> Substrate<P, T> {
        Substrate { nodes: Vec::new() }
    }

    pub fn add_node(&mut self, position: P, data: T) {
        self.nodes.push(Node {
            position: position,
            data: data,
        });
    }

    /// Iterate over all produced links of Cppn.
    pub fn iter_links<'a>(&'a self,
                          cppn: &'a mut Cppn,
                          max_distance: Option<f64>)
                          -> LinkIterator<'a, P, T> {
        LinkIterator {
            nodes: &self.nodes,
            cppn: cppn,
            inner: 0,
            outer: 0,
            max_distance: max_distance,
        }
    }
}
<commit_msg>Include the source and target index into the Link struct. This eases graph generation based on these indices.<commit_after>use position::Position;
use cppn::Cppn;

/// Represents a node in the substrate. `T` is an arbitrary
/// type used to store additional information about that node.
pub struct Node<P: Position, T> {
    pub position: P,
    pub data: T,
}

pub struct Substrate<P: Position, T> {
    nodes: Vec<Node<P, T>>,
}

pub struct LinkIterator<'a, P: Position + 'a, T: 'a> {
    nodes: &'a [Node<P, T>],
    cppn: &'a mut Cppn,
    inner: usize,
    outer: usize,
    max_distance: Option<f64>,
}

#[derive(Copy, Clone)]
pub struct Link<'a, P: Position + 'a, T: 'a> {
    pub source: &'a Node<P, T>,
    pub target: &'a Node<P, T>,
    pub source_idx: usize,
    pub target_idx: usize,
    pub weight: f64,
    pub distance: f64,
}

impl<'a, P: Position + 'a, T: 'a> Iterator for LinkIterator<'a, P, T> {
    type Item = Link<'a, P, T>;
    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if self.inner >= self.nodes.len() {
                self.inner = 0;
                self.outer += 1;
            }
            if self.outer >= self.nodes.len() {
                return None;
            }
            if self.inner == self.outer {
                self.inner += 1;
                continue;
            }

            assert!(self.inner < self.nodes.len() && self.outer < self.nodes.len() &&
                    self.inner != self.outer);
            let source = &self.nodes[self.inner];
            let target = &self.nodes[self.outer];
            let distance = source.position.distance(&target.position);

            // reject a pair of nodes based on `max_distance`.
            if let Some(max_d) = self.max_distance {
                if distance > max_d {
                    self.inner += 1;
                    continue;
                }
            }

            // Calculate the weight between source and target using the CPPN.
            let inputs_to_cppn = [source.position.coords(), target.position.coords()];
            let outputs_from_cppn = self.cppn.calculate(&inputs_to_cppn);
            assert!(outputs_from_cppn.len() == 1);
            let weight = outputs_from_cppn[0];

            let link = Link {
                source: source,
                target: target,
                source_idx: self.inner,
                target_idx: self.outer,
                weight: weight,
                distance: distance,
            };
            self.inner += 1;
            return Some(link);
        }
    }
}

impl<P: Position, T> Substrate<P, T> {
    pub fn new() -> Substrate<P, T> {
        Substrate { nodes: Vec::new() }
    }

    pub fn add_node(&mut self, position: P, data: T) {
        self.nodes.push(Node {
            position: position,
            data: data,
        });
    }

    /// Iterate over all produced links of Cppn.
    pub fn iter_links<'a>(&'a self,
                          cppn: &'a mut Cppn,
                          max_distance: Option<f64>)
                          -> LinkIterator<'a, P, T> {
        LinkIterator {
            nodes: &self.nodes,
            cppn: cppn,
            inner: 0,
            outer: 0,
            max_distance: max_distance,
        }
    }
}
<|endoftext|>