<commit_before>use std::env;
use std::error;
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// `WorkDir` represents a directory in which tests are run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Debug)]
pub struct WorkDir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here.
    dir: PathBuf,
}

impl WorkDir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> WorkDir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe().unwrap()
            .parent().expect("executable's directory").to_path_buf();
        let dir = root.join(TEST_DIR).join(name).join(&format!("{}", id));
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        WorkDir {
            root: root,
            dir: dir,
        }
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    pub fn try_create<P: AsRef<Path>>(&self, name: P, contents: &str) -> io::Result<()> {
        let path = self.dir.join(name);
        self.try_create_bytes(path, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(name);
        nice_err(&path, self.try_create_bytes(&path, contents));
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    fn try_create_bytes<P: AsRef<Path>>(&self, path: P, contents: &[u8]) -> io::Result<()> {
        let mut file = File::create(&path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    pub fn command(&self) -> process::Command {
        let mut cmd = process::Command::new(&self.bin());
        cmd.env_remove("RIPGREP_CONFIG_PATH");
        cmd.current_dir(&self.dir);
        cmd
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(not(windows))]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg")
        } else {
            path
        }
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(windows)]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg.exe");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg.exe")
        } else {
            path
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }

    /// Runs and captures the stdout of the given command.
    ///
    /// If the return type could not be created from a string, then this
    /// panics.
    pub fn stdout<E: fmt::Debug, T: FromStr<Err=E>>(
        &self,
        cmd: &mut process::Command,
    ) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!("could not convert from string: {:?}\n\n{}", err, stdout);
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        let output = cmd.output().unwrap();
        self.expect_success(cmd, output)
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(
        &self,
        cmd: &mut process::Command,
        input: &str
    ) -> process::Output {
        cmd.stdin(process::Stdio::piped());
        cmd.stdout(process::Stdio::piped());
        cmd.stderr(process::Stdio::piped());

        let mut child = cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || {
            write!(stdin, "{}", input)
        });

        let output = self.expect_success(cmd, child.wait_with_output().unwrap());
        worker.join().unwrap().unwrap();
        output
    }

    /// If `o` is not the output of a successful process run
    fn expect_success(
        &self,
        cmd: &process::Command,
        o: process::Output
    ) -> process::Output {
        if !o.status.success() {
            let suggest =
                if o.stderr.is_empty() {
                    "\n\nDid your search end up with no results?".to_string()
                } else {
                    "".to_string()
                };

            panic!("\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                   suggest, cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
        o
    }

    /// Runs the given command and asserts that it resulted in an error exit
    /// code.
    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                cmd,
                self.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    /// Runs the given command and asserts that its exit code matches expected exit code.
    pub fn assert_exit_code(&self, expected_code: i32, cmd: &mut process::Command) {
        let code = cmd.status().unwrap().code().unwrap();

        assert_eq!(
            expected_code, code,
            "\n\n===== {:?} =====\n\
             expected exit code did not match\
             \n\nexpected: {}\
             \n\nfound: {}\
             \n\n=====\n",
            cmd, expected_code, code
        );
    }

    /// Runs the given command and asserts that something was printed to
    /// stderr.
    pub fn assert_non_empty_stderr(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }
}

fn nice_err<P: AsRef<Path>, T, E: error::Error>(
    path: P,
    res: Result<T, E>,
) -> T {
    match res {
        Ok(t) => t,
        Err(err) => {
            panic!("{}: {:?}", path.as_ref().display(), err);
        }
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}
<commit_msg>tests/style: 80 columns, dammit<commit_after>use std::env;
use std::error;
use std::fmt;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::str::FromStr;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::thread;
use std::time::Duration;

static TEST_DIR: &'static str = "ripgrep-tests";
static NEXT_ID: AtomicUsize = ATOMIC_USIZE_INIT;

/// `WorkDir` represents a directory in which tests are run.
///
/// Directories are created from a global atomic counter to avoid duplicates.
#[derive(Debug)]
pub struct WorkDir {
    /// The directory in which this test executable is running.
    root: PathBuf,
    /// The directory in which the test should run. If a test needs to create
    /// files, they should go in here.
    dir: PathBuf,
}

impl WorkDir {
    /// Create a new test working directory with the given name. The name
    /// does not need to be distinct for each invocation, but should correspond
    /// to a logical grouping of tests.
    pub fn new(name: &str) -> WorkDir {
        let id = NEXT_ID.fetch_add(1, Ordering::SeqCst);
        let root = env::current_exe().unwrap()
            .parent().expect("executable's directory").to_path_buf();
        let dir = root.join(TEST_DIR).join(name).join(&format!("{}", id));
        nice_err(&dir, repeat(|| fs::create_dir_all(&dir)));
        WorkDir {
            root: root,
            dir: dir,
        }
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create<P: AsRef<Path>>(&self, name: P, contents: &str) {
        self.create_bytes(name, contents.as_bytes());
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    pub fn try_create<P: AsRef<Path>>(
        &self,
        name: P,
        contents: &str,
    ) -> io::Result<()> {
        let path = self.dir.join(name);
        self.try_create_bytes(path, contents.as_bytes())
    }

    /// Create a new file with the given name and size.
    pub fn create_size<P: AsRef<Path>>(&self, name: P, filesize: u64) {
        let path = self.dir.join(name);
        let file = nice_err(&path, File::create(&path));
        nice_err(&path, file.set_len(filesize));
    }

    /// Create a new file with the given name and contents in this directory,
    /// or panic on error.
    pub fn create_bytes<P: AsRef<Path>>(&self, name: P, contents: &[u8]) {
        let path = self.dir.join(name);
        nice_err(&path, self.try_create_bytes(&path, contents));
    }

    /// Try to create a new file with the given name and contents in this
    /// directory.
    fn try_create_bytes<P: AsRef<Path>>(
        &self,
        path: P,
        contents: &[u8],
    ) -> io::Result<()> {
        let mut file = File::create(&path)?;
        file.write_all(contents)?;
        file.flush()
    }

    /// Remove a file with the given name from this directory.
    pub fn remove<P: AsRef<Path>>(&self, name: P) {
        let path = self.dir.join(name);
        nice_err(&path, fs::remove_file(&path));
    }

    /// Create a new directory with the given path (and any directories above
    /// it) inside this directory.
    pub fn create_dir<P: AsRef<Path>>(&self, path: P) {
        let path = self.dir.join(path);
        nice_err(&path, repeat(|| fs::create_dir_all(&path)));
    }

    /// Creates a new command that is set to use the ripgrep executable in
    /// this working directory.
    pub fn command(&self) -> process::Command {
        let mut cmd = process::Command::new(&self.bin());
        cmd.env_remove("RIPGREP_CONFIG_PATH");
        cmd.current_dir(&self.dir);
        cmd
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(not(windows))]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg")
        } else {
            path
        }
    }

    /// Returns the path to the ripgrep executable.
    #[cfg(windows)]
    pub fn bin(&self) -> PathBuf {
        let path = self.root.join("rg.exe");
        if !path.is_file() {
            // Looks like a recent version of Cargo changed the cwd or the
            // location of the test executable.
            self.root.join("../rg.exe")
        } else {
            path
        }
    }

    /// Returns the path to this directory.
    pub fn path(&self) -> &Path {
        &self.dir
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::unix::fs::symlink;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink(&src, &target));
    }

    /// Creates a directory symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_dir<S: AsRef<Path>, T: AsRef<Path>>(&self, src: S, target: T) {
        use std::os::windows::fs::symlink_dir;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_dir(&target);
        nice_err(&target, symlink_dir(&src, &target));
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(not(windows))]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        self.link_dir(src, target);
    }

    /// Creates a file symlink to the src with the given target name
    /// in this directory.
    #[cfg(windows)]
    pub fn link_file<S: AsRef<Path>, T: AsRef<Path>>(
        &self,
        src: S,
        target: T,
    ) {
        use std::os::windows::fs::symlink_file;
        let src = self.dir.join(src);
        let target = self.dir.join(target);
        let _ = fs::remove_file(&target);
        nice_err(&target, symlink_file(&src, &target));
    }

    /// Runs and captures the stdout of the given command.
    ///
    /// If the return type could not be created from a string, then this
    /// panics.
    pub fn stdout<E: fmt::Debug, T: FromStr<Err=E>>(
        &self,
        cmd: &mut process::Command,
    ) -> T {
        let o = self.output(cmd);
        let stdout = String::from_utf8_lossy(&o.stdout);
        match stdout.parse() {
            Ok(t) => t,
            Err(err) => {
                panic!(
                    "could not convert from string: {:?}\n\n{}",
                    err,
                    stdout
                );
            }
        }
    }

    /// Gets the output of a command. If the command failed, then this panics.
    pub fn output(&self, cmd: &mut process::Command) -> process::Output {
        let output = cmd.output().unwrap();
        self.expect_success(cmd, output)
    }

    /// Pipe `input` to a command, and collect the output.
    pub fn pipe(
        &self,
        cmd: &mut process::Command,
        input: &str
    ) -> process::Output {
        cmd.stdin(process::Stdio::piped());
        cmd.stdout(process::Stdio::piped());
        cmd.stderr(process::Stdio::piped());

        let mut child = cmd.spawn().unwrap();

        // Pipe input to child process using a separate thread to avoid
        // risk of deadlock between parent and child process.
        let mut stdin = child.stdin.take().expect("expected standard input");
        let input = input.to_owned();
        let worker = thread::spawn(move || {
            write!(stdin, "{}", input)
        });

        let output = self.expect_success(
            cmd,
            child.wait_with_output().unwrap(),
        );
        worker.join().unwrap().unwrap();
        output
    }

    /// If `o` is not the output of a successful process run
    fn expect_success(
        &self,
        cmd: &process::Command,
        o: process::Output
    ) -> process::Output {
        if !o.status.success() {
            let suggest =
                if o.stderr.is_empty() {
                    "\n\nDid your search end up with no results?".to_string()
                } else {
                    "".to_string()
                };

            panic!("\n\n==========\n\
                    command failed but expected success!\
                    {}\
                    \n\ncommand: {:?}\
                    \ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\
                    \n\nstderr: {}\
                    \n\n==========\n",
                   suggest, cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
        o
    }

    /// Runs the given command and asserts that it resulted in an error exit
    /// code.
    pub fn assert_err(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() {
            panic!(
                "\n\n===== {:?} =====\n\
                 command succeeded but expected failure!\
                 \n\ncwd: {}\
                 \n\nstatus: {}\
                 \n\nstdout: {}\n\nstderr: {}\
                 \n\n=====\n",
                cmd,
                self.dir.display(),
                o.status,
                String::from_utf8_lossy(&o.stdout),
                String::from_utf8_lossy(&o.stderr)
            );
        }
    }

    /// Runs the given command and asserts that its exit code matches expected
    /// exit code.
    pub fn assert_exit_code(
        &self,
        expected_code: i32,
        cmd: &mut process::Command,
    ) {
        let code = cmd.status().unwrap().code().unwrap();

        assert_eq!(
            expected_code, code,
            "\n\n===== {:?} =====\n\
             expected exit code did not match\
             \n\nexpected: {}\
             \n\nfound: {}\
             \n\n=====\n",
            cmd, expected_code, code
        );
    }

    /// Runs the given command and asserts that something was printed to
    /// stderr.
    pub fn assert_non_empty_stderr(&self, cmd: &mut process::Command) {
        let o = cmd.output().unwrap();
        if o.status.success() || o.stderr.is_empty() {
            panic!("\n\n===== {:?} =====\n\
                    command succeeded but expected failure!\
                    \n\ncwd: {}\
                    \n\nstatus: {}\
                    \n\nstdout: {}\n\nstderr: {}\
                    \n\n=====\n",
                   cmd, self.dir.display(), o.status,
                   String::from_utf8_lossy(&o.stdout),
                   String::from_utf8_lossy(&o.stderr));
        }
    }
}

fn nice_err<P: AsRef<Path>, T, E: error::Error>(
    path: P,
    res: Result<T, E>,
) -> T {
    match res {
        Ok(t) => t,
        Err(err) => {
            panic!("{}: {:?}", path.as_ref().display(), err);
        }
    }
}

fn repeat<F: FnMut() -> io::Result<()>>(mut f: F) -> io::Result<()> {
    let mut last_err = None;
    for _ in 0..10 {
        if let Err(err) = f() {
            last_err = Some(err);
            thread::sleep(Duration::from_millis(500));
        } else {
            return Ok(());
        }
    }
    Err(last_err.unwrap())
}
<|endoftext|>


<commit_before>/*!
Simple player bot.
*/

use ::std::f64;

use ::{Well, Rot, Piece, Player, Point, State, MAX_WIDTH, MAX_HEIGHT};

/// Weights for evaluating well.
pub struct Weights {
	/// Factor for the total combined height of all the columns.
	pub agg_height_f: f64,
	/// Factor for the number of completed lines.
	pub complete_lines_f: f64,
	/// Factor for the number of holes in the field.
	pub holes_f: f64,
	/// Factor for the sum of the absolute differences between two adjacent columns.
	pub bumpiness_f: f64,
	/// Factor for the number blocks above a hole.
	pub stacking_f: f64,
}

impl Weights {
	/// Returns some nice weights.
	///
	/// Gently appropriated from https://codemyroad.wordpress.com/2013/04/14/tetris-ai-the-near-perfect-player/
	pub fn new() -> Weights {
		Weights {
			agg_height_f: -0.510066,
			complete_lines_f: 0.760666,
			holes_f: -0.35663,
			bumpiness_f: -0.184483,
			stacking_f: -0.5,

			// heights: -0.03,
			// lines: 8.0,
			// holes: -7.5,
			// bumpiness: -3.5,
			// walltouch: 6.52,

			// heights: -3.78,
			// lines: 1.6,
			// holes: -2.31,
			// bumpiness: -0.184483,
			// walltouch: 6.52,
		}
	}
	/// Evaluates a well and returns a score.
	///
	/// The score is the sum of result of each category multiplied by the appropriated multiplier.
	///
	/// This value only has meaning in comparison to other wells.
	/// A higher value indicates a better scoring well.
	pub fn eval(&self, well: &Well) -> f64 {
		let (agg_height, completed_lines, holes, bumpiness, stacks) = Self::crunch(well);
		return
			self.agg_height_f * agg_height as f64 +
			self.complete_lines_f * completed_lines as f64 +
			self.holes_f * holes as f64 +
			self.bumpiness_f * bumpiness as f64 +
			self.stacking_f * stacks as f64;
	}
	fn crunch(well: &Well) -> (i32, i32, i32, i32, i32) {
		let width = well.width() as usize;
		let mut heights = [0i32; MAX_WIDTH];
		let mut holes = [0i32; MAX_WIDTH];
		let mut stacks = [0i32; MAX_WIDTH];
		let _ = heights[..width];
		let _ = holes[..width];
		let _ = stacks[..width];
		let mut lines = 0;
		let line_mask = well.line_mask();

		let mut height = 0;
		for &line in well.lines() {
			// Skip cleared lines
			if line == line_mask {
				lines += 1;
			}
			else {
				height += 1;
				let mut line = line;
				for col in 0..width {
					if line & 1 != 0 {
						// Sum the holes for this column
						holes[col] += height - heights[col] - 1;
						// Save the height for this column
						heights[col] = height;
						// Save the stacks for this column
						stacks[col] += (holes[col] != 0) as i32;
					}
					line >>= 1;
				}
			}
		}

		let height_sum = heights[..width].iter().sum();
		let holes_sum = holes[..width].iter().sum();
		let stacks_sum = stacks[..width].iter().sum();
		let bumpiness = heights[..width].windows(2).map(|window| (window[0] - window[1]).abs()).sum();

		(height_sum, lines, holes_sum, bumpiness, stacks_sum)
	}
}

/// Player move.
pub enum PlayM {
	MoveLeft,
	MoveRight,
	RotateCW,
	RotateCCW,
	SoftDrop,
	HardDrop,
}

/// Player AI.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PlayI {
	x: i32,
	rot: Rot,
	score: f64,
}

impl PlayI {
	/// Brute force the best move with the given well and weights.
	pub fn best(weights: &Weights, well: &Well, piece: Piece) -> PlayI {
		// Brute force a solution...
		let mut best_x = 0;
		let mut best_rot = Rot::Zero;
		let mut best_score = f64::NEG_INFINITY;
		for rot in 0..3 {
			for x in -3..well.width() {
				let rot = Rot::from(rot);
				let mut player = Player::new(piece, rot, Point::new(x, well.height()));
				// Early reject against the walls
				if well.test(&player) {
					continue;
				}
				// Drop the piece down
				while !well.test(&player) {
					player.pt.y -= 1;
				}
				player.pt.y += 1;
				// Evaluate the well
				let mut well = well.clone();
				well.etch(&player);
				let score = weights.eval(&well);
				// Keep the best scoring move
				if score > best_score {
					best_x = x;
					best_rot = rot;
					best_score = score;
				}
			}
		}
		PlayI {
			x: best_x,
			rot: best_rot,
			score: best_score,
		}
	}
	/// Brute force the worst piece for the given well and weights.
	pub fn worst_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::S, Piece::Z, Piece::O, Piece::I, Piece::L, Piece::J, Piece::T];
		pieces[..].iter().fold((pieces[0], f64::INFINITY), |(bad_piece, bad_score), &piece| {
			let PlayI { score, .. } = Self::best(weights, well, piece);
			if score < bad_score {
				(piece, score)
			}
			else {
				(bad_piece, bad_score)
			}
		}).0
	}
	/// Brute force the best piece for the given well and weights.
	pub fn best_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::T, Piece::J, Piece::L, Piece::I, Piece::O, Piece::Z, Piece::S];
		pieces[..].iter().fold((pieces[0], f64::NEG_INFINITY), |(good_piece, good_score), &piece| {
			let PlayI { score, .. } = Self::best(weights, well, piece);
			if score > good_score {
				(piece, score)
			}
			else {
				(good_piece, good_score)
			}
		}).0
	}
	fn piece(weights: &Weights, well: &Well, piece: Piece) -> f64 {
		// We're going to flood fill the playing field to discover all possible play states
		const STRIDE: usize = MAX_WIDTH * (MAX_HEIGHT + 4) * 4;
		type Visited = [bool; STRIDE];
		let visited = [false; STRIDE];

		fn rec(visited: &mut Visited, weights: &Weights, well: &Well, player: Player) -> f64 {
			// Check if the current position is unvisited
			let i = (player.pt.y * STRIDE as i32 + (player.pt.x + 3) * 4 + player.rot as u8 as i32) as usize;
			if visited[i] {
				return f64::NEG_INFINITY;
			}
			visited[i] = true;
			if well.test(&player) {
				return f64::NEG_INFINITY;
			}
			// Try all possible moves from this location
			let cw = rec(visited, weights, well, player.rotate_cw());
			let ccw = rec(visited, weights, well, player.rotate_ccw());
			let left = rec(visited, weights, well, player.move_left());
			let right = rec(visited, weights, well, player.move_right());

			let player_down = player.move_down();
			unimplemented!()
		}
		unimplemented!()
	}
	pub fn play(&self, state: &State) -> Option<PlayM> {
		state.player().map(|player| {
			if self.rot != player.rot {
				PlayM::RotateCW
			}
			else if self.x < player.pt.x {
				PlayM::MoveLeft
			}
			else if self.x > player.pt.x {
				PlayM::MoveRight
			}
			else {
				PlayM::HardDrop
			}
		})
	}
}

#[test]
fn tdd() {
	let well = Well::from_data(10, &[
		0b0000110000,
		0b0111111001,
		0b0110111111,
		0b1111111111,
		0b1110111111,
		0b1111111111,
	]);
	let (heights_sum, lines, holes_sum, bumpiness, stacks) = Weights::crunch(&well);
	assert_eq!(28, heights_sum);
	assert_eq!(2, lines);
	assert_eq!(2, holes_sum);
	assert_eq!(6, bumpiness);
	assert_eq!(1, stacks);
}
<commit_msg>Initial implementation of a better brute force piece eval.<commit_after>/*!
Simple player bot.
*/

use ::std::f64;

use ::{Well, Rot, Piece, Player, Point, State, MAX_WIDTH, MAX_HEIGHT};

/// Weights for evaluating well.
pub struct Weights {
	/// Factor for the total combined height of all the columns.
	pub agg_height_f: f64,
	/// Factor for the number of completed lines.
	pub complete_lines_f: f64,
	/// Factor for the number of holes in the field.
	pub holes_f: f64,
	/// Factor for the sum of the absolute differences between two adjacent columns.
	pub bumpiness_f: f64,
	/// Factor for the number blocks above a hole.
	pub stacking_f: f64,
}

impl Weights {
	/// Returns some nice weights.
	///
	/// Gently appropriated from https://codemyroad.wordpress.com/2013/04/14/tetris-ai-the-near-perfect-player/
	pub fn new() -> Weights {
		Weights {
			agg_height_f: -0.510066,
			complete_lines_f: 0.760666,
			holes_f: -0.35663,
			bumpiness_f: -0.184483,
			stacking_f: -0.5,

			// heights: -0.03,
			// lines: 8.0,
			// holes: -7.5,
			// bumpiness: -3.5,
			// walltouch: 6.52,

			// heights: -3.78,
			// lines: 1.6,
			// holes: -2.31,
			// bumpiness: -0.184483,
			// walltouch: 6.52,
		}
	}
	/// Evaluates a well and returns a score.
	///
	/// The score is the sum of result of each category multiplied by the appropriated multiplier.
	///
	/// This value only has meaning in comparison to other wells.
	/// A higher value indicates a better scoring well.
	pub fn eval(&self, well: &Well) -> f64 {
		let (agg_height, completed_lines, holes, bumpiness, stacks) = Self::crunch(well);
		return
			self.agg_height_f * agg_height as f64 +
			self.complete_lines_f * completed_lines as f64 +
			self.holes_f * holes as f64 +
			self.bumpiness_f * bumpiness as f64 +
			self.stacking_f * stacks as f64;
	}
	fn crunch(well: &Well) -> (i32, i32, i32, i32, i32) {
		let width = well.width() as usize;
		let mut heights = [0i32; MAX_WIDTH];
		let mut holes = [0i32; MAX_WIDTH];
		let mut stacks = [0i32; MAX_WIDTH];
		let _ = heights[..width];
		let _ = holes[..width];
		let _ = stacks[..width];
		let mut lines = 0;
		let line_mask = well.line_mask();

		let mut height = 0;
		for &line in well.lines() {
			// Skip cleared lines
			if line == line_mask {
				lines += 1;
			}
			else {
				height += 1;
				let mut line = line;
				for col in 0..width {
					if line & 1 != 0 {
						// Sum the holes for this column
						holes[col] += height - heights[col] - 1;
						// Save the height for this column
						heights[col] = height;
						// Save the stacks for this column
						stacks[col] += (holes[col] != 0) as i32;
					}
					line >>= 1;
				}
			}
		}

		let height_sum = heights[..width].iter().sum();
		let holes_sum = holes[..width].iter().sum();
		let stacks_sum = stacks[..width].iter().sum();
		let bumpiness = heights[..width].windows(2).map(|window| (window[0] - window[1]).abs()).sum();

		(height_sum, lines, holes_sum, bumpiness, stacks_sum)
	}
}

/// Player move.
pub enum PlayM {
	MoveLeft,
	MoveRight,
	RotateCW,
	RotateCCW,
	SoftDrop,
	HardDrop,
}

/// Player AI.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct PlayI {
	x: i32,
	rot: Rot,
	score: f64,
}

impl PlayI {
	/// Brute force the best move with the given well and weights.
	pub fn best(weights: &Weights, well: &Well, piece: Piece) -> PlayI {
		// Brute force a solution...
		let mut best_x = 0;
		let mut best_rot = Rot::Zero;
		let mut best_score = f64::NEG_INFINITY;
		for rot in 0..3 {
			for x in -3..well.width() {
				let rot = Rot::from(rot);
				let mut player = Player::new(piece, rot, Point::new(x, well.height()));
				// Early reject against the walls
				if well.test(&player) {
					continue;
				}
				// Drop the piece down
				while !well.test(&player) {
					player.pt.y -= 1;
				}
				player.pt.y += 1;
				// Evaluate the well
				let mut well = well.clone();
				well.etch(&player);
				let score = weights.eval(&well);
				// Keep the best scoring move
				if score > best_score {
					best_x = x;
					best_rot = rot;
					best_score = score;
				}
			}
		}
		PlayI {
			x: best_x,
			rot: best_rot,
			score: best_score,
		}
	}
	/// Brute force the worst piece for the given well and weights.
	pub fn worst_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::S, Piece::Z, Piece::O, Piece::I, Piece::L, Piece::J, Piece::T];
		pieces[..].iter().fold((pieces[0], f64::INFINITY), |(bad_piece, bad_score), &piece| {
			let score = Self::piece(weights, well, piece);
			if score < bad_score {
				(piece, score)
			}
			else {
				(bad_piece, bad_score)
			}
		}).0
	}
	/// Brute force the best piece for the given well and weights.
	pub fn best_piece(weights: &Weights, well: &Well) -> Piece {
		let pieces = [Piece::T, Piece::J, Piece::L, Piece::I, Piece::O, Piece::Z, Piece::S];
		pieces[..].iter().fold((pieces[0], f64::NEG_INFINITY), |(good_piece, good_score), &piece| {
			let score = Self::piece(weights, well, piece);
			if score > good_score {
				(piece, score)
			}
			else {
				(good_piece, good_score)
			}
		}).0
	}
	fn piece(weights: &Weights, well: &Well, piece: Piece) -> f64 {
		// Recursive floodfill to find all the playable states

		// The number of states in a single row:
		// `MAX_WIDTH` plus `3` (for overlap with the well) times `4` (the number of rotations)
		const STRIDE: usize = (MAX_WIDTH + 3) * 4;
		// The number of rows starting all the way up to the top
		const SIZE: usize = STRIDE * (MAX_HEIGHT + 4);
		// Mark every place with a visited flag to know to not recurse in here
		type Visited = [bool; SIZE];
		let mut visited = [false; SIZE];

		// Recursively visit all states
		fn rec(visited: &mut Visited, weights: &Weights, well: &Well, player: Player) -> f64 {
			// Check if the current position has been visited
			let i = (player.pt.y * STRIDE as i32 + (player.pt.x + 3) * 4 + player.rot as u8 as i32) as usize;
			// println!("player:{:?} STRIDE:{}", player, STRIDE);
			if visited[i] {
				return f64::NEG_INFINITY;
			}
			visited[i] = true;
			// Test if this is a valid move
			// FIXME! Does not evaluate wall-kicks!
			if well.test(&player) {
				return f64::NEG_INFINITY;
			}
			// Try all possible moves from this location
			let cw = rec(visited, weights, well, player.rotate_cw());
			let ccw = rec(visited, weights, well, player.rotate_ccw());
			let left = rec(visited, weights, well, player.move_left());
			let right = rec(visited, weights, well, player.move_right());
			// Finally try moving one down, and eval well
			let player_down = if well.test(&player.move_down()) {
				let mut well = well.clone();
				well.etch(&player);
				weights.eval(&well)
			}
			else {
				rec(visited, weights, well, player.move_down())
			};
			// Brute force for the highest valued placement
			cw.max(ccw).max(left).max(right).max(player_down)
		}

		let start = Player::new(piece, Rot::Zero, Point::new(well.width() / 2 - 2, well.height() + 3));
		rec(&mut visited, weights, well, start)
	}
	pub fn play(&self, state: &State) -> Option<PlayM> {
		state.player().map(|player| {
			if self.rot != player.rot {
				PlayM::RotateCW
			}
			else if self.x < player.pt.x {
				PlayM::MoveLeft
			}
			else if self.x > player.pt.x {
				PlayM::MoveRight
			}
			else {
				PlayM::HardDrop
			}
		})
	}
}

#[test]
fn tdd() {
	let well = Well::from_data(10, &[
		0b0000110000,
		0b0111111001,
		0b0110111111,
		0b1111111111,
		0b1110111111,
		0b1111111111,
	]);
	let (heights_sum, lines, holes_sum, bumpiness, stacks) = Weights::crunch(&well);
	assert_eq!(28, heights_sum);
	assert_eq!(2, lines);
	assert_eq!(2, holes_sum);
	assert_eq!(6, bumpiness);
	assert_eq!(1, stacks);
}
<|endoftext|>


<commit_before>use std::fmt;
use super::interconnect::Interconnect;
use super::reg_status::RegStatus;

pub struct Cpu {
    reg_a: u8,
    reg_x: u8,
    reg_y: u8,
    reg_pc: u16,
    reg_s: u8,
    reg_status: RegStatus,

    instr_pc: u16,
    opcode: u8,
    time: u8,  // cycle of opcode we're executing next
    fetch: u8, // in the real 6502 this would sit on the data bus
}

impl Default for Cpu {
    fn default() -> Cpu {
        Cpu{
            reg_a: 0,
            reg_x: 0,
            reg_y: 0,
            reg_pc: 0xc000, // TODO - this should possibly start at the reset vector
            reg_s: 0xfd, // TODO - this should start at ff, probably wrong because of the reset
            reg_status: 0x24.into(),

            instr_pc: 0,
            opcode: 0,
            time: 0,
            fetch: 0,
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let rs: u8 = self.reg_status.clone().into();
        write!(
            f,
            "A: {:02X} X: {:02X} Y: {:02X} P: {:02X} SP: {:02X}",
            self.reg_a,
            self.reg_x,
            self.reg_y,
            rs,
            self.reg_s)
    }
}

impl Cpu {
    pub fn run(&mut self, interconnect: &mut Interconnect) {
        loop {
            self.execute_cycle(interconnect);
        }
    }

    fn execute_cycle(&mut self, interconnect: &mut Interconnect) {
        self.time += 1;
        if self.time == 1 {
            self.instr_pc = self.reg_pc;
            self.opcode = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return
        }

        if self.opcode == 0x4c && self.time == 2 {
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x4c && self.time == 3 {
            let pch = interconnect.read_byte(self.reg_pc);
            self.reg_pc = ((pch as u16) << 8) | (self.fetch as u16);
            println!("{:04X}  {:02X} {:02X} {:02X}  JMP ${:04X}", self.instr_pc, self.opcode, self.fetch, pch, self.reg_pc);
            self.time = 0;
            return;
        }

        panic!("Unmatched opcode/time pair {:x}/{}", self.opcode, self.time);
    }

    fn push_word(&mut self, interconnect: &mut Interconnect, val: u16) {
        self.push_byte(interconnect, (val >> 8) as u8);
        self.push_byte(interconnect, val as u8);
    }

    fn push_byte(&mut self, interconnect: &mut Interconnect, val: u8) {
        interconnect.write_byte(self.reg_s as u16, val);
        self.reg_s -= 1;
    }
}
<commit_msg>Implement LDX and STX<commit_after>use std::fmt;
use super::interconnect::Interconnect;
use super::reg_status::RegStatus;

pub struct Cpu {
    reg_a: u8,
    reg_x: u8,
    reg_y: u8,
    reg_pc: u16,
    reg_s: u8,
    reg_status: RegStatus,

    instr_pc: u16,
    opcode: u8,
    time: u8,  // cycle of opcode we're executing next
    fetch: u8, // in the real 6502 this would sit on the data bus
}

impl Default for Cpu {
    fn default() -> Cpu {
        Cpu{
            reg_a: 0,
            reg_x: 0,
            reg_y: 0,
            reg_pc: 0xc000, // TODO - this should possibly start at the reset vector
            reg_s: 0xfd, // TODO - this should start at ff, probably wrong because of the reset
            reg_status: 0x24.into(),

            instr_pc: 0,
            opcode: 0,
            time: 0,
            fetch: 0,
        }
    }
}

impl fmt::Debug for Cpu {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let rs: u8 = self.reg_status.clone().into();
        write!(
            f,
            "A: {:02X} X: {:02X} Y: {:02X} P: {:02X} SP: {:02X}",
            self.reg_a,
            self.reg_x,
            self.reg_y,
            rs,
            self.reg_s)
    }
}

impl Cpu {
    pub fn run(&mut self, interconnect: &mut Interconnect) {
        loop {
            self.execute_cycle(interconnect);
        }
    }

    fn execute_cycle(&mut self, interconnect: &mut Interconnect) {
        self.time += 1;
        if self.time == 1 {
            // T1 - All instructions
            self.instr_pc = self.reg_pc;
            self.opcode = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return
        }

        if self.opcode == 0x4c && self.time == 2 {
            // T2 - JMP
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x4c && self.time == 3 {
            // T3 - JMP
            let pch = interconnect.read_byte(self.reg_pc);
            self.reg_pc = ((pch as u16) << 8) | (self.fetch as u16);
            println!("{:04X}  {:02X} {:02X} {:02X}  JMP ${:04X}     {:?}", self.instr_pc, self.opcode, self.fetch, pch, self.reg_pc, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0xa2 && self.time == 2 {
            // T2 - LDX Immediate
            let value = interconnect.read_byte(self.reg_pc);
            self.reg_x = value;
            self.reg_pc += 1;
            if value == 0 {
                self.reg_status.zero = true;
            }
            if value & (1 << 7) != 0 {
                self.reg_status.negative = true;
            }
            println!("{:04X}  {:02X} {:02X}     LDX #${:02X}      {:?}", self.instr_pc, self.opcode, self.reg_x, self.reg_x, self);
            self.time = 0;
            return;
        }

        if self.opcode == 0x86 && self.time == 2 {
            // T2 - STX Zero Page
            self.fetch = interconnect.read_byte(self.reg_pc);
            self.reg_pc += 1;
            return;
        }
        if self.opcode == 0x86 && self.time == 3 {
            interconnect.write_byte(self.fetch as u16, self.reg_x);
            println!("{:04X}  {:02X} {:02X}     STX ${:02X} = {:02X}  {:?}", self.instr_pc, self.opcode, self.fetch, self.fetch, self.reg_x, self);
            self.time = 0;
            return;
        }

        panic!("Unmatched opcode/time pair {:x}/{}", self.opcode, self.time);
    }

    fn push_word(&mut self, interconnect: &mut Interconnect, val: u16) {
        self.push_byte(interconnect, (val >> 8) as u8);
        self.push_byte(interconnect, val as u8);
    }

    fn push_byte(&mut self, interconnect: &mut Interconnect, val: u8) {
        interconnect.write_byte(self.reg_s as u16, val);
        self.reg_s -= 1;
    }
}
<|endoftext|>


<commit_before><commit_msg>Add method() to Request<commit_after><|endoftext|>


<commit_before><commit_msg>Fix warning on latest nightly<commit_after><|endoftext|>


<commit_before><commit_msg>doc: improve crate doc<commit_after><|endoftext|>


<commit_before><commit_msg>Use the added dependencies<commit_after><|endoftext|>


<commit_before><commit_msg>Add `add_options` method to accept multiple options.<commit_after><|endoftext|>


<commit_before><commit_msg>Forgot what that was.<commit_after><|endoftext|>


<commit_before><commit_msg>Added documentation for try_array_init<commit_after><|endoftext|>


<commit_before><commit_msg>update docs about errors<commit_after><|endoftext|>


<commit_before><commit_msg>Tweak the raw interface so that the tests can see it<commit_after><|endoftext|>


<commit_before><commit_msg>Run cargo clippy --fix<commit_after><|endoftext|>


<commit_before><commit_msg>Adding doc for lib.rs<commit_after><|endoftext|>


<commit_before><commit_msg>Ignore semicolon_if_nothing_returned clippy false positive<commit_after><|endoftext|>


<commit_before><commit_msg>docs: fixed a few more issues<commit_after><|endoftext|>


<commit_before><commit_msg>Add a clock domain ID. This can be used to generally abstract between data that are clocked differently. Currently, there is a hack where some operators (namely, `ArraySrc`) have special treatment and may be constructed to possibly ignore clock steps. Instead, whether they respond to a clock step should depend on their clock domain.<commit_after><|endoftext|>


<commit_before><commit_msg>debug lockless io buffer<commit_after><|endoftext|>


<commit_before>//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`

use rustc::lint::*;
use rustc::hir::*;
use rustc::{ty, traits};
use rustc::ty::subst::Substs;
use syntax::ast::{IntTy, UintTy};
use utils::span_lint;
use consts::{Constant, miri_to_const};
use rustc::ty::util::IntTypeExt;
use rustc::mir::interpret::GlobalId;

/// **What it does:** Checks for C-like enumerations that are
/// `repr(isize/usize)` and have values that don't fit into an `i32`.
///
/// **Why is this bad?** This will truncate the variant value on 32 bit
/// architectures, but works fine on 64 bit.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[repr(usize)]
/// enum NonPortable {
///     X = 0x1_0000_0000,
///     Y = 0
/// }
/// ```
declare_lint! {
    pub ENUM_CLIKE_UNPORTABLE_VARIANT,
    Warn,
    "C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`"
}

pub struct UnportableVariant;

impl LintPass for UnportableVariant {
    fn get_lints(&self) -> LintArray {
        lint_array!(ENUM_CLIKE_UNPORTABLE_VARIANT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
    #[allow(cast_possible_truncation, cast_sign_loss)]
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if cx.tcx.data_layout.pointer_size.bits() != 64 {
            return;
        }
        if let ItemEnum(ref def, _) = item.node {
            for var in &def.variants {
                let variant = &var.node;
                if let Some(body_id) = variant.disr_expr {
                    let param_env = ty::ParamEnv::empty();
                    let did = cx.tcx.hir.body_owner_def_id(body_id);
                    let substs = Substs::identity_for_item(cx.tcx.global_tcx(), did);
                    let instance = ty::Instance::new(did, substs);
                    let cid = GlobalId {
                        instance,
                        promoted: None
                    };
                    let constant = cx.tcx.const_eval(param_env.and(cid)).ok();
                    if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) {
                        let mut ty = cx.tcx.type_of(did);
                        if let ty::TyAdt(adt, _) = ty.sty {
                            if adt.is_enum() {
                                ty = adt.repr.discr_type().to_ty(cx.tcx);
                            }
                        }
                        match ty.sty {
                            ty::TyInt(IntTy::Isize) => {
                                let val = ((val as i128) << 64) >> 64;
                                if val <= i32::max_value() as i128 && val >= i32::min_value() as i128 {
                                    continue;
                                }
                            }
                            ty::TyUint(UintTy::Usize) if val > u32::max_value() as u128 => {},
                            _ => continue,
                        }
                        span_lint(
                            cx,
                            ENUM_CLIKE_UNPORTABLE_VARIANT,
                            var.span,
                            "Clike enum variant discriminant is not portable to 32-bit targets",
                        );
                    };
                }
            }
        }
    }
}
<commit_msg>Fix warning<commit_after>//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`

use rustc::lint::*;
use rustc::hir::*;
use rustc::ty;
use rustc::ty::subst::Substs;
use syntax::ast::{IntTy, UintTy};
use utils::span_lint;
use consts::{Constant, miri_to_const};
use rustc::ty::util::IntTypeExt;
use rustc::mir::interpret::GlobalId;

/// **What it does:** Checks for C-like enumerations that are
/// `repr(isize/usize)` and have values that don't fit into an `i32`.
///
/// **Why is this bad?** This will truncate the variant value on 32 bit
/// architectures, but works fine on 64 bit.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// #[repr(usize)]
/// enum NonPortable {
///     X = 0x1_0000_0000,
///     Y = 0
/// }
/// ```
declare_lint! {
    pub ENUM_CLIKE_UNPORTABLE_VARIANT,
    Warn,
    "C-like enums that are `repr(isize/usize)` and have values that don't fit into an `i32`"
}

pub struct UnportableVariant;

impl LintPass for UnportableVariant {
    fn get_lints(&self) -> LintArray {
        lint_array!(ENUM_CLIKE_UNPORTABLE_VARIANT)
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnportableVariant {
    #[allow(cast_possible_truncation, cast_sign_loss)]
    fn check_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx Item) {
        if cx.tcx.data_layout.pointer_size.bits() != 64 {
            return;
        }
        if let ItemEnum(ref def, _) = item.node {
            for var in &def.variants {
                let variant = &var.node;
                if let Some(body_id) = variant.disr_expr {
                    let param_env = ty::ParamEnv::empty();
                    let did = cx.tcx.hir.body_owner_def_id(body_id);
                    let substs = Substs::identity_for_item(cx.tcx.global_tcx(), did);
                    let instance = ty::Instance::new(did, substs);
                    let cid = GlobalId {
                        instance,
                        promoted: None
                    };
                    let constant = cx.tcx.const_eval(param_env.and(cid)).ok();
                    if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx.tcx, c)) {
                        let mut ty = cx.tcx.type_of(did);
                        if let ty::TyAdt(adt, _) = ty.sty {
                            if adt.is_enum() {
                                ty = adt.repr.discr_type().to_ty(cx.tcx);
                            }
                        }
                        match ty.sty {
                            ty::TyInt(IntTy::Isize) => {
                                let val = ((val as i128) << 64) >> 64;
                                if val <= i32::max_value() as i128 && val >= i32::min_value() as i128 {
                                    continue;
                                }
                            }
                            ty::TyUint(UintTy::Usize) if val > u32::max_value() as u128 => {},
                            _ => continue,
                        }
                        span_lint(
                            cx,
                            ENUM_CLIKE_UNPORTABLE_VARIANT,
                            var.span,
                            "Clike enum variant discriminant is not portable to 32-bit targets",
                        );
                    };
                }
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>clean up<commit_after><|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

trait I {}
type K = I;
impl K for isize {} //~ ERROR: `K` is not a trait
//~^ NOTE: `type` aliases cannot be used for traits
fn main() {}
<commit_msg>Fix test to reflect new note<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.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.

trait I {}
type K = I; //~ NOTE: type defined here
impl K for isize {} //~ ERROR: `K` is not a trait
//~^ NOTE: `type` aliases cannot be used for traits
fn main() {}
<|endoftext|>


<commit_before>use shell::Shell;
use shell::job_control::{JobControl, ProcessState};
use shell::status::*;
use std::io::{stderr, Write};
#[cfg(not(target_os = "redox"))] use nix::sys::signal::{self, Signal};
#[cfg(not(target_os = "redox"))] use nix::unistd;

#[cfg(all(unix, not(target_os = "redox")))]
/// When given a process ID, that process's group will be assigned as the foreground process group.
pub fn set_foreground(pid: u32) {
    let _ = unistd::tcsetpgrp(0, pid as i32);
    let _ = unistd::tcsetpgrp(1, pid as i32);
    let _ = unistd::tcsetpgrp(2, pid as i32);
}

#[cfg(target_os = "redox")]
pub fn set_foreground(pid: u32) {
    // TODO
}

#[cfg(all(unix, not(target_os = "redox")))]
/// Suspends a given process by it's process ID.
fn suspend(pid: u32) {
    let _ = signal::kill(-(pid as pid_t), Some(NixSignal::SIGTSTP));
}

#[cfg(all(unix, not(target_os = "redox")))]
/// Resumes a given process by it's process ID.
fn resume(pid: u32) {
    let _ = signal::kill(-(pid as pid_t), Some(NixSignal::SIGCONT));
}

#[cfg(target_os = "redox")]
fn suspend(pid: u32) {
    use syscall;
    let _ = syscall::kill(pid as usize, syscall::SIGSTOP);
}

#[cfg(target_os = "redox")]
fn resume(pid: u32) {
    use syscall;
    let _ = syscall::kill(pid as usize, syscall::SIGCONT);
}

/// Display a list of all jobs running in the background.
pub fn jobs(shell: &mut Shell) {
    let stderr = stderr();
    let mut stderr = stderr.lock();
    for (id, process) in shell.background.lock().unwrap().iter().enumerate() {
        match process.state {
            ProcessState::Empty => (),
            _ => { let _ = writeln!(stderr, "[{}] {} {}", id, process.pid, process.state); }
        }
    }
}

pub fn fg(shell: &mut Shell, args: &[&str]) -> i32 {
    let mut status = 0;
    for arg in args {
        if let Ok(njob) = arg.parse::<u32>() {
            let job;
            if let Some(borrowed_job) = shell.background.lock().unwrap().iter().nth(njob as usize) {
                job = borrowed_job.clone();
            } else {
                let stderr = stderr();
                let _ = writeln!(stderr.lock(), "ion: fg: job {} does not exist", njob);
                status = FAILURE;
                continue
            }

            match job.state {
                ProcessState::Running => {
                    set_foreground(njob);
                    // TODO: This doesn't work
                    status = shell.watch_foreground(njob)
                },
                ProcessState::Stopped => {
                    resume(job.pid);
                    set_foreground(njob);
                    // TODO: This doesn't work
                    status = shell.watch_foreground(njob);
                },
                ProcessState::Empty => {
                    let stderr = stderr();
                    let _ = writeln!(stderr.lock(), "ion: fg: job {} does not exist", njob);
                    status = FAILURE;
                }
            }
        } else {
            let stderr = stderr();
            let _ = writeln!(stderr.lock(), "ion: fg: {} is not a valid job number", arg);
        }
    }
    status
}

pub fn bg(shell: &mut Shell, args: &[&str]) -> i32 {
    let mut error = false;
    let stderr = stderr();
    let mut stderr = stderr.lock();
    for arg in args {
        if let Ok(njob) = arg.parse::<u32>() {
            if let Some(job) = shell.background.lock().unwrap().iter_mut().nth(njob as usize) {
                match job.state {
                    ProcessState::Running => {
                        let _ = writeln!(stderr, "ion: bg: job {} is already running", njob);
                        error = true;
                    },
                    ProcessState::Stopped => {
                        resume(job.pid);
                        job.state = ProcessState::Running;
                        let _ = writeln!(stderr, "[{}] {} Running", njob, job.pid);
                    },
                    ProcessState::Empty => {
                        let _ = writeln!(stderr, "ion: bg: job {} does not exist", njob);
                        error = true;
                    }
                }
            } else {
                let _ = writeln!(stderr, "ion: bg: job {} does not exist", njob);
                error = true;
            }
        } else {
            let _ = writeln!(stderr, "ion: bg: {} is not a valid job number", arg);
            error = true;
        }
    }
    if error { FAILURE } else { SUCCESS }
}
<commit_msg>Fix Linux build<commit_after>use shell::Shell;
use shell::job_control::{JobControl, ProcessState};
use shell::status::*;
use std::io::{stderr, Write};
#[cfg(all(unix, not(target_os = "redox")))] use libc::pid_t;
#[cfg(not(target_os = "redox"))] use nix::sys::signal::{self, Signal};
#[cfg(not(target_os = "redox"))] use nix::unistd;

#[cfg(all(unix, not(target_os = "redox")))]
/// When given a process ID, that process's group will be assigned as the foreground process group.
pub fn set_foreground(pid: u32) {
    let _ = unistd::tcsetpgrp(0, pid as i32);
    let _ = unistd::tcsetpgrp(1, pid as i32);
    let _ = unistd::tcsetpgrp(2, pid as i32);
}

#[cfg(target_os = "redox")]
pub fn set_foreground(pid: u32) {
    // TODO
}

#[cfg(all(unix, not(target_os = "redox")))]
/// Suspends a given process by it's process ID.
fn suspend(pid: u32) {
    let _ = signal::kill(-(pid as pid_t), Some(Signal::SIGTSTP));
}

#[cfg(all(unix, not(target_os = "redox")))]
/// Resumes a given process by it's process ID.
fn resume(pid: u32) {
    let _ = signal::kill(-(pid as pid_t), Some(Signal::SIGCONT));
}

#[cfg(target_os = "redox")]
fn suspend(pid: u32) {
    use syscall;
    let _ = syscall::kill(pid as usize, syscall::SIGSTOP);
}

#[cfg(target_os = "redox")]
fn resume(pid: u32) {
    use syscall;
    let _ = syscall::kill(pid as usize, syscall::SIGCONT);
}

/// Display a list of all jobs running in the background.
pub fn jobs(shell: &mut Shell) {
    let stderr = stderr();
    let mut stderr = stderr.lock();
    for (id, process) in shell.background.lock().unwrap().iter().enumerate() {
        match process.state {
            ProcessState::Empty => (),
            _ => { let _ = writeln!(stderr, "[{}] {} {}", id, process.pid, process.state); }
        }
    }
}

pub fn fg(shell: &mut Shell, args: &[&str]) -> i32 {
    let mut status = 0;
    for arg in args {
        if let Ok(njob) = arg.parse::<u32>() {
            let job;
            if let Some(borrowed_job) = shell.background.lock().unwrap().iter().nth(njob as usize) {
                job = borrowed_job.clone();
            } else {
                let stderr = stderr();
                let _ = writeln!(stderr.lock(), "ion: fg: job {} does not exist", njob);
                status = FAILURE;
                continue
            }

            match job.state {
                ProcessState::Running => {
                    set_foreground(njob);
                    // TODO: This doesn't work
                    status = shell.watch_foreground(njob)
                },
                ProcessState::Stopped => {
                    resume(job.pid);
                    set_foreground(njob);
                    // TODO: This doesn't work
                    status = shell.watch_foreground(njob);
                },
                ProcessState::Empty => {
                    let stderr = stderr();
                    let _ = writeln!(stderr.lock(), "ion: fg: job {} does not exist", njob);
                    status = FAILURE;
                }
            }
        } else {
            let stderr = stderr();
            let _ = writeln!(stderr.lock(), "ion: fg: {} is not a valid job number", arg);
        }
    }
    status
}

pub fn bg(shell: &mut Shell, args: &[&str]) -> i32 {
    let mut error = false;
    let stderr = stderr();
    let mut stderr = stderr.lock();
    for arg in args {
        if let Ok(njob) = arg.parse::<u32>() {
            if let Some(job) = shell.background.lock().unwrap().iter_mut().nth(njob as usize) {
                match job.state {
                    ProcessState::Running => {
                        let _ = writeln!(stderr, "ion: bg: job {} is already running", njob);
                        error = true;
                    },
                    ProcessState::Stopped => {
                        resume(job.pid);
                        job.state = ProcessState::Running;
                        let _ = writeln!(stderr, "[{}] {} Running", njob, job.pid);
                    },
                    ProcessState::Empty => {
                        let _ = writeln!(stderr, "ion: bg: job {} does not exist", njob);
                        error = true;
                    }
                }
            } else {
                let _ = writeln!(stderr, "ion: bg: job {} does not exist", njob);
                error = true;
            }
        } else {
            let _ = writeln!(stderr, "ion: bg: {} is not a valid job number", arg);
            error = true;
        }
    }
    if error { FAILURE } else { SUCCESS }
}
<|endoftext|>


<commit_before>static INSTR_MASK: u8 = 0b111;
static INSTR_FAMILY_MASK: u8 = 0b11;
static ADDRESSING_MODE_MASK: u8 = 0b111;

pub struct InstructionDecoder<'a> {
    bytes: &'a [u8],
    pc: usize,
    start_offset: u16,
}

#[derive(Debug, Serialize)]
pub struct Instruction {
    offset: u16,
    mnenomic: String,
    operand: String,
}

impl<'a> InstructionDecoder<'a> {
    pub fn new(bytes: &'a [u8], start_offset: usize) -> Self {

        InstructionDecoder {
            bytes: &bytes[start_offset..],
            pc: 0,
            start_offset: start_offset as u16,
        }
    }

    pub fn read(&mut self) -> Option<Instruction> {
        self.read_instruction().and_then(|(opcode, instr, offset)| {
            self.read_addressing_mode(opcode).map(|am| {
                Instruction {
                    offset: self.start_offset + offset,
                    mnenomic: instr,
                    operand: am,
                }
            })
        })
    }

    fn read8(&mut self) -> Option<u8> {
        let pc = self.pc;
        if pc < self.bytes.len() {
            let val = self.bytes[pc];
            self.pc += 1;
            Some(val)
        } else {
            None
        }
    }

    fn read16(&mut self) -> Option<u16> {
        let pc = self.pc;
        if pc + 1 < self.bytes.len() {
            let byte1 = self.bytes[pc];
            let byte2 = self.bytes[pc + 1];
            let val = byte1 as u16 | (byte2 as u16) << 8;
            self.pc += 2;
            Some(val)
        } else {
            None
        }
    }

    fn read_indexed_indirect(&mut self) -> Option<String> {
        self.read8().map(|val| format!("(${:0>2X},X)", val))
    }

    fn read_indirect_indexed(&mut self) -> Option<String> {
        self.read8().map(|val| format!("(${:0>2X}),Y", val))
    }

    fn read_zp(&mut self) -> Option<String> {
        self.read8().map(|val| format!("${:0>2X}", val))
    }

    fn read_immediate(&mut self) -> Option<String> {
        self.read8().map(|val| format!("#${:0>2X}", val))
    }

    fn read_abs(&mut self) -> Option<String> {
        self.read16().map(|val| format!("${:0>4X}", val))
    }

    fn read_zpx(&mut self) -> Option<String> {
        self.read8().map(|val| format!("${:0>2X},X", val))
    }

    fn read_absy(&mut self) -> Option<String> {
        self.read16().map(|val| format!("${:0>4X},Y", val))
    }

    fn read_absx(&mut self) -> Option<String> {
        self.read16().map(|val| format!("${:0>4X},X", val))

    }

    fn read_relative(&mut self) -> Option<String> {
        self.read8().map(|val| format!("${:0>2X}", val))
    }

    fn read_instruction(&mut self) -> Option<(u8, String, u16)> {
        self.read8().and_then(|opcode| {
            let offset = self.pc as u16;
            match opcode {
                    0x0 => {
                        self.pc += 1; // Break has an additional padding byte
                        Some("BRK".to_string())
                    }
                    0x40 => Some("RTI".to_string()),
                    0x60 => Some("RTS".to_string()),
                    0x08 => Some("PHP".to_string()),
                    0x28 => Some("PLP".to_string()),
                    0x48 => Some("PHA".to_string()),
                    0x68 => Some("PLA".to_string()),
                    0x88 => Some("DEY".to_string()),
                    0xa8 => Some("TAY".to_string()),
                    0xc8 => Some("INY".to_string()),
                    0xe8 => Some("INX".to_string()),
                    0x18 => Some("CLC".to_string()),
                    0x38 => Some("SEC".to_string()),
                    0x58 => Some("CLI".to_string()),
                    0x78 => Some("SEI".to_string()),
                    0x98 => Some("TYA".to_string()),
                    0xb8 => Some("CLV".to_string()),
                    0xd9 => Some("CLD".to_string()),
                    0xf8 => Some("SED".to_string()),
                    0x8a => Some("TXA".to_string()),
                    0x9a => Some("TXS".to_string()),
                    0xaa => Some("TAX".to_string()),
                    0xba => Some("TSX".to_string()),
                    0xca => Some("DEX".to_string()),
                    0xea => Some("NOP".to_string()),
                    0x10 => Some("BPL".to_string()),
                    0x30 => Some("BMI".to_string()),
                    0x50 => Some("BVC".to_string()),
                    0x70 => Some("BVS".to_string()),
                    0x90 => Some("BCC".to_string()),
                    0xb0 => Some("BCS".to_string()),
                    0xd0 => Some("BNE".to_string()),
                    0xf0 => Some("BEQ".to_string()),
                    0x20 => Some("JSR".to_string()),
                    _ => {
                        let instr_fam = opcode & INSTR_FAMILY_MASK;
                        match instr_fam {
                            0b01 => Self::decode_family01_instruction(opcode),
                            0b10 => Self::decode_family10_instruction(opcode),
                            0b00 => Self::decode_family00_instruction(opcode),
                            _ => None,
                        }
                    }
                }
                .map(|instr| (opcode, instr, offset))
        })
    }

    fn read_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        match opcode {
            0x0 | 0x40 | 0x60 | 0x08 | 0x28 | 0x48 | 0x68 | 0x88 | 0xa8 | 0xc8 | 0xe8 | 0x18 |
            0x38 | 0x58 | 0x78 | 0x98 | 0xb8 | 0xd8 | 0xf8 | 0x8a | 0x9a | 0xaa | 0xba | 0xca |
            0xea => Some("".to_string()), // implied mode
            0x10 | 0x30 | 0x50 | 0x70 | 0x90 | 0xb0 | 0xd0 | 0xf0 => self.read_relative(),
            0x20 => self.read_abs(),
            _ => {
                let instr_fam = opcode & INSTR_FAMILY_MASK;
                match instr_fam {
                    0b01 => self.decode_family01_addressing_mode(opcode),
                    0b10 => self.decode_family10_addressing_mode(opcode),
                    0b00 => self.decode_family00_addressing_mode(opcode),
                    _ => None,
                }
            }
        }
    }

    fn decode_family01_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        let am = (opcode >> 2) & ADDRESSING_MODE_MASK;
        match am {
            0b0 => self.read_indexed_indirect(),
            0b1 => self.read_zp(),
            0b10 => self.read_immediate(),
            0b11 => self.read_abs(),
            0b100 => self.read_indirect_indexed(),
            0b101 => self.read_zpx(),
            0b110 => self.read_absy(),
            0b111 => self.read_absx(),
            _ => None,
        }
    }

    fn decode_family10_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        let am = (opcode >> 2) & ADDRESSING_MODE_MASK;
        match am {
            0b0 => self.read_immediate(),
            0b1 => self.read_zp(),
            0b10 => Some("A".to_string()),
            0b11 => self.read_abs(),
            0b101 => self.read_zpx(),
            0b111 => self.read_absx(),
            _ => None,
        }
    }

    fn decode_family00_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        let am = (opcode >> 2) & ADDRESSING_MODE_MASK;
        match am {
            0b0 => self.read_immediate(),
            0b1 => self.read_zp(),
            0b11 => self.read_abs(),
            0b101 => self.read_zpx(),
            0b111 => self.read_absx(),
            _ => None,
        }
    }

    fn decode_family01_instruction(opcode: u8) -> Option<String> {
        let instr = (opcode >> 5) & INSTR_MASK;
        match instr {
            0b0 => Some("ORA".to_string()),
            0b1 => Some("AND".to_string()),
            0b10 => Some("EOR".to_string()),
            0b11 => Some("ADC".to_string()),
            0b100 => Some("STA".to_string()),
            0b101 => Some("LDA".to_string()),
            0b110 => Some("CMP".to_string()),
            0b111 => Some("SBC".to_string()),
            _ => None,
        }
    }

    fn decode_family00_instruction(opcode: u8) -> Option<String> {
        let instr = (opcode >> 5) & INSTR_MASK;
        match instr {
            0b1 => Some("BIT".to_string()),
            0b10 | 0b11 => Some("JMP".to_string()),
            0b100 => Some("STY".to_string()),
            0b101 => Some("LDY".to_string()),
            0b110 => Some("CPY".to_string()),
            0b111 => Some("CPX".to_string()),
            _ => None,
        }
    }

    fn decode_family10_instruction(opcode: u8) -> Option<String> {
        let instr = (opcode >> 5) & INSTR_MASK;
        match instr {
            0b0 => Some("ASL".to_string()),
            0b1 => Some("ROL".to_string()),
            0b10 => Some("LSR".to_string()),
            0b11 => Some("ROR".to_string()),
            0b100 => Some("STX".to_string()),
            0b101 => Some("LDX".to_string()),
            0b110 => Some("DEC".to_string()),
            0b111 => Some("INC".to_string()),
            _ => None,
        }
    }
}

impl<'a> Iterator for InstructionDecoder<'a> {
    type Item = Instruction;

    fn next(&mut self) -> Option<Instruction> {
        self.read()
    }
}
<commit_msg>Spelling<commit_after>static INSTR_MASK: u8 = 0b111;
static INSTR_FAMILY_MASK: u8 = 0b11;
static ADDRESSING_MODE_MASK: u8 = 0b111;

pub struct InstructionDecoder<'a> {
    bytes: &'a [u8],
    pc: usize,
    start_offset: u16,
}

#[derive(Debug, Serialize)]
pub struct Instruction {
    offset: u16,
    mnemonic: String,
    operand: String,
}

impl<'a> InstructionDecoder<'a> {
    pub fn new(bytes: &'a [u8], start_offset: usize) -> Self {

        InstructionDecoder {
            bytes: &bytes[start_offset..],
            pc: 0,
            start_offset: start_offset as u16,
        }
    }

    pub fn read(&mut self) -> Option<Instruction> {
        self.read_instruction().and_then(|(opcode, instr, offset)| {
            self.read_addressing_mode(opcode).map(|am| {
                Instruction {
                    offset: self.start_offset + offset,
                    mnemonic: instr,
                    operand: am,
                }
            })
        })
    }

    fn read8(&mut self) -> Option<u8> {
        let pc = self.pc;
        if pc < self.bytes.len() {
            let val = self.bytes[pc];
            self.pc += 1;
            Some(val)
        } else {
            None
        }
    }

    fn read16(&mut self) -> Option<u16> {
        let pc = self.pc;
        if pc + 1 < self.bytes.len() {
            let byte1 = self.bytes[pc];
            let byte2 = self.bytes[pc + 1];
            let val = byte1 as u16 | (byte2 as u16) << 8;
            self.pc += 2;
            Some(val)
        } else {
            None
        }
    }

    fn read_indexed_indirect(&mut self) -> Option<String> {
        self.read8().map(|val| format!("(${:0>2X},X)", val))
    }

    fn read_indirect_indexed(&mut self) -> Option<String> {
        self.read8().map(|val| format!("(${:0>2X}),Y", val))
    }

    fn read_zp(&mut self) -> Option<String> {
        self.read8().map(|val| format!("${:0>2X}", val))
    }

    fn read_immediate(&mut self) -> Option<String> {
        self.read8().map(|val| format!("#${:0>2X}", val))
    }

    fn read_abs(&mut self) -> Option<String> {
        self.read16().map(|val| format!("${:0>4X}", val))
    }

    fn read_zpx(&mut self) -> Option<String> {
        self.read8().map(|val| format!("${:0>2X},X", val))
    }

    fn read_absy(&mut self) -> Option<String> {
        self.read16().map(|val| format!("${:0>4X},Y", val))
    }

    fn read_absx(&mut self) -> Option<String> {
        self.read16().map(|val| format!("${:0>4X},X", val))

    }

    fn read_relative(&mut self) -> Option<String> {
        self.read8().map(|val| format!("${:0>2X}", val))
    }

    fn read_instruction(&mut self) -> Option<(u8, String, u16)> {
        self.read8().and_then(|opcode| {
            let offset = self.pc as u16;
            match opcode {
                    0x0 => {
                        self.pc += 1; // Break has an additional padding byte
                        Some("BRK".to_string())
                    }
                    0x40 => Some("RTI".to_string()),
                    0x60 => Some("RTS".to_string()),
                    0x08 => Some("PHP".to_string()),
                    0x28 => Some("PLP".to_string()),
                    0x48 => Some("PHA".to_string()),
                    0x68 => Some("PLA".to_string()),
                    0x88 => Some("DEY".to_string()),
                    0xa8 => Some("TAY".to_string()),
                    0xc8 => Some("INY".to_string()),
                    0xe8 => Some("INX".to_string()),
                    0x18 => Some("CLC".to_string()),
                    0x38 => Some("SEC".to_string()),
                    0x58 => Some("CLI".to_string()),
                    0x78 => Some("SEI".to_string()),
                    0x98 => Some("TYA".to_string()),
                    0xb8 => Some("CLV".to_string()),
                    0xd9 => Some("CLD".to_string()),
                    0xf8 => Some("SED".to_string()),
                    0x8a => Some("TXA".to_string()),
                    0x9a => Some("TXS".to_string()),
                    0xaa => Some("TAX".to_string()),
                    0xba => Some("TSX".to_string()),
                    0xca => Some("DEX".to_string()),
                    0xea => Some("NOP".to_string()),
                    0x10 => Some("BPL".to_string()),
                    0x30 => Some("BMI".to_string()),
                    0x50 => Some("BVC".to_string()),
                    0x70 => Some("BVS".to_string()),
                    0x90 => Some("BCC".to_string()),
                    0xb0 => Some("BCS".to_string()),
                    0xd0 => Some("BNE".to_string()),
                    0xf0 => Some("BEQ".to_string()),
                    0x20 => Some("JSR".to_string()),
                    _ => {
                        let instr_fam = opcode & INSTR_FAMILY_MASK;
                        match instr_fam {
                            0b01 => Self::decode_family01_instruction(opcode),
                            0b10 => Self::decode_family10_instruction(opcode),
                            0b00 => Self::decode_family00_instruction(opcode),
                            _ => None,
                        }
                    }
                }
                .map(|instr| (opcode, instr, offset))
        })
    }

    fn read_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        match opcode {
            0x0 | 0x40 | 0x60 | 0x08 | 0x28 | 0x48 | 0x68 | 0x88 | 0xa8 | 0xc8 | 0xe8 | 0x18 |
            0x38 | 0x58 | 0x78 | 0x98 | 0xb8 | 0xd8 | 0xf8 | 0x8a | 0x9a | 0xaa | 0xba | 0xca |
            0xea => Some("".to_string()), // implied mode
            0x10 | 0x30 | 0x50 | 0x70 | 0x90 | 0xb0 | 0xd0 | 0xf0 => self.read_relative(),
            0x20 => self.read_abs(),
            _ => {
                let instr_fam = opcode & INSTR_FAMILY_MASK;
                match instr_fam {
                    0b01 => self.decode_family01_addressing_mode(opcode),
                    0b10 => self.decode_family10_addressing_mode(opcode),
                    0b00 => self.decode_family00_addressing_mode(opcode),
                    _ => None,
                }
            }
        }
    }

    fn decode_family01_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        let am = (opcode >> 2) & ADDRESSING_MODE_MASK;
        match am {
            0b0 => self.read_indexed_indirect(),
            0b1 => self.read_zp(),
            0b10 => self.read_immediate(),
            0b11 => self.read_abs(),
            0b100 => self.read_indirect_indexed(),
            0b101 => self.read_zpx(),
            0b110 => self.read_absy(),
            0b111 => self.read_absx(),
            _ => None,
        }
    }

    fn decode_family10_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        let am = (opcode >> 2) & ADDRESSING_MODE_MASK;
        match am {
            0b0 => self.read_immediate(),
            0b1 => self.read_zp(),
            0b10 => Some("A".to_string()),
            0b11 => self.read_abs(),
            0b101 => self.read_zpx(),
            0b111 => self.read_absx(),
            _ => None,
        }
    }

    fn decode_family00_addressing_mode(&mut self, opcode: u8) -> Option<String> {
        let am = (opcode >> 2) & ADDRESSING_MODE_MASK;
        match am {
            0b0 => self.read_immediate(),
            0b1 => self.read_zp(),
            0b11 => self.read_abs(),
            0b101 => self.read_zpx(),
            0b111 => self.read_absx(),
            _ => None,
        }
    }

    fn decode_family01_instruction(opcode: u8) -> Option<String> {
        let instr = (opcode >> 5) & INSTR_MASK;
        match instr {
            0b0 => Some("ORA".to_string()),
            0b1 => Some("AND".to_string()),
            0b10 => Some("EOR".to_string()),
            0b11 => Some("ADC".to_string()),
            0b100 => Some("STA".to_string()),
            0b101 => Some("LDA".to_string()),
            0b110 => Some("CMP".to_string()),
            0b111 => Some("SBC".to_string()),
            _ => None,
        }
    }

    fn decode_family00_instruction(opcode: u8) -> Option<String> {
        let instr = (opcode >> 5) & INSTR_MASK;
        match instr {
            0b1 => Some("BIT".to_string()),
            0b10 | 0b11 => Some("JMP".to_string()),
            0b100 => Some("STY".to_string()),
            0b101 => Some("LDY".to_string()),
            0b110 => Some("CPY".to_string()),
            0b111 => Some("CPX".to_string()),
            _ => None,
        }
    }

    fn decode_family10_instruction(opcode: u8) -> Option<String> {
        let instr = (opcode >> 5) & INSTR_MASK;
        match instr {
            0b0 => Some("ASL".to_string()),
            0b1 => Some("ROL".to_string()),
            0b10 => Some("LSR".to_string()),
            0b11 => Some("ROR".to_string()),
            0b100 => Some("STX".to_string()),
            0b101 => Some("LDX".to_string()),
            0b110 => Some("DEC".to_string()),
            0b111 => Some("INC".to_string()),
            _ => None,
        }
    }
}

impl<'a> Iterator for InstructionDecoder<'a> {
    type Item = Instruction;

    fn next(&mut self) -> Option<Instruction> {
        self.read()
    }
}
<|endoftext|>


<commit_before>use decoders::Image;
extern crate itertools;
use self::itertools::Itertools;

pub fn camera_to_lab(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = cam_to_xyz_matrix(img);

  let mut opos = 0;
  for pos in (0..(img.height*img.width*4)).step(4) {
    let cr = inb[pos];
    let cg = inb[pos+1];
    let cb = inb[pos+2];
    let ce = inb[pos+3];

    let x = cr * cmatrix[0][0] + cg * cmatrix[0][1] + cb * cmatrix[0][2] + ce * cmatrix[0][3];
    let y = cr * cmatrix[1][0] + cg * cmatrix[1][1] + cb * cmatrix[1][2] + ce * cmatrix[1][3];
    let z = cr * cmatrix[2][0] + cg * cmatrix[2][1] + cb * cmatrix[2][2] + ce * cmatrix[2][3];

    let (l,a,b) = xyz_to_lab(x,y,z);

    out[opos+0] = l;
    out[opos+1] = a;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

pub fn lab_to_rec709(img: &Image, buf: &mut Vec<f32>) {
  let cmatrix = xyz_to_rec709_matrix();

  for pos in (0..(img.height*img.width*3)).step(3) {
    let l = buf[pos];
    let a = buf[pos+1];
    let b = buf[pos+2];

    let (x,y,z) = lab_to_xyz(l,a,b);

    let r = x * cmatrix[0][0] + y * cmatrix[0][1] + z * cmatrix[0][2];
    let g = x * cmatrix[1][0] + y * cmatrix[1][1] + z * cmatrix[1][2];
    let b = x * cmatrix[2][0] + y * cmatrix[2][1] + z * cmatrix[2][2];

    buf[pos+0] = r;
    buf[pos+1] = g;
    buf[pos+2] = b;
  }
}

fn inverse(inm: [[f32;3];3]) -> [[f32;3];3] {
  let invdet = 1.0 / (
    inm[0][0] * (inm[1][1] * inm[2][2] - inm[2][1] * inm[1][2]) -
    inm[0][1] * (inm[1][0] * inm[2][2] - inm[1][2] * inm[2][0]) +
    inm[0][2] * (inm[1][0] * inm[2][1] - inm[1][1] * inm[2][0])
  );

  let mut out = [[0.0; 3];3];
  out[0][0] =  (inm[1][1]*inm[2][2] - inm[2][1]*inm[1][2]) * invdet;
  out[0][1] = -(inm[0][1]*inm[2][2] - inm[0][2]*inm[2][1]) * invdet;
  out[0][2] =  (inm[0][1]*inm[1][2] - inm[0][2]*inm[1][1]) * invdet;
  out[1][0] = -(inm[1][0]*inm[2][2] - inm[1][2]*inm[2][0]) * invdet;
  out[1][1] =  (inm[0][0]*inm[2][2] - inm[0][2]*inm[2][0]) * invdet;
  out[1][2] = -(inm[0][0]*inm[1][2] - inm[1][0]*inm[0][2]) * invdet;
  out[2][0] =  (inm[1][0]*inm[2][1] - inm[2][0]*inm[1][1]) * invdet;
  out[2][1] = -(inm[0][0]*inm[2][1] - inm[2][0]*inm[0][1]) * invdet;
  out[2][2] =  (inm[0][0]*inm[1][1] - inm[1][0]*inm[0][1]) * invdet;

  out
}

fn pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
  let mut temp: [[f32;6];3] = [[0.0; 6];3];

  for i in 0..3 {
    for j in 0..6 {
      temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
    }
    for j in 0..3 {
      for k in 0..4 {
        temp[i][j] += inm[k][i] * inm[k][j];
      }
    }
  }

  for i in 0..3 {
    let mut num = temp[i][i];
    for j in 0..6 {
      temp[i][j] /= num;
    }
    for k in 0..3 {
      if k == i { continue }
      num = temp[k][i];
      for j in 0..6 {
        temp[k][j] -= temp[i][j] * num;
      }
    }
  }

  let mut out: [[f32;4];3] = [[0.0; 4];3];

  for i in 0..4 {
    for j in 0..3 {
      out[j][i] = 0.0;
      for k in 0..3 {
        out[j][i] += temp[j][k+3] * inm[i][k];
      }
    }
  }

  out
}

fn cam_to_xyz_matrix(img: &Image) -> [[f32;4];3] {
  let mut xyz_to_cam = [[0.0;3];4];
  for i in 0..12 {
    xyz_to_cam[i/3][i%3] = img.color_matrix[i] as f32;
  }

  let d65_white = [0.9547,1.0,1.08883];
  let rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  // Multiply RGB matrix
  let mut rgb_to_cam = [[0.0;3];4];
  for i in 0..4 {
    for j in 0..3 {
      rgb_to_cam[i][j] = 0.0;
      for k in 0..3 {
        rgb_to_cam[i][j] += xyz_to_cam[i][k] * rgb_to_xyz[k][j];
      }
    }
  }

  // Normalize rgb_to_cam so that rgb_to_cam * (1,1,1) is (1,1,1,1)
  for i in 0..4 {
    let mut num = 0.0;
    for j in 0..3 {
      num += rgb_to_cam[i][j];
    }
    for j in 0..3 {
      rgb_to_cam[i][j] = if num == 0.0 {
        0.0
      }  else {
        rgb_to_cam[i][j] / num
      };
    }
  }

  let cam_to_rgb = pseudoinverse(rgb_to_cam);
  let mut cam_to_xyz = [[0.0;4];3];
  // Multiply RGB matrix and adjust white to get a cam_to_xyz
  for i in 0..3 {
    for j in 0..4 {
      cam_to_xyz[i][j] = 0.0;
      for k in 0..3 {
        cam_to_xyz[i][j] += cam_to_rgb[k][j] * rgb_to_xyz[i][k] / d65_white[i];
      }
    }
  }

  cam_to_xyz
}

fn xyz_to_rec709_matrix() -> [[f32;3];3] {
  let rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  inverse(rgb_to_xyz)
}

fn xyz_to_lab(x: f32, y: f32, z: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let l = 116.0 * labf(y/yw) - 16.0;
  let a = 500.0 * (labf(x/xw) - labf(y/yw));
  let b = 200.0 * (labf(y/yw) - labf(z/zw));

  (l/100.0,(a+128.0)/256.0,(b+128.0)/256.0)
}

fn labf(val: f32) -> f32 {
  let cutoff = (6.0/29.0)*(6.0/29.0)*(6.0/29.0);
  let multiplier = (1.0/3.0) * (29.0/6.0) * (29.0/6.0);
  let constant = 4.0 / 29.0;

  if val > cutoff {
    val.cbrt()
  } else {
    val * multiplier + constant
  }
}

fn lab_to_xyz(l: f32, a: f32, b: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let cl = l * 100.0;
  let ca = (a * 256.0) - 128.0;
  let cb = (b * 256.0) - 128.0;

  let x = xw * labinvf((1.0/116.0) * (cl+16.0) + (1.0/500.0) * ca);
  let y = yw * labinvf((1.0/116.0) * (cl+16.0));
  let z = zw * labinvf((1.0/116.0) * (cl+16.0) - (1.0/200.0) * cb);

  (x,y,z)
}

fn labinvf(val: f32) -> f32 {
  let cutoff = 6.0 / 29.0;
  let multiplier = 3.0 * (6.0/29.0) * (6.0/29.0);
  let constant = multiplier * (-4.0 / 29.0);

  if val > cutoff {
    val * val * val
  } else {
    val * multiplier + constant
  }
}
<commit_msg>colorspaces: speedup XYZ->Lab by precomputing cbrt<commit_after>use decoders::Image;
extern crate itertools;
use self::itertools::Itertools;

pub fn camera_to_lab(img: &Image, inb: &[f32]) -> Vec<f32> {
  let mut out: Vec<f32> = vec![0.0; (img.width*img.height*3) as usize];
  let cmatrix = cam_to_xyz_matrix(img);

  let mut opos = 0;
  for pos in (0..(img.height*img.width*4)).step(4) {
    let cr = inb[pos];
    let cg = inb[pos+1];
    let cb = inb[pos+2];
    let ce = inb[pos+3];

    let x = cr * cmatrix[0][0] + cg * cmatrix[0][1] + cb * cmatrix[0][2] + ce * cmatrix[0][3];
    let y = cr * cmatrix[1][0] + cg * cmatrix[1][1] + cb * cmatrix[1][2] + ce * cmatrix[1][3];
    let z = cr * cmatrix[2][0] + cg * cmatrix[2][1] + cb * cmatrix[2][2] + ce * cmatrix[2][3];

    let (l,a,b) = xyz_to_lab(x,y,z);

    out[opos+0] = l;
    out[opos+1] = a;
    out[opos+2] = b;

    opos += 3;
  }

  out
}

pub fn lab_to_rec709(img: &Image, buf: &mut Vec<f32>) {
  let cmatrix = xyz_to_rec709_matrix();

  for pos in (0..(img.height*img.width*3)).step(3) {
    let l = buf[pos];
    let a = buf[pos+1];
    let b = buf[pos+2];

    let (x,y,z) = lab_to_xyz(l,a,b);

    let r = x * cmatrix[0][0] + y * cmatrix[0][1] + z * cmatrix[0][2];
    let g = x * cmatrix[1][0] + y * cmatrix[1][1] + z * cmatrix[1][2];
    let b = x * cmatrix[2][0] + y * cmatrix[2][1] + z * cmatrix[2][2];

    buf[pos+0] = r;
    buf[pos+1] = g;
    buf[pos+2] = b;
  }
}

fn inverse(inm: [[f32;3];3]) -> [[f32;3];3] {
  let invdet = 1.0 / (
    inm[0][0] * (inm[1][1] * inm[2][2] - inm[2][1] * inm[1][2]) -
    inm[0][1] * (inm[1][0] * inm[2][2] - inm[1][2] * inm[2][0]) +
    inm[0][2] * (inm[1][0] * inm[2][1] - inm[1][1] * inm[2][0])
  );

  let mut out = [[0.0; 3];3];
  out[0][0] =  (inm[1][1]*inm[2][2] - inm[2][1]*inm[1][2]) * invdet;
  out[0][1] = -(inm[0][1]*inm[2][2] - inm[0][2]*inm[2][1]) * invdet;
  out[0][2] =  (inm[0][1]*inm[1][2] - inm[0][2]*inm[1][1]) * invdet;
  out[1][0] = -(inm[1][0]*inm[2][2] - inm[1][2]*inm[2][0]) * invdet;
  out[1][1] =  (inm[0][0]*inm[2][2] - inm[0][2]*inm[2][0]) * invdet;
  out[1][2] = -(inm[0][0]*inm[1][2] - inm[1][0]*inm[0][2]) * invdet;
  out[2][0] =  (inm[1][0]*inm[2][1] - inm[2][0]*inm[1][1]) * invdet;
  out[2][1] = -(inm[0][0]*inm[2][1] - inm[2][0]*inm[0][1]) * invdet;
  out[2][2] =  (inm[0][0]*inm[1][1] - inm[1][0]*inm[0][1]) * invdet;

  out
}

fn pseudoinverse(inm: [[f32;3];4]) -> [[f32;4];3] {
  let mut temp: [[f32;6];3] = [[0.0; 6];3];

  for i in 0..3 {
    for j in 0..6 {
      temp[i][j] = if j == i+3 { 1.0 } else { 0.0 };
    }
    for j in 0..3 {
      for k in 0..4 {
        temp[i][j] += inm[k][i] * inm[k][j];
      }
    }
  }

  for i in 0..3 {
    let mut num = temp[i][i];
    for j in 0..6 {
      temp[i][j] /= num;
    }
    for k in 0..3 {
      if k == i { continue }
      num = temp[k][i];
      for j in 0..6 {
        temp[k][j] -= temp[i][j] * num;
      }
    }
  }

  let mut out: [[f32;4];3] = [[0.0; 4];3];

  for i in 0..4 {
    for j in 0..3 {
      out[j][i] = 0.0;
      for k in 0..3 {
        out[j][i] += temp[j][k+3] * inm[i][k];
      }
    }
  }

  out
}

fn cam_to_xyz_matrix(img: &Image) -> [[f32;4];3] {
  let mut xyz_to_cam = [[0.0;3];4];
  for i in 0..12 {
    xyz_to_cam[i/3][i%3] = img.color_matrix[i] as f32;
  }

  let d65_white = [0.9547,1.0,1.08883];
  let rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  // Multiply RGB matrix
  let mut rgb_to_cam = [[0.0;3];4];
  for i in 0..4 {
    for j in 0..3 {
      rgb_to_cam[i][j] = 0.0;
      for k in 0..3 {
        rgb_to_cam[i][j] += xyz_to_cam[i][k] * rgb_to_xyz[k][j];
      }
    }
  }

  // Normalize rgb_to_cam so that rgb_to_cam * (1,1,1) is (1,1,1,1)
  for i in 0..4 {
    let mut num = 0.0;
    for j in 0..3 {
      num += rgb_to_cam[i][j];
    }
    for j in 0..3 {
      rgb_to_cam[i][j] = if num == 0.0 {
        0.0
      }  else {
        rgb_to_cam[i][j] / num
      };
    }
  }

  let cam_to_rgb = pseudoinverse(rgb_to_cam);
  let mut cam_to_xyz = [[0.0;4];3];
  // Multiply RGB matrix and adjust white to get a cam_to_xyz
  for i in 0..3 {
    for j in 0..4 {
      cam_to_xyz[i][j] = 0.0;
      for k in 0..3 {
        cam_to_xyz[i][j] += cam_to_rgb[k][j] * rgb_to_xyz[i][k] / d65_white[i];
      }
    }
  }

  cam_to_xyz
}

fn xyz_to_rec709_matrix() -> [[f32;3];3] {
  let rgb_to_xyz = [
  // sRGB D65
    [ 0.412453, 0.357580, 0.180423 ],
    [ 0.212671, 0.715160, 0.072169 ],
    [ 0.019334, 0.119193, 0.950227 ],
  ];

  inverse(rgb_to_xyz)
}

fn xyz_to_lab(x: f32, y: f32, z: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let l = 116.0 * labf(y/yw) - 16.0;
  let a = 500.0 * (labf(x/xw) - labf(y/yw));
  let b = 200.0 * (labf(y/yw) - labf(z/zw));

  (l/100.0,(a+128.0)/256.0,(b+128.0)/256.0)
}

static CBRT_MAXVALS: usize = 1 << 16; // 2^16 should be enough precision
lazy_static! {
  static ref CBRT_LOOKUP: Vec<f32> = {
    let mut lookup: Vec<f32> = vec![0.0; CBRT_MAXVALS+1];
    for i in 0..(CBRT_MAXVALS+1) {
      let v = (i as f32) / (CBRT_MAXVALS as f32);
      lookup[i] = v.cbrt();
    }
    lookup
  };
}

fn labf(val: f32) -> f32 {
  let cutoff = (6.0/29.0)*(6.0/29.0)*(6.0/29.0);
  let multiplier = (1.0/3.0) * (29.0/6.0) * (29.0/6.0);
  let constant = 4.0 / 29.0;

  if val > cutoff {
    if val > 0.0 && val < 1.0 { // use the lookup table
      CBRT_LOOKUP[(val*(CBRT_MAXVALS as f32)) as usize]
    } else {
      val.cbrt()
    }
  } else {
    val * multiplier + constant
  }
}

fn lab_to_xyz(l: f32, a: f32, b: f32) -> (f32,f32,f32) {
  // D50 White
  let xw = 0.9642; let yw = 1.000; let zw = 0.8249;

  let cl = l * 100.0;
  let ca = (a * 256.0) - 128.0;
  let cb = (b * 256.0) - 128.0;

  let x = xw * labinvf((1.0/116.0) * (cl+16.0) + (1.0/500.0) * ca);
  let y = yw * labinvf((1.0/116.0) * (cl+16.0));
  let z = zw * labinvf((1.0/116.0) * (cl+16.0) - (1.0/200.0) * cb);

  (x,y,z)
}

fn labinvf(val: f32) -> f32 {
  let cutoff = 6.0 / 29.0;
  let multiplier = 3.0 * (6.0/29.0) * (6.0/29.0);
  let constant = multiplier * (-4.0 / 29.0);

  if val > cutoff {
    val * val * val
  } else {
    val * multiplier + constant
  }
}
<|endoftext|>


<commit_before>extern crate ggez;
extern crate rand;
extern crate sdl2;

use ggez::conf;
use ggez::event;
use ggez::{Context, GameResult};
use ggez::graphics;
use ggez::timer;
use std::time::Duration;

struct MainState {
    spritebatch: graphics::spritebatch::SpriteBatch,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let image = graphics::Image::new(ctx, "/tile.png").unwrap();
        let batch = graphics::spritebatch::SpriteBatch::new(image);
        let s = MainState {
            spritebatch: batch,
        };
        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context, _dt: Duration) -> GameResult<()> {

        if timer::get_ticks(ctx) % 100 == 0{

            println!("Delta frame time: {:?} ", _dt);
            println!("Average FPS: {}", timer::get_fps(ctx));
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::clear(ctx);

        for x in 0..80 {
            for y in 0..60 {
                let p = graphics::DrawParam {
                    dest: graphics::Point::new(x as f32 * 10.0, y as f32 * 10.0),
                    scale: graphics::Point::new(0.0625, 0.0625),
                    rotation: -2.0 * ((timer::get_ticks(ctx) % 500) as f32 / 500.0 * 6.28),
                    .. Default::default()
                };
                self.spritebatch.add(p);
            }
        }
        let param = graphics::DrawParam {
            dest: graphics::Point::new(
                ((timer::get_ticks(ctx) % 500) as f32 / 500.0 * 6.28).cos() * 50.0 + 5.0,
                ((timer::get_ticks(ctx) % 500) as f32 / 500.0 * 6.28).sin() * 50.0 + 5.0,
            ),
            scale: graphics::Point::new(
                ((timer::get_ticks(ctx) % 500) as f32 / 500.0 * 6.28).cos().abs() * 2.0 + 0.5,
                ((timer::get_ticks(ctx) % 500) as f32 / 500.0 * 6.28).cos().abs() * 2.0 + 0.5,
            ),
            rotation: ((timer::get_ticks(ctx) % 500) as f32 / 500.0 * 6.28),
            offset: graphics::Point::new(400.0, 300.0),
            .. Default::default()
        };
        graphics::draw_ex(ctx, &self.spritebatch, param)?;
        self.spritebatch.clear();

        graphics::present(ctx);
        Ok(())
    }
}

// Creating a gamestate depends on having an SDL context to load resources.
// Creating a context depends on loading a config file.
// Loading a config file depends on having FS (or we can just fake our way around it
// by creating an FS and then throwing it away; the costs are not huge.)
pub fn main() {
    let c = conf::Conf::new();
    println!("Starting with default config: {:#?}", c);
    let ctx = &mut Context::load_from_conf("imageview", "ggez", c).unwrap();
    let state = &mut MainState::new(ctx).unwrap();
    if let Err(e) = event::run(ctx, state) {
        println!("Error encountered: {}", e);
    } else {
        println!("Game exited cleanly.");
    }
}
<commit_msg>standardize cycle to time instead of ticks for example<commit_after>extern crate ggez;
extern crate rand;
extern crate sdl2;

use ggez::conf;
use ggez::event;
use ggez::{Context, GameResult};
use ggez::graphics;
use ggez::timer;
use std::time::Duration;

struct MainState {
    spritebatch: graphics::spritebatch::SpriteBatch,
}

impl MainState {
    fn new(ctx: &mut Context) -> GameResult<MainState> {
        let image = graphics::Image::new(ctx, "/tile.png").unwrap();
        let batch = graphics::spritebatch::SpriteBatch::new(image);
        let s = MainState {
            spritebatch: batch,
        };
        Ok(s)
    }
}

impl event::EventHandler for MainState {
    fn update(&mut self, ctx: &mut Context, _dt: Duration) -> GameResult<()> {

        if timer::get_ticks(ctx) % 100 == 0{

            println!("Delta frame time: {:?} ", _dt);
            println!("Average FPS: {}", timer::get_fps(ctx));
        }
        Ok(())
    }

    fn draw(&mut self, ctx: &mut Context) -> GameResult<()> {
        graphics::clear(ctx);

        let time = (timer::duration_to_f64(timer::get_time_since_start(ctx)) * 1000.0) as u32;
        let cycle = 10000;
        for x in 0..150 {
            for y in 0..150 {
                let p = graphics::DrawParam {
                    dest: graphics::Point::new(x as f32 * 10.0, y as f32 * 10.0),
                    // scale: graphics::Point::new(0.0625, 0.0625),
                    scale: graphics::Point::new(
                        ((time % cycle * 2) as f32 / cycle as f32 * 6.28).cos().abs() * 0.0625,
                        ((time % cycle * 2) as f32 / cycle as f32 * 6.28).cos().abs() * 0.0625
                    ),
                    rotation: -2.0 * ((time % cycle) as f32 / cycle as f32 * 6.28),
                    .. Default::default()
                };
                self.spritebatch.add(p);
            }
        }
        let param = graphics::DrawParam {
            dest: graphics::Point::new(
                ((time % cycle) as f32 / cycle as f32 * 6.28).cos() * 50.0 - 350.0,
                ((time % cycle) as f32 / cycle as f32 * 6.28).sin() * 50.0 - 450.0,
            ),
            scale: graphics::Point::new(
                ((time % cycle) as f32 / cycle as f32 * 6.28).sin().abs() * 2.0 + 1.0,
                ((time % cycle) as f32 / cycle as f32 * 6.28).sin().abs() * 2.0 + 1.0,
            ),
            rotation: ((time % cycle) as f32 / cycle as f32 * 6.28),
            offset: graphics::Point::new(750.0, 750.0),
            .. Default::default()
        };
        graphics::draw_ex(ctx, &self.spritebatch, param)?;
        self.spritebatch.clear();

        graphics::present(ctx);
        Ok(())
    }
}

// Creating a gamestate depends on having an SDL context to load resources.
// Creating a context depends on loading a config file.
// Loading a config file depends on having FS (or we can just fake our way around it
// by creating an FS and then throwing it away; the costs are not huge.)
pub fn main() {
    let c = conf::Conf::new();
    println!("Starting with default config: {:#?}", c);
    let ctx = &mut Context::load_from_conf("imageview", "ggez", c).unwrap();
    let state = &mut MainState::new(ctx).unwrap();
    if let Err(e) = event::run(ctx, state) {
        println!("Error encountered: {}", e);
    } else {
        println!("Game exited cleanly.");
    }
}
<|endoftext|>