<commit_before>#![allow(unknown_lints)]
#![allow(float_cmp)]

use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
    Char(char),

    F32(f32), F64(f64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl | Shr => bug!("`bin_op` operation should already have been handled", bin_op.to_hir_binop().as_str()),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    macro_rules! float_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => $v($l + $r),
                Sub    => $v($l - $r),
                Mul    => $v($l * $r),
                Div    => $v($l / $r),
                Rem    => $v($l % $r),

                // invalid float ops
                BitXor | BitAnd | BitOr |
                Shl | Shr => bug!("`{}` is not a valid operation on floats", bin_op.to_hir_binop().as_str()),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in that range
            let type_bits: u32 = match left {
                I8(_) | U8(_) => 8,
                I16(_) | U16(_) => 16,
                I32(_) | U32(_) => 32,
                I64(_) | U64(_) => 64,
                _ => bug!("bad MIR: bitshift lhs is not integral"),
            };
            assert!(type_bits.is_power_of_two());
            // turn into `u32` because `overflowing_sh{l,r}` only take `u32`
            let r = match right {
                I8(i) => i as u32,
                I16(i) => i as u32,
                I32(i) => i as u32,
                I64(i) => i as u32,
                U8(i) => i as u32,
                U16(i) => i as u32,
                U32(i) => i as u32,
                U64(i) => i as u32,
                _ => bug!("bad MIR: bitshift rhs is not integral"),
            };
            // apply mask
            let r = r & (type_bits - 1);
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({
                    match bin_op {
                        Shl => overflow!($v, U32, $l, overflowing_shl, $r),
                        Shr => overflow!($v, U32, $l, overflowing_shr, $r),
                        _ => bug!("it has already been checked that this is a shift op"),
                    }
                })
            }
            let val = match left {
                I8(l) => shift!(I8, l, r),
                I16(l) => shift!(I16, l, r),
                I32(l) => shift!(I32, l, r),
                I64(l) => shift!(I64, l, r),
                U8(l) => shift!(U8, l, r),
                U16(l) => shift!(U16, l, r),
                U32(l) => shift!(U32, l, r),
                U64(l) => shift!(U64, l, r),
                _ => bug!("bad MIR: bitshift lhs is not integral (should already have been checked)"),
            };
            return Ok((val, false));
        },
        _ => {},
    }

    let val = match (left, right) {
        (I8(l),  I8(r))  => int_binops!(I8, l, r),
        (I16(l), I16(r)) => int_binops!(I16, l, r),
        (I32(l), I32(r)) => int_binops!(I32, l, r),
        (I64(l), I64(r)) => int_binops!(I64, l, r),
        (U8(l),  U8(r))  => int_binops!(U8, l, r),
        (U16(l), U16(r)) => int_binops!(U16, l, r),
        (U32(l), U32(r)) => int_binops!(U32, l, r),
        (U64(l), U64(r)) => int_binops!(U64, l, r),
        (F32(l), F32(r)) => float_binops!(F32, l, r),
        (F64(l), F64(r)) => float_binops!(F64, l, r),
        (Char(l), Char(r)) => match bin_op {
            Eq => Bool(l == r),
            Ne => Bool(l != r),
            Lt => Bool(l < r),
            Le => Bool(l <= r),
            Gt => Bool(l > r),
            Ge => Bool(l >= r),
            _ => bug!("invalid char op: {:?}", bin_op),
        },

        (Bool(l), Bool(r)) => {
            Bool(match bin_op {
                Eq => l == r,
                Ne => l != r,
                Lt => l < r,
                Le => l <= r,
                Gt => l > r,
                Ge => l >= r,
                BitOr => l | r,
                BitXor => l ^ r,
                BitAnd => l & r,
                Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)),
            })
        }

        (IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),

        (AbstractPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), AbstractPtr(_)) |
        (FnPtr(_), AbstractPtr(_)) |
        (AbstractPtr(_), FnPtr(_)) |
        (FnPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), FnPtr(_)) =>
            unrelated_ptr_ops(bin_op)?,

        (FnPtr(l_ptr), FnPtr(r_ptr)) => match bin_op {
            Eq => Bool(l_ptr == r_ptr),
            Ne => Bool(l_ptr != r_ptr),
            _ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
        },

        (AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
            if l_ptr.alloc_id != r_ptr.alloc_id {
                return Ok((unrelated_ptr_ops(bin_op)?, false));
            }

            let l = l_ptr.offset;
            let r = r_ptr.offset;

            match bin_op {
                Eq => Bool(l == r),
                Ne => Bool(l != r),
                Lt => Bool(l < r),
                Le => Bool(l <= r),
                Gt => Bool(l > r),
                Ge => Bool(l >= r),
                _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))),
            }
        }

        (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))),
    };

    Ok((val, false))
}

pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
    use rustc::mir::repr::UnOp::*;
    use self::PrimVal::*;
    match (un_op, val) {
        (Not, Bool(b)) => Ok(Bool(!b)),
        (Not, I8(n))  => Ok(I8(!n)),
        (Neg, I8(n))  => Ok(I8(-n)),
        (Not, I16(n)) => Ok(I16(!n)),
        (Neg, I16(n)) => Ok(I16(-n)),
        (Not, I32(n)) => Ok(I32(!n)),
        (Neg, I32(n)) => Ok(I32(-n)),
        (Not, I64(n)) => Ok(I64(!n)),
        (Neg, I64(n)) => Ok(I64(-n)),
        (Not, U8(n))  => Ok(U8(!n)),
        (Not, U16(n)) => Ok(U16(!n)),
        (Not, U32(n)) => Ok(U32(!n)),
        (Not, U64(n)) => Ok(U64(!n)),

        (Neg, F64(n)) => Ok(F64(-n)),
        (Neg, F32(n)) => Ok(F32(-n)),
        _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))),
    }
}
<commit_msg>forgot to insert a {} into the format string<commit_after>#![allow(unknown_lints)]
#![allow(float_cmp)]

use rustc::mir::repr as mir;

use error::{EvalError, EvalResult};
use memory::Pointer;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum PrimVal {
    Bool(bool),
    I8(i8), I16(i16), I32(i32), I64(i64),
    U8(u8), U16(u16), U32(u32), U64(u64),

    AbstractPtr(Pointer),
    FnPtr(Pointer),
    IntegerPtr(u64),
    Char(char),

    F32(f32), F64(f64),
}

/// returns the result of the operation and whether the operation overflowed
pub fn binary_op<'tcx>(bin_op: mir::BinOp, left: PrimVal, right: PrimVal) -> EvalResult<'tcx, (PrimVal, bool)> {
    use rustc::mir::repr::BinOp::*;
    use self::PrimVal::*;

    macro_rules! overflow {
        ($v:ident, $v2:ident, $l:ident, $op:ident, $r:ident) => ({
            let (val, of) = $l.$op($r);
            if of {
                return Ok(($v(val), true));
            } else {
                $v(val)
            }
        })
    }

    macro_rules! int_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => overflow!($v, $v, $l, overflowing_add, $r),
                Sub    => overflow!($v, $v, $l, overflowing_sub, $r),
                Mul    => overflow!($v, $v, $l, overflowing_mul, $r),
                Div    => overflow!($v, $v, $l, overflowing_div, $r),
                Rem    => overflow!($v, $v, $l, overflowing_rem, $r),
                BitXor => $v($l ^ $r),
                BitAnd => $v($l & $r),
                BitOr  => $v($l | $r),

                // these have already been handled
                Shl | Shr => bug!("`{}` operation should already have been handled", bin_op.to_hir_binop().as_str()),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    macro_rules! float_binops {
        ($v:ident, $l:ident, $r:ident) => ({
            match bin_op {
                Add    => $v($l + $r),
                Sub    => $v($l - $r),
                Mul    => $v($l * $r),
                Div    => $v($l / $r),
                Rem    => $v($l % $r),

                // invalid float ops
                BitXor | BitAnd | BitOr |
                Shl | Shr => bug!("`{}` is not a valid operation on floats", bin_op.to_hir_binop().as_str()),

                Eq => Bool($l == $r),
                Ne => Bool($l != $r),
                Lt => Bool($l < $r),
                Le => Bool($l <= $r),
                Gt => Bool($l > $r),
                Ge => Bool($l >= $r),
            }
        })
    }

    fn unrelated_ptr_ops<'tcx>(bin_op: mir::BinOp) -> EvalResult<'tcx, PrimVal> {
        use rustc::mir::repr::BinOp::*;
        match bin_op {
            Eq => Ok(Bool(false)),
            Ne => Ok(Bool(true)),
            Lt | Le | Gt | Ge => Err(EvalError::InvalidPointerMath),
            _ => unimplemented!(),
        }
    }

    match bin_op {
        // can have rhs with a different numeric type
        Shl | Shr => {
            // these numbers are the maximum number a bitshift rhs could possibly have
            // e.g. u16 can be bitshifted by 0..16, so masking with 0b1111 (16 - 1) will ensure we are in that range
            let type_bits: u32 = match left {
                I8(_) | U8(_) => 8,
                I16(_) | U16(_) => 16,
                I32(_) | U32(_) => 32,
                I64(_) | U64(_) => 64,
                _ => bug!("bad MIR: bitshift lhs is not integral"),
            };
            assert!(type_bits.is_power_of_two());
            // turn into `u32` because `overflowing_sh{l,r}` only take `u32`
            let r = match right {
                I8(i) => i as u32,
                I16(i) => i as u32,
                I32(i) => i as u32,
                I64(i) => i as u32,
                U8(i) => i as u32,
                U16(i) => i as u32,
                U32(i) => i as u32,
                U64(i) => i as u32,
                _ => bug!("bad MIR: bitshift rhs is not integral"),
            };
            // apply mask
            let r = r & (type_bits - 1);
            macro_rules! shift {
                ($v:ident, $l:ident, $r:ident) => ({
                    match bin_op {
                        Shl => overflow!($v, U32, $l, overflowing_shl, $r),
                        Shr => overflow!($v, U32, $l, overflowing_shr, $r),
                        _ => bug!("it has already been checked that this is a shift op"),
                    }
                })
            }
            let val = match left {
                I8(l) => shift!(I8, l, r),
                I16(l) => shift!(I16, l, r),
                I32(l) => shift!(I32, l, r),
                I64(l) => shift!(I64, l, r),
                U8(l) => shift!(U8, l, r),
                U16(l) => shift!(U16, l, r),
                U32(l) => shift!(U32, l, r),
                U64(l) => shift!(U64, l, r),
                _ => bug!("bad MIR: bitshift lhs is not integral (should already have been checked)"),
            };
            return Ok((val, false));
        },
        _ => {},
    }

    let val = match (left, right) {
        (I8(l),  I8(r))  => int_binops!(I8, l, r),
        (I16(l), I16(r)) => int_binops!(I16, l, r),
        (I32(l), I32(r)) => int_binops!(I32, l, r),
        (I64(l), I64(r)) => int_binops!(I64, l, r),
        (U8(l),  U8(r))  => int_binops!(U8, l, r),
        (U16(l), U16(r)) => int_binops!(U16, l, r),
        (U32(l), U32(r)) => int_binops!(U32, l, r),
        (U64(l), U64(r)) => int_binops!(U64, l, r),
        (F32(l), F32(r)) => float_binops!(F32, l, r),
        (F64(l), F64(r)) => float_binops!(F64, l, r),
        (Char(l), Char(r)) => match bin_op {
            Eq => Bool(l == r),
            Ne => Bool(l != r),
            Lt => Bool(l < r),
            Le => Bool(l <= r),
            Gt => Bool(l > r),
            Ge => Bool(l >= r),
            _ => bug!("invalid char op: {:?}", bin_op),
        },

        (Bool(l), Bool(r)) => {
            Bool(match bin_op {
                Eq => l == r,
                Ne => l != r,
                Lt => l < r,
                Le => l <= r,
                Gt => l > r,
                Ge => l >= r,
                BitOr => l | r,
                BitXor => l ^ r,
                BitAnd => l & r,
                Add | Sub | Mul | Div | Rem | Shl | Shr => return Err(EvalError::InvalidBoolOp(bin_op)),
            })
        }

        (IntegerPtr(l), IntegerPtr(r)) => int_binops!(IntegerPtr, l, r),

        (AbstractPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), AbstractPtr(_)) |
        (FnPtr(_), AbstractPtr(_)) |
        (AbstractPtr(_), FnPtr(_)) |
        (FnPtr(_), IntegerPtr(_)) |
        (IntegerPtr(_), FnPtr(_)) =>
            unrelated_ptr_ops(bin_op)?,

        (FnPtr(l_ptr), FnPtr(r_ptr)) => match bin_op {
            Eq => Bool(l_ptr == r_ptr),
            Ne => Bool(l_ptr != r_ptr),
            _ => return Err(EvalError::Unimplemented(format!("unimplemented fn ptr comparison: {:?}", bin_op))),
        },

        (AbstractPtr(l_ptr), AbstractPtr(r_ptr)) => {
            if l_ptr.alloc_id != r_ptr.alloc_id {
                return Ok((unrelated_ptr_ops(bin_op)?, false));
            }

            let l = l_ptr.offset;
            let r = r_ptr.offset;

            match bin_op {
                Eq => Bool(l == r),
                Ne => Bool(l != r),
                Lt => Bool(l < r),
                Le => Bool(l <= r),
                Gt => Bool(l > r),
                Ge => Bool(l >= r),
                _ => return Err(EvalError::Unimplemented(format!("unimplemented ptr op: {:?}", bin_op))),
            }
        }

        (l, r) => return Err(EvalError::Unimplemented(format!("unimplemented binary op: {:?}, {:?}, {:?}", l, r, bin_op))),
    };

    Ok((val, false))
}

pub fn unary_op<'tcx>(un_op: mir::UnOp, val: PrimVal) -> EvalResult<'tcx, PrimVal> {
    use rustc::mir::repr::UnOp::*;
    use self::PrimVal::*;
    match (un_op, val) {
        (Not, Bool(b)) => Ok(Bool(!b)),
        (Not, I8(n))  => Ok(I8(!n)),
        (Neg, I8(n))  => Ok(I8(-n)),
        (Not, I16(n)) => Ok(I16(!n)),
        (Neg, I16(n)) => Ok(I16(-n)),
        (Not, I32(n)) => Ok(I32(!n)),
        (Neg, I32(n)) => Ok(I32(-n)),
        (Not, I64(n)) => Ok(I64(!n)),
        (Neg, I64(n)) => Ok(I64(-n)),
        (Not, U8(n))  => Ok(U8(!n)),
        (Not, U16(n)) => Ok(U16(!n)),
        (Not, U32(n)) => Ok(U32(!n)),
        (Not, U64(n)) => Ok(U64(!n)),

        (Neg, F64(n)) => Ok(F64(-n)),
        (Neg, F32(n)) => Ok(F32(-n)),
        _ => Err(EvalError::Unimplemented(format!("unimplemented unary op: {:?}, {:?}", un_op, val))),
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::{BufRead, BufReader};

struct Problem {
	id: u32,
	statement: Vec<String>,
	name: Vec<String>,
	authors: Vec<String>,
	input: Vec<String>
}

enum State {
	Default,
	Name,
	Statement,
	Authors,
	Input
}

impl Problem {
	fn new(id: u32) -> Problem {
		let reader = match File::open(format!("problems/{}.rs", id)) {
				Ok(file) => file,
				Err(err) => panic!("Unable to load problem '#{}`: {}", id, err),
			};
		let buf = BufReader::new(&reader);
		let mut statement = vec![];
		let mut name = vec![];
		let mut authors = vec![];
		let mut input = vec![];
	    let mut state = State::Default;
	    let mut info = false;
	    for line in buf.lines()  {
	    	let l = line.unwrap();
	    	if !info {
	    		if l == "/* [info]" {
		    		info = true;
	    		}
		    	continue;
	    	}
	        match l.as_ref() {
	        	"[authors]" => state = State::Authors,
	        	"[name]" => state = State::Name,
	        	"[statement]" => state = State::Statement,
	        	"[input]" => state = State::Input,
	        	"[end] */" => break,
	        	_ => {
	        		match state {
	        			State::Authors => authors.push(l.trim().to_string()),
	        			State::Name => name.push(l.trim().to_string()),
	        			State::Statement => statement.push(l.trim().to_string()),
	        			State::Input => input.push(l.trim().to_string()),
	        			_ => continue
	        		}
	        	}
	        }
	    }
		Problem {
			id: id,
			statement: statement,
			name: name,
			authors: authors,
			input: input,
		}
	}
}

#[test]
fn read_test() {
	let p = Problem::new(0);
	assert_eq!(p.id, 0);
	assert_eq!(p.authors, vec!["Testhor", "qwerty"]);
	assert_eq!(p.name, vec!["Test name", "check"]);
	assert_eq!(p.statement, vec!["Test statement", "3", "4"]);
	assert_eq!(p.input, vec!["1sd", "check", "123"]);
}<commit_msg>fix tabs<commit_after>use std::fs::File;
use std::io::{BufRead, BufReader};

struct Problem {
	id: u32,
	statement: Vec<String>,
	name: Vec<String>,
	authors: Vec<String>,
	input: Vec<String>
}

enum State {
	Default,
	Name,
	Statement,
	Authors,
	Input
}

impl Problem {
	fn new(id: u32) -> Problem {
		let reader = match File::open(format!("problems/{}.rs", id)) {
				Ok(file) => file,
				Err(err) => panic!("Unable to load problem '#{}`: {}", id, err),
			};
		let buf = BufReader::new(&reader);
		let mut statement = vec![];
		let mut name = vec![];
		let mut authors = vec![];
		let mut input = vec![];
		let mut state = State::Default;
		let mut info = false;
		for line in buf.lines()  {
			let l = line.unwrap();
			if !info {
				if l == "/* [info]" {
					info = true;
				}
				continue;
			}
			match l.as_ref() {
				"[authors]" => state = State::Authors,
				"[name]" => state = State::Name,
				"[statement]" => state = State::Statement,
			 	"[input]" => state = State::Input,
				"[end] */" => break,
				_ => {
					match state {
						State::Authors => authors.push(l.trim().to_string()),
						State::Name => name.push(l.trim().to_string()),
						State::Statement => statement.push(l.trim().to_string()),
						State::Input => input.push(l.trim().to_string()),
						_ => continue
					}
				}
			}
		}
		Problem {
			id: id,
			statement: statement,
			name: name,
			authors: authors,
			input: input,
		}
	}
}

#[test]
fn read_test() {
	let p = Problem::new(0);
	assert_eq!(p.id, 0);
	assert_eq!(p.authors, vec!["Testhor", "qwerty"]);
	assert_eq!(p.name, vec!["Test name", "check"]);
	assert_eq!(p.statement, vec!["Test statement", "3", "4"]);
	assert_eq!(p.input, vec!["1sd", "check", "123"]);
}<|endoftext|>


<commit_before>use super::super::{Grid, Y, X, Coord};
use grid_loop::{Edge, GridLoopField};
use super::*;

use rand::Rng;

#[derive(Debug, Clone, Copy)]
pub struct Symmetry {
    pub dyad: bool,         // 180-degree symmetry
    pub tetrad: bool,       // 90-degree symmetry
    pub horizontal: bool,   // horizontal line symmetry
    pub vertical: bool,     // vertical line symmetry
}

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_score = 0;
    let temperature = 5.0f64;

    let mut unplaced_clues = 0;
    for y in 0..height {
        for x in 0..width {
            if has_clue[(Y(y), X(x))] {
                unplaced_clues += 1;
            }
        }
    }

    let mut last_field = Field::new(&current_problem, dic);

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                let cd = (Y(y), X(x));
                if has_clue[cd] && (current_problem[cd] == NO_CLUE || has_undecided_nearby(&last_field, cd)) {
                    pos_cand.push(cd);
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            let mut common;
            if prev_clue == NO_CLUE {
                common = last_field.clone();
            } else {
                current_problem[pos] = NO_CLUE;
                common = Field::new(&current_problem, dic);
                common.check_all_cell();
            }

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = common.clone();
                field.add_clue(pos, c);

                let isok;
                let current_score;
                if field.inconsistent() {
                    isok = false;
                    current_score = -1;
                } else {
                    current_score = field.grid_loop().num_decided_edges() - count_prohibited_patterns(has_clue, &field, &current_problem) * 10;

                    if prev_score < current_score {
                        isok = true;
                    } else {
                        isok = rng.next_f64() < ((current_score - prev_score) as f64 / temperature).exp()
                    }
                }

                if isok {
                    updated = true;
                    prev_score = current_score;
                    if prev_clue == NO_CLUE {
                        unplaced_clues -= 1;
                    }

                    if field.fully_solved() && unplaced_clues == 0 {
                        return Some(current_problem);
                    }

                    last_field = field;
                    break;
                }
            }

            if updated {
                break;
            } else {
                current_problem[pos] = prev_clue;
            }
        }
    }

    None
}

fn has_undecided_nearby(field: &Field, clue_pos: Coord) -> bool {
    let (Y(y), X(x)) = clue_pos;
    let y = y * 2 + 1;
    let x = x * 2 + 1;

    let neighbor_size: i32 = 7;
    for dy in -neighbor_size..(neighbor_size + 1) {
        let dx_max = neighbor_size - dy.abs();
        for dx in -dx_max..(dx_max + 1) {
            let y2 = y + dy;
            let x2 = x + dx;

            let cd = (Y(y2), X(x2));
            if (dy & 1) != (dx & 1) {
                if field.get_edge_safe(cd) == Edge::Undecided {
                    return true;
                }
            }
        }
    }
    false
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}
fn count_prohibited_patterns(has_clue: &Grid<bool>, field: &Field, problem: &Grid<Clue>) -> i32 {
    let neighbor = [
        (Y(1), X(0)),
        (Y(0), X(1)),
        (Y(-1), X(0)),
        (Y(0), X(-1)),
    ];
    let mut ret = 0;
    for y in 0..has_clue.height() {
        for x in 0..has_clue.width() {
            if has_clue[(Y(y), X(x))] && field.get_clue((Y(y), X(x))) == NO_CLUE && has_zero_nearby(problem, (Y(y), X(x))) {
                if
                    field.get_edge((Y(2 * y + 0), X(2 * x + 1))) == Edge::Blank &&
                    field.get_edge((Y(2 * y + 1), X(2 * x + 0))) == Edge::Blank &&
                    field.get_edge((Y(2 * y + 2), X(2 * x + 1))) == Edge::Blank &&
                    field.get_edge((Y(2 * y + 1), X(2 * x + 2))) == Edge::Blank {
                    ret += 1;
                    continue;
                }
            }
            if y > 0 && field.get_clue((Y(y - 1), X(x))) != NO_CLUE { continue; }
            if x > 0 && field.get_clue((Y(y), X(x - 1))) != NO_CLUE { continue; }
            if y < has_clue.height() - 1 && field.get_clue((Y(y + 1), X(x))) != NO_CLUE { continue; }
            if x < has_clue.width() - 1 && field.get_clue((Y(y), X(x + 1))) != NO_CLUE { continue; }

            if field.get_clue((Y(y), X(x))) == Clue(2) {
                if
                    field.get_edge_safe((Y(2 * y + 1 + 2), X(2 * x + 1 + 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 + 1), X(2 * x + 1 + 2))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 - 2), X(2 * x + 1 - 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 - 1), X(2 * x + 1 - 2))) == Edge::Blank {
                    ret += 1;
                    continue;
                }
                if
                    field.get_edge_safe((Y(2 * y + 1 - 2), X(2 * x + 1 + 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 - 1), X(2 * x + 1 + 2))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 + 2), X(2 * x + 1 - 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 + 1), X(2 * x + 1 - 2))) == Edge::Blank {
                    ret += 1;
                    continue;
                }
            } else if field.get_clue((Y(y), X(x))) == NO_CLUE {
                let mut n_in = 0;
                let mut n_blank = 0;

                for d in 0..4 {
                    let (Y(dy1), X(dx1)) = neighbor[d];
                    let (Y(dy2), X(dx2)) = neighbor[(d + 1) % 4];
                    let edge1 = field.get_edge_safe((Y(2 * y + 1 + dy1 * 2 + dy2), X(2 * x + 1 + dx1 * 2 + dx2)));
                    let edge2 = field.get_edge_safe((Y(2 * y + 1 + dy2 * 2 + dy1), X(2 * x + 1 + dx2 * 2 + dx1)));

                    match (edge1, edge2) {
                        (Edge::Blank, Edge::Blank) => n_blank += 1,
                        (Edge::Blank, Edge::Line) | (Edge::Line, Edge::Blank) => n_in += 1,
                        _ => (),
                    }
                }

                if n_in >= 1 && n_blank >= 2 {
                    ret += 1;
                }
            }
        }
    }
    ret
}

pub fn generate_placement<R: Rng>(height: i32, width: i32, num_clues: i32, symmetry: Symmetry, rng: &mut R) -> Grid<bool> {
    let mut num_clues = num_clues;
    let mut symmetry = symmetry;

    symmetry.dyad |= symmetry.tetrad;
    symmetry.tetrad &= (height == width);

    let mut grp_ids = Grid::new(height, width, false);
    let mut last_id = 0;

    let mut clue_positions: Vec<Vec<Coord>> = vec![];

    for y in 0..height {
        for x in 0..width {
            if !grp_ids[(Y(y), X(x))] {
                let mut sto = vec![];
                update_grp(y, x, last_id, symmetry, &mut grp_ids, &mut sto);
                clue_positions.push(sto);
            }
        }
    }

    let mut ret = Grid::new(height, width, false);
    while clue_positions.len() > 0 && num_clues > 0 {
        let mut scores = vec![];
        let mut scores_total = 0.0f64;

        for pos in &clue_positions {
            let (Y(y), X(x)) = pos[0];
            let mut score_base = 0.0f64;

            for dy in -2..3 {
                for dx in -2..3 {
                    let cd2 = (Y(y + dy), X(x + dx));
                    if ret.is_valid_coord(cd2) && ret[cd2] {
                        let dist = dy.abs() + dx.abs();
                        score_base += 5.0f64 - (dist as f64);
                        if dist == 1 {
                            score_base += 2.0f64;
                        }
                    }
                }
            }

            let pos_score = 64.0f64 * 2.0f64.powf((16.0f64 - score_base) / 2.0f64) + 4.0f64;
            scores.push(pos_score);
            scores_total += pos_score;
        }

        let mut thresh = rng.gen_range(0.0f64, scores_total);
        for i in 0..clue_positions.len() {
            if thresh < scores[i] {
                for &c in &(clue_positions[i]) {
                    ret[c] = true;
                    num_clues -= 1;
                }
                clue_positions.swap_remove(i);
                break;
            } else {
                thresh -= scores[i];
            }
        }
    }

    ret
}

fn update_grp(y: i32, x: i32, id: i32, symmetry: Symmetry, grp_ids: &mut Grid<bool>, sto: &mut Vec<Coord>) {
    if grp_ids[(Y(y), X(x))] {
        return;
    }
    grp_ids[(Y(y), X(x))] = true;
    sto.push((Y(y), X(x)));

    if symmetry.tetrad {
        update_grp(grp_ids.height() - 1 - x, y, id, symmetry, grp_ids, sto);
    } else if symmetry.dyad {
        update_grp(grp_ids.height() - 1 - y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
    if symmetry.horizontal {
        update_grp(grp_ids.height() - 1 - y, x, id, symmetry, grp_ids, sto);
    }
    if symmetry.vertical {
        update_grp(y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand;

    fn run_placement_test<R: Rng>(placement: Vec<Vec<bool>>, dic: &Dictionary, rng: &mut R) {
        let placement = ::common::vec_to_grid(&placement);
        let mut succeeded = false;

        for _ in 0..10 {
            let problem = generate(&placement, dic, rng);

            if let Some(problem) = problem {
                succeeded = true;

                assert_eq!(problem.height(), placement.height());
                assert_eq!(problem.width(), placement.width());

                for y in 0..placement.height() {
                    for x in 0..placement.width() {
                        let clue = problem[(Y(y), X(x))];
                        assert_eq!(placement[(Y(y), X(x))], clue != NO_CLUE);

                        if clue == Clue(0) {
                            for dy in -1..2 {
                                for dx in -1..2 {
                                    let y2 = y + dy;
                                    let x2 = x + dx;

                                    if 0 <= y2 && y2 < placement.height() && 0 <= x2 && x2 < placement.width() && (dy, dx) != (0, 0) {
                                        assert!(problem[(Y(y2), X(x2))] != Clue(0));
                                    }
                                }
                            }
                        }
                    }
                }

                let mut field = Field::new(&problem, &dic);
                field.check_all_cell();
                assert!(!field.inconsistent());
                assert!(field.fully_solved());

                break;
            }
        }

        assert!(succeeded);
    }

    #[test]
    fn test_generator() {
        let mut rng = rand::thread_rng();
        let dic = Dictionary::complete();

        run_placement_test(vec![
            vec![true , true , true , true , true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , true , true , true , true ],
        ], &dic, &mut rng);

        run_placement_test(vec![
            vec![true , false, true , true , true ],
            vec![false, false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, false],
            vec![true , true , true , false, true ],
        ], &dic, &mut rng);
    }
}
<commit_msg>Slitherlink: use apply_inout_rule and check_connectability in generator<commit_after>use super::super::{Grid, Y, X, Coord};
use grid_loop::{Edge, GridLoop, GridLoopField};
use super::*;

use rand::Rng;

#[derive(Debug, Clone, Copy)]
pub struct Symmetry {
    pub dyad: bool,         // 180-degree symmetry
    pub tetrad: bool,       // 90-degree symmetry
    pub horizontal: bool,   // horizontal line symmetry
    pub vertical: bool,     // vertical line symmetry
}

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_score = 0;
    let temperature = 5.0f64;

    let mut unplaced_clues = 0;
    for y in 0..height {
        for x in 0..width {
            if has_clue[(Y(y), X(x))] {
                unplaced_clues += 1;
            }
        }
    }

    let mut last_field = Field::new(&current_problem, dic);

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                let cd = (Y(y), X(x));
                if has_clue[cd] && (current_problem[cd] == NO_CLUE || has_undecided_nearby(&last_field, cd)) {
                    pos_cand.push(cd);
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            let mut common;
            if prev_clue == NO_CLUE {
                common = last_field.clone();
            } else {
                current_problem[pos] = NO_CLUE;
                common = Field::new(&current_problem, dic);
                common.check_all_cell();
            }

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = common.clone();
                field.add_clue(pos, c);

                if field.inconsistent() {
                    continue;
                }

                let current_score = field.grid_loop().num_decided_edges() - count_prohibited_patterns(has_clue, &field, &current_problem) * 10;

                if prev_score >= current_score {
                    if !(rng.next_f64() < ((current_score - prev_score) as f64 / temperature).exp()) {
                        continue;
                    }
                }

                let mut field_inout_test = field.clone();
                GridLoop::apply_inout_rule(&mut field_inout_test);
                GridLoop::check_connectability(&mut field_inout_test);
                if field_inout_test.inconsistent() {
                    continue;
                }

                updated = true;
                prev_score = current_score;
                if prev_clue == NO_CLUE {
                    unplaced_clues -= 1;
                }

                if field.fully_solved() && unplaced_clues == 0 {
                    return Some(current_problem);
                }

                last_field = field;
                break;
            }

            if updated {
                break;
            } else {
                current_problem[pos] = prev_clue;
            }
        }
    }

    None
}

fn has_undecided_nearby(field: &Field, clue_pos: Coord) -> bool {
    let (Y(y), X(x)) = clue_pos;
    let y = y * 2 + 1;
    let x = x * 2 + 1;

    let neighbor_size: i32 = 7;
    for dy in -neighbor_size..(neighbor_size + 1) {
        let dx_max = neighbor_size - dy.abs();
        for dx in -dx_max..(dx_max + 1) {
            let y2 = y + dy;
            let x2 = x + dx;

            let cd = (Y(y2), X(x2));
            if (dy & 1) != (dx & 1) {
                if field.get_edge_safe(cd) == Edge::Undecided {
                    return true;
                }
            }
        }
    }
    false
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}
fn count_prohibited_patterns(has_clue: &Grid<bool>, field: &Field, problem: &Grid<Clue>) -> i32 {
    let neighbor = [
        (Y(1), X(0)),
        (Y(0), X(1)),
        (Y(-1), X(0)),
        (Y(0), X(-1)),
    ];
    let mut ret = 0;
    for y in 0..has_clue.height() {
        for x in 0..has_clue.width() {
            if has_clue[(Y(y), X(x))] && field.get_clue((Y(y), X(x))) == NO_CLUE && has_zero_nearby(problem, (Y(y), X(x))) {
                if
                    field.get_edge((Y(2 * y + 0), X(2 * x + 1))) == Edge::Blank &&
                    field.get_edge((Y(2 * y + 1), X(2 * x + 0))) == Edge::Blank &&
                    field.get_edge((Y(2 * y + 2), X(2 * x + 1))) == Edge::Blank &&
                    field.get_edge((Y(2 * y + 1), X(2 * x + 2))) == Edge::Blank {
                    ret += 1;
                    continue;
                }
            }
            if y > 0 && field.get_clue((Y(y - 1), X(x))) != NO_CLUE { continue; }
            if x > 0 && field.get_clue((Y(y), X(x - 1))) != NO_CLUE { continue; }
            if y < has_clue.height() - 1 && field.get_clue((Y(y + 1), X(x))) != NO_CLUE { continue; }
            if x < has_clue.width() - 1 && field.get_clue((Y(y), X(x + 1))) != NO_CLUE { continue; }

            if field.get_clue((Y(y), X(x))) == Clue(2) {
                if
                    field.get_edge_safe((Y(2 * y + 1 + 2), X(2 * x + 1 + 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 + 1), X(2 * x + 1 + 2))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 - 2), X(2 * x + 1 - 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 - 1), X(2 * x + 1 - 2))) == Edge::Blank {
                    ret += 1;
                    continue;
                }
                if
                    field.get_edge_safe((Y(2 * y + 1 - 2), X(2 * x + 1 + 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 - 1), X(2 * x + 1 + 2))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 + 2), X(2 * x + 1 - 1))) == Edge::Blank &&
                    field.get_edge_safe((Y(2 * y + 1 + 1), X(2 * x + 1 - 2))) == Edge::Blank {
                    ret += 1;
                    continue;
                }
            } else if field.get_clue((Y(y), X(x))) == NO_CLUE {
                let mut n_in = 0;
                let mut n_blank = 0;

                for d in 0..4 {
                    let (Y(dy1), X(dx1)) = neighbor[d];
                    let (Y(dy2), X(dx2)) = neighbor[(d + 1) % 4];
                    let edge1 = field.get_edge_safe((Y(2 * y + 1 + dy1 * 2 + dy2), X(2 * x + 1 + dx1 * 2 + dx2)));
                    let edge2 = field.get_edge_safe((Y(2 * y + 1 + dy2 * 2 + dy1), X(2 * x + 1 + dx2 * 2 + dx1)));

                    match (edge1, edge2) {
                        (Edge::Blank, Edge::Blank) => n_blank += 1,
                        (Edge::Blank, Edge::Line) | (Edge::Line, Edge::Blank) => n_in += 1,
                        _ => (),
                    }
                }

                if n_in >= 1 && n_blank >= 2 {
                    ret += 1;
                }
            }
        }
    }
    ret
}

pub fn generate_placement<R: Rng>(height: i32, width: i32, num_clues: i32, symmetry: Symmetry, rng: &mut R) -> Grid<bool> {
    let mut num_clues = num_clues;
    let mut symmetry = symmetry;

    symmetry.dyad |= symmetry.tetrad;
    symmetry.tetrad &= (height == width);

    let mut grp_ids = Grid::new(height, width, false);
    let mut last_id = 0;

    let mut clue_positions: Vec<Vec<Coord>> = vec![];

    for y in 0..height {
        for x in 0..width {
            if !grp_ids[(Y(y), X(x))] {
                let mut sto = vec![];
                update_grp(y, x, last_id, symmetry, &mut grp_ids, &mut sto);
                clue_positions.push(sto);
            }
        }
    }

    let mut ret = Grid::new(height, width, false);
    while clue_positions.len() > 0 && num_clues > 0 {
        let mut scores = vec![];
        let mut scores_total = 0.0f64;

        for pos in &clue_positions {
            let (Y(y), X(x)) = pos[0];
            let mut score_base = 0.0f64;

            for dy in -2..3 {
                for dx in -2..3 {
                    let cd2 = (Y(y + dy), X(x + dx));
                    if ret.is_valid_coord(cd2) && ret[cd2] {
                        let dist = dy.abs() + dx.abs();
                        score_base += 5.0f64 - (dist as f64);
                        if dist == 1 {
                            score_base += 2.0f64;
                        }
                    }
                }
            }

            let pos_score = 64.0f64 * 2.0f64.powf((16.0f64 - score_base) / 2.0f64) + 4.0f64;
            scores.push(pos_score);
            scores_total += pos_score;
        }

        let mut thresh = rng.gen_range(0.0f64, scores_total);
        for i in 0..clue_positions.len() {
            if thresh < scores[i] {
                for &c in &(clue_positions[i]) {
                    ret[c] = true;
                    num_clues -= 1;
                }
                clue_positions.swap_remove(i);
                break;
            } else {
                thresh -= scores[i];
            }
        }
    }

    ret
}

fn update_grp(y: i32, x: i32, id: i32, symmetry: Symmetry, grp_ids: &mut Grid<bool>, sto: &mut Vec<Coord>) {
    if grp_ids[(Y(y), X(x))] {
        return;
    }
    grp_ids[(Y(y), X(x))] = true;
    sto.push((Y(y), X(x)));

    if symmetry.tetrad {
        update_grp(grp_ids.height() - 1 - x, y, id, symmetry, grp_ids, sto);
    } else if symmetry.dyad {
        update_grp(grp_ids.height() - 1 - y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
    if symmetry.horizontal {
        update_grp(grp_ids.height() - 1 - y, x, id, symmetry, grp_ids, sto);
    }
    if symmetry.vertical {
        update_grp(y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use rand;

    fn run_placement_test<R: Rng>(placement: Vec<Vec<bool>>, dic: &Dictionary, rng: &mut R) {
        let placement = ::common::vec_to_grid(&placement);
        let mut succeeded = false;

        for _ in 0..10 {
            let problem = generate(&placement, dic, rng);

            if let Some(problem) = problem {
                succeeded = true;

                assert_eq!(problem.height(), placement.height());
                assert_eq!(problem.width(), placement.width());

                for y in 0..placement.height() {
                    for x in 0..placement.width() {
                        let clue = problem[(Y(y), X(x))];
                        assert_eq!(placement[(Y(y), X(x))], clue != NO_CLUE);

                        if clue == Clue(0) {
                            for dy in -1..2 {
                                for dx in -1..2 {
                                    let y2 = y + dy;
                                    let x2 = x + dx;

                                    if 0 <= y2 && y2 < placement.height() && 0 <= x2 && x2 < placement.width() && (dy, dx) != (0, 0) {
                                        assert!(problem[(Y(y2), X(x2))] != Clue(0));
                                    }
                                }
                            }
                        }
                    }
                }

                let mut field = Field::new(&problem, &dic);
                field.check_all_cell();
                assert!(!field.inconsistent());
                assert!(field.fully_solved());

                break;
            }
        }

        assert!(succeeded);
    }

    #[test]
    fn test_generator() {
        let mut rng = rand::thread_rng();
        let dic = Dictionary::complete();

        run_placement_test(vec![
            vec![true , true , true , true , true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , true , true , true , true ],
        ], &dic, &mut rng);

        run_placement_test(vec![
            vec![true , false, true , true , true ],
            vec![false, false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, false],
            vec![true , true , true , false, true ],
        ], &dic, &mut rng);
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where F: FnMut(&T) -> bool {
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) { return Some(start + offset); }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {

            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => {},

                        Command::JumpForward => {
                            let patch = Program::attempt_forward_jump(&self.instructions, index, self.current_depth);
                            return self.update(patch).execute(vm);
                        },

                        command => vm.apply(command),
                    }
                }
            }

            _ => {}
        }
    }

    fn update (&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {},
            }
            if goal_depth == current_depth {
                return ProgramPatch { instruction_pointer: index, status: ProgramStatus::Normal, current_depth };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(commands: &Vec<Command>, index: usize, goal_depth: u64, mut current_depth: u64) -> ProgramPatch {
        let index = find_by(commands, Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {},
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index,
                status: ProgramStatus::Normal,
                current_depth
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            }
        };
    }
}
<commit_msg>Implement execute logic<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

#[derive(Clone, Copy, Debug)]
pub struct ProgramPatch {
    pub instruction_pointer: usize,
    pub current_depth: u64,
    pub status: ProgramStatus,
}

fn find_by<T, F>(list: &[T], start: Option<usize>, mut predicate: F) -> Option<usize>
where F: FnMut(&T) -> bool {
    let start = start.unwrap_or(0);
    for (offset, element) in list.iter().enumerate() {
        if predicate(element) { return Some(start + offset); }
    }

    return None;
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(index), ProgramStatus::Seeking(goal)) if index < self.instructions.len() => {
                let patch = Program::attempt_forward_jump(&self.instructions, index, goal, self.current_depth);
                println!("SEEKING BRANCH\n{:?}\n", patch);
                return self.update(patch).execute(vm)
            }

            (Some(start), ProgramStatus::Normal) if start < self.instructions.len() => {
                for index in start..self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpBackward => {
                            if vm.cells[vm.data_pointer] == 0 {
                                self.current_depth -= 1;
                                continue;
                            }

                            let patch = Program::backward_jump(&self.instructions, index, self.current_depth);
                            println!("BACKWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        },

                        Command::JumpForward => {
                            if vm.cells[vm.data_pointer] != 0 {
                                self.current_depth += 1;
                                continue;
                            }

                            let patch = Program::attempt_forward_jump(&self.instructions, index, self.current_depth, self.current_depth);
                            println!("FORWARD BRANCH\n{:?}\n", patch);
                            return self.update(patch).execute(vm);
                        },

                        command if start < self.instructions.len() => vm.apply(command),

                        _ => {},
                    }
                }
            }

            _ => {}
        }
    }

    fn update (&mut self, patch: ProgramPatch) -> &mut Self {
        self.instruction_pointer = Some(patch.instruction_pointer);
        self.current_depth = patch.current_depth;
        self.status = patch.status;
        return self;
    }

    fn backward_jump(commands: &Vec<Command>, start: usize, depth: u64) -> ProgramPatch {
        let goal_depth = depth - 1;
        let mut current_depth = depth;
        for index in (0..start).rev() {
            match commands[index] {
                Command::JumpBackward => current_depth += 1,
                Command::JumpForward => current_depth -= 1,
                _ => {},
            }
            if goal_depth == current_depth {
                return ProgramPatch { instruction_pointer: index, status: ProgramStatus::Normal, current_depth };
            }
        }
        panic!("No opening bracket found?");
    }

    fn attempt_forward_jump(commands: &Vec<Command>, index: usize, goal_depth: u64, mut current_depth: u64) -> ProgramPatch {
        let index = find_by(commands, Some(index), |command| {
            match command {
                &Command::JumpBackward => current_depth -= 1,
                &Command::JumpForward => current_depth += 1,
                _ => {},
            };
            return current_depth == goal_depth;
        });

        return match index {
            Some(index) => ProgramPatch {
                instruction_pointer: index,
                status: ProgramStatus::Normal,
                current_depth
            },

            None => ProgramPatch {
                instruction_pointer: commands.len(),
                status: ProgramStatus::Seeking(goal_depth),
                current_depth,
            }
        };
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.handle_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        self.current_depth = self.current_depth - 1
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn seek_forward(&mut self, mut index: usize) -> usize {
        let goal_depth = self.goal_depth.unwrap();
        while self.current_depth != goal_depth && index < self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            index = index + 1;
        }
        index
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            return self.seek_forward(index)
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<commit_msg>Make seek_forward report found status in addition to index<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() { self.instruction_pointer = Some(0); }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match self.instruction_pointer {
            None => {},
            Some(mut index) => {
                while index < self.instructions.len() {
                    let command = self.instructions[index];
                    if command == Command::JumpForward {
                        index = self.handle_jump_forward(vm, index);
                    } else if command == Command::JumpBackward {
                        self.current_depth = self.current_depth - 1
                    } else {
                        vm.apply(command);
                        index = index + 1;
                    }
                }
                self.instruction_pointer = Some(index);
            }
        }
    }

    fn seek_forward(&mut self, starting_index: usize) -> (usize, bool) {
        let goal_depth = self.goal_depth.unwrap();
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth = self.current_depth + 1,
                Command::JumpBackward => self.current_depth = self.current_depth - 1,
                _ => {},
            }
            if self.current_depth == goal_depth { return (index + 1, false) }
        }
        (self.instructions.len(), true)
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: usize) -> usize {
        if vm.cells[vm.data_pointer] == 0 {
            self.goal_depth = Some(self.current_depth);
            let (index, still_seeking) = self.seek_forward(index);
            self.is_seeking = still_seeking;
            return index;
        } else {
            self.current_depth = self.current_depth + 1;
            return index;
        }
    }
}
<|endoftext|>


<commit_before>use command::Command;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
    }
}
<commit_msg>Add program.execute(&mut VM) stub<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions : Vec<Command>,
    instruction_pointer: Option<usize>,
    is_seeking: bool,
    current_depth: u64,
    goal_depth: Option<u64>,
}

impl Program {
    pub fn new () -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            is_seeking: false,
            current_depth: 0,
            goal_depth: None,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
    }

    pub fn execute(&mut self, vm: &mut VM) {
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::iter::{repeat};
use std::num::{Float, SignedInt};
use cgmath::{Vector};
use common::types::{Size2, ZInt, MapPos};
use dir::{Dir, DirIter, dirs};

#[derive(Clone)]
pub enum Terrain {
    Plain,
    Trees,
}

pub struct Map<T> {
    tiles: Vec<T>,
    size: Size2<ZInt>,
}

impl<T: Clone> Map<T> {
    // TODO: remove 'empty'
    pub fn new(size: &Size2<ZInt>, empty: T) -> Map<T> {
        let tiles_count = size.w * size.h;
        let tiles = repeat(empty).take(tiles_count as usize).collect();
        Map {
            tiles: tiles,
            size: size.clone(),
        }
    }

    pub fn size(&self) -> &Size2<ZInt> {
        &self.size
    }

    pub fn tile_mut(&mut self, pos: &MapPos) -> &mut T {
        assert!(self.is_inboard(pos));
        let index = self.size.w * pos.v.y + pos.v.x;
        &mut self.tiles[index as usize]
    }

    pub fn tile(&self, pos: &MapPos) -> &T {
        assert!(self.is_inboard(pos));
        let index = self.size.w * pos.v.y + pos.v.x;
        &self.tiles[index as usize]
    }

    pub fn is_inboard(&self, pos: &MapPos) -> bool {
        let x = pos.v.x;
        let y = pos.v.y;
        x >= 0 && y >= 0 && x < self.size.w && y < self.size.h
    }

    pub fn get_iter(&self) -> MapPosIter {
        MapPosIter::new(self.size())
    }
}

pub struct MapPosIter {
    cursor: MapPos,
    map_size: Size2<ZInt>,
}

impl MapPosIter {
    fn new(map_size: &Size2<ZInt>) -> MapPosIter {
        MapPosIter {
            cursor: MapPos{v: Vector::from_value(0)},
            map_size: map_size.clone(),
        }
    }
}

impl Iterator for MapPosIter {
    type Item = MapPos;

    fn next(&mut self) -> Option<MapPos> {
        let current_pos = if self.cursor.v.y >= self.map_size.h {
            None
        } else {
            Some(self.cursor.clone())
        };
        self.cursor.v.x += 1;
        if self.cursor.v.x >= self.map_size.w {
            self.cursor.v.x = 0;
            self.cursor.v.y += 1;
        }
        current_pos
    }
}

pub struct RingIter {
    cursor: MapPos,
    segment_index: ZInt,
    dir_iter: DirIter,
    radius: ZInt,
    dir: Dir,
}

pub fn ring_iter(pos: &MapPos, radius: ZInt) -> RingIter {
    let mut pos = pos.clone();
    pos.v.x -= radius;
    let mut dir_iter = dirs();
    let dir = dir_iter.next()
        .expect("Can`t get first direction");
    assert_eq!(dir, Dir::SouthEast);
    RingIter {
        cursor: pos.clone(),
        radius: radius,
        segment_index: 0,
        dir_iter: dir_iter,
        dir: dir,
    }
}

impl RingIter {
    fn simple_step(&mut self) -> Option<MapPos> {
        self.cursor = Dir::get_neighbour_pos(
            &self.cursor, &self.dir);
        self.segment_index += 1;
        Some(self.cursor.clone())
    }

    fn rotate(&mut self, dir: Dir) -> Option<MapPos> {
        self.segment_index = 0;
        self.cursor = Dir::get_neighbour_pos(&self.cursor, &self.dir);
        self.dir = dir;
        Some(self.cursor.clone())
    }
}

impl Iterator for RingIter {
    type Item = MapPos;

    fn next(&mut self) -> Option<MapPos> {
        if self.segment_index >= self.radius - 1 {
            if let Some(dir) = self.dir_iter.next() {
                self.rotate(dir)
            } else {
                if self.segment_index == self.radius {
                    None
                } else {
                    // last pos
                    self.simple_step()
                }
            }
        } else {
            self.simple_step()
        }
    }
}

pub struct SpiralIter {
    ring_iter: RingIter,
    radius: ZInt,
    last_radius: ZInt,
    origin: MapPos,
}

pub fn spiral_iter(pos: &MapPos, radius: ZInt) -> SpiralIter {
    assert!(radius >= 1);
    SpiralIter {
        ring_iter: ring_iter(pos, 1),
        radius: 1,
        last_radius: radius,
        origin: pos.clone(),
    }
}

impl Iterator for SpiralIter {
    type Item = MapPos;

    fn next(&mut self) -> Option<MapPos> {
        let pos = self.ring_iter.next();
        if pos.is_some() {
            pos
        } else {
            self.radius += 1;
            if self.radius > self.last_radius {
                None
            } else {
                self.ring_iter = ring_iter(
                    &self.origin, self.radius);
                self.ring_iter.next()
            }
        }
    }
}

pub fn distance(from: &MapPos, to: &MapPos) -> ZInt {
    let to = to.v;
    let from = from.v;
    let dx = (to.x + to.y / 2) - (from.x + from.y / 2);
    let dy = to.y - from.y;
    (dx.abs() + dy.abs() + (dx - dy).abs()) / 2
}

#[cfg(test)]
mod tests {
    use cgmath::{Vector2};
    use common::types::{MapPos};
    use super::{ring_iter, spiral_iter};

    #[test]
    fn test_ring_1() {
        let radius = 1;
        let start_pos = MapPos{v: Vector2{x: 0, y: 0}};
        let expected = [
            (0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 0) ];
        let mut expected = expected;
        for p in ring_iter(&start_pos, radius) {
            let expected = expected.next().expect(
                "Can not get next element from expected vector");
            assert_eq!(*expected, (p.v.x, p.v.y));
        }
        assert!(expected.next().is_none());
    }

    #[test]
    fn test_ring_2() {
        let radius = 2;
        let start_pos = MapPos{v: Vector2{x: 0, y: 0}};
        let expected = [
            (-1, -1),
            (-1, -2),
            (0, -2),
            (1, -2),
            (2, -1),
            (2, 0),
            (2, 1),
            (1, 2),
            (0, 2),
            (-1, 2),
            (-1, 1),
            (-2, 0),
        ];
        let mut expected = expected;
        for p in ring_iter(&start_pos, radius) {
            let expected = expected.next().expect(
                "Can not get next element from expected vector");
            assert_eq!(*expected, (p.v.x, p.v.y));
        }
        assert!(expected.next().is_none());
    }

    #[test]
    fn test_spiral_1() {
        let radius = 2;
        let start_pos = MapPos{v: Vector2{x: 0, y: 0}};
        let expected = [
            // ring 1
            (0, -1),
            (1, -1),
            (1, 0),
            (1, 1),
            (0, 1),
            (-1, 0),
            // ring 2
            (-1, -1),
            (-1, -2),
            (0, -2),
            (1, -2),
            (2, -1),
            (2, 0),
            (2, 1),
            (1, 2),
            (0, 2),
            (-1, 2),
            (-1, 1),
            (-2, 0),
        ];
        let mut expected = expected;
        for p in spiral_iter(&start_pos, radius) {
            let expected = expected.next().expect(
                "Can not get next element from expected vector");
            assert_eq!(*expected, (p.v.x, p.v.y));
        }
        assert!(expected.next().is_none());
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>map.rs: Fixed tests<commit_after>// See LICENSE file for copyright and license details.

use std::iter::{repeat};
use std::num::{Float, SignedInt};
use cgmath::{Vector};
use common::types::{Size2, ZInt, MapPos};
use dir::{Dir, DirIter, dirs};

#[derive(Clone)]
pub enum Terrain {
    Plain,
    Trees,
}

pub struct Map<T> {
    tiles: Vec<T>,
    size: Size2<ZInt>,
}

impl<T: Clone> Map<T> {
    // TODO: remove 'empty'
    pub fn new(size: &Size2<ZInt>, empty: T) -> Map<T> {
        let tiles_count = size.w * size.h;
        let tiles = repeat(empty).take(tiles_count as usize).collect();
        Map {
            tiles: tiles,
            size: size.clone(),
        }
    }

    pub fn size(&self) -> &Size2<ZInt> {
        &self.size
    }

    pub fn tile_mut(&mut self, pos: &MapPos) -> &mut T {
        assert!(self.is_inboard(pos));
        let index = self.size.w * pos.v.y + pos.v.x;
        &mut self.tiles[index as usize]
    }

    pub fn tile(&self, pos: &MapPos) -> &T {
        assert!(self.is_inboard(pos));
        let index = self.size.w * pos.v.y + pos.v.x;
        &self.tiles[index as usize]
    }

    pub fn is_inboard(&self, pos: &MapPos) -> bool {
        let x = pos.v.x;
        let y = pos.v.y;
        x >= 0 && y >= 0 && x < self.size.w && y < self.size.h
    }

    pub fn get_iter(&self) -> MapPosIter {
        MapPosIter::new(self.size())
    }
}

pub struct MapPosIter {
    cursor: MapPos,
    map_size: Size2<ZInt>,
}

impl MapPosIter {
    fn new(map_size: &Size2<ZInt>) -> MapPosIter {
        MapPosIter {
            cursor: MapPos{v: Vector::from_value(0)},
            map_size: map_size.clone(),
        }
    }
}

impl Iterator for MapPosIter {
    type Item = MapPos;

    fn next(&mut self) -> Option<MapPos> {
        let current_pos = if self.cursor.v.y >= self.map_size.h {
            None
        } else {
            Some(self.cursor.clone())
        };
        self.cursor.v.x += 1;
        if self.cursor.v.x >= self.map_size.w {
            self.cursor.v.x = 0;
            self.cursor.v.y += 1;
        }
        current_pos
    }
}

pub struct RingIter {
    cursor: MapPos,
    segment_index: ZInt,
    dir_iter: DirIter,
    radius: ZInt,
    dir: Dir,
}

pub fn ring_iter(pos: &MapPos, radius: ZInt) -> RingIter {
    let mut pos = pos.clone();
    pos.v.x -= radius;
    let mut dir_iter = dirs();
    let dir = dir_iter.next()
        .expect("Can`t get first direction");
    assert_eq!(dir, Dir::SouthEast);
    RingIter {
        cursor: pos.clone(),
        radius: radius,
        segment_index: 0,
        dir_iter: dir_iter,
        dir: dir,
    }
}

impl RingIter {
    fn simple_step(&mut self) -> Option<MapPos> {
        self.cursor = Dir::get_neighbour_pos(
            &self.cursor, &self.dir);
        self.segment_index += 1;
        Some(self.cursor.clone())
    }

    fn rotate(&mut self, dir: Dir) -> Option<MapPos> {
        self.segment_index = 0;
        self.cursor = Dir::get_neighbour_pos(&self.cursor, &self.dir);
        self.dir = dir;
        Some(self.cursor.clone())
    }
}

impl Iterator for RingIter {
    type Item = MapPos;

    fn next(&mut self) -> Option<MapPos> {
        if self.segment_index >= self.radius - 1 {
            if let Some(dir) = self.dir_iter.next() {
                self.rotate(dir)
            } else {
                if self.segment_index == self.radius {
                    None
                } else {
                    // last pos
                    self.simple_step()
                }
            }
        } else {
            self.simple_step()
        }
    }
}

pub struct SpiralIter {
    ring_iter: RingIter,
    radius: ZInt,
    last_radius: ZInt,
    origin: MapPos,
}

pub fn spiral_iter(pos: &MapPos, radius: ZInt) -> SpiralIter {
    assert!(radius >= 1);
    SpiralIter {
        ring_iter: ring_iter(pos, 1),
        radius: 1,
        last_radius: radius,
        origin: pos.clone(),
    }
}

impl Iterator for SpiralIter {
    type Item = MapPos;

    fn next(&mut self) -> Option<MapPos> {
        let pos = self.ring_iter.next();
        if pos.is_some() {
            pos
        } else {
            self.radius += 1;
            if self.radius > self.last_radius {
                None
            } else {
                self.ring_iter = ring_iter(
                    &self.origin, self.radius);
                self.ring_iter.next()
            }
        }
    }
}

pub fn distance(from: &MapPos, to: &MapPos) -> ZInt {
    let to = to.v;
    let from = from.v;
    let dx = (to.x + to.y / 2) - (from.x + from.y / 2);
    let dy = to.y - from.y;
    (dx.abs() + dy.abs() + (dx - dy).abs()) / 2
}

#[cfg(test)]
mod tests {
    use cgmath::{Vector2};
    use common::types::{MapPos};
    use super::{ring_iter, spiral_iter};

    #[test]
    fn test_ring_1() {
        let radius = 1;
        let start_pos = MapPos{v: Vector2{x: 0, y: 0}};
        let expected = [
            (0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 0) ];
        let mut expected = expected.iter();
        for p in ring_iter(&start_pos, radius) {
            let expected = expected.next().expect(
                "Can not get next element from expected vector");
            assert_eq!(*expected, (p.v.x, p.v.y));
        }
        assert!(expected.next().is_none());
    }

    #[test]
    fn test_ring_2() {
        let radius = 2;
        let start_pos = MapPos{v: Vector2{x: 0, y: 0}};
        let expected = [
            (-1, -1),
            (-1, -2),
            (0, -2),
            (1, -2),
            (2, -1),
            (2, 0),
            (2, 1),
            (1, 2),
            (0, 2),
            (-1, 2),
            (-1, 1),
            (-2, 0),
        ];
        let mut expected = expected.iter();
        for p in ring_iter(&start_pos, radius) {
            let expected = expected.next().expect(
                "Can not get next element from expected vector");
            assert_eq!(*expected, (p.v.x, p.v.y));
        }
        assert!(expected.next().is_none());
    }

    #[test]
    fn test_spiral_1() {
        let radius = 2;
        let start_pos = MapPos{v: Vector2{x: 0, y: 0}};
        let expected = [
            // ring 1
            (0, -1),
            (1, -1),
            (1, 0),
            (1, 1),
            (0, 1),
            (-1, 0),
            // ring 2
            (-1, -1),
            (-1, -2),
            (0, -2),
            (1, -2),
            (2, -1),
            (2, 0),
            (2, 1),
            (1, 2),
            (0, 2),
            (-1, 2),
            (-1, 1),
            (-2, 0),
        ];
        let mut expected = expected.iter();
        for p in spiral_iter(&start_pos, radius) {
            let expected = expected.next().expect(
                "Can not get next element from expected vector");
            assert_eq!(*expected, (p.v.x, p.v.y));
        }
        assert!(expected.next().is_none());
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketConstants;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{Temporary, JSRef};
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::eventtarget::{EventTarget, EventTargetHelpers, WebSocketTypeId};
use servo_net::resource_task::{Load, LoadData, LoadResponse};
use servo_util::str::DOMString;
use std::ascii::IntoBytes;
use std::comm::channel;
use url::Url;

#[dom_struct]
pub struct WebSocket {
    eventtarget: EventTarget,
    url: DOMString,
    response: LoadResponse,
    state: u16
}

impl WebSocket {
    pub fn new_inherited(url: DOMString, resp: LoadResponse, state_value: u16) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(WebSocketTypeId),
            url: url,
            response: resp,
            state: state_value
        }
    }

    pub fn new(global: &GlobalRef, url: DOMString) -> Temporary<WebSocket> {
        let resource_task = global.resource_task();
        let ws_url = Url::parse(url.as_slice()).unwrap();
        let(start_chan, start_port) = channel();
        resource_task.send(Load(LoadData::new(ws_url), start_chan));
        let resp = start_port.recv();
        reflect_dom_object(box WebSocket::new_inherited(url, resp, WebSocketConstants::OPEN),
                           global,
                           WebSocketBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef, url: DOMString) -> Fallible<Temporary<WebSocket>> {
        Ok(WebSocket::new(global, url))
    }
}

impl Reflectable for WebSocket {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }
}

impl<'a> WebSocketMethods for JSRef<'a, WebSocket> {
    event_handler!(open, GetOnopen, SetOnopen)
    event_handler!(error, GetOnerror, SetOnerror)
    event_handler!(close, GetOnclose, SetOnclose)
    event_handler!(message, GetOnmessage, SetOnmessage)

    fn Send(self, message: DOMString) {
        if self.state == WebSocketConstants::OPEN
        {
            let message_u8: Vec<u8>=message.to_string().into_bytes();
            assert!(message.len() <= 125);
            let mut payload: Vec<u8> = Vec::with_capacity(2 + message_u8.len());
           /*
              We are sending a single framed unmasked text message. Referring to http://tools.ietf.org/html/rfc6455#section-5.7.
              10000001 this indicates FIN bit=1 and the opcode is 0001 which means it is a text frame and the decimal equivalent is 129
           */
            const ENTRY1: u8 = 0x81;
            payload.push(ENTRY1);
            payload.push(message.len() as u8);
            payload.push_all(message_u8.as_slice());
        } else {
             return;
        }
    }

    fn Close(self) {
    }

    fn Url(self) -> DOMString {
        self.url.clone()
    }
}
<commit_msg>unaddressed issues are resolved<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::WebSocketBinding;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketMethods;
use dom::bindings::codegen::Bindings::WebSocketBinding::WebSocketConstants;
use dom::bindings::error::Fallible;
use dom::bindings::global::GlobalRef;
use dom::bindings::js::{Temporary, JSRef};
use dom::bindings::trace::JSTraceable;
use dom::bindings::utils::{Reflectable, Reflector, reflect_dom_object};
use dom::eventtarget::{EventTarget, EventTargetHelpers, WebSocketTypeId};
use servo_net::resource_task::{Load, LoadData, LoadResponse};
use servo_util::str::DOMString;
use std::ascii::IntoBytes;
use std::comm::channel;
use url::Url;

#[dom_struct]
pub struct WebSocket {
    eventtarget: EventTarget,
    url: DOMString,
    response: LoadResponse,
    state: u16
}

impl WebSocket {
    pub fn new_inherited(url: DOMString, resp: LoadResponse, state_value: u16) -> WebSocket {
        WebSocket {
            eventtarget: EventTarget::new_inherited(WebSocketTypeId),
            url: url,
            response: resp,
            state: state_value
        }
    }

    pub fn new(global: &GlobalRef, url: DOMString) -> Temporary<WebSocket> {
        let resource_task = global.resource_task();
        let ws_url = Url::parse(url.as_slice()).unwrap();
        let(start_chan, start_port) = channel();
        resource_task.send(Load(LoadData::new(ws_url), start_chan));
        let resp = start_port.recv();
        reflect_dom_object(box WebSocket::new_inherited(url, resp, WebSocketConstants::OPEN),
                           global,
                           WebSocketBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef, url: DOMString) -> Fallible<Temporary<WebSocket>> {
        Ok(WebSocket::new(global, url))
    }
}

impl Reflectable for WebSocket {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }
}

impl<'a> WebSocketMethods for JSRef<'a, WebSocket> {
    event_handler!(open, GetOnopen, SetOnopen)
    event_handler!(error, GetOnerror, SetOnerror)
    event_handler!(close, GetOnclose, SetOnclose)
    event_handler!(message, GetOnmessage, SetOnmessage)

    fn Send(self, message: DOMString) {
        if self.state == WebSocketConstants::OPEN {
            let message_u8: Vec<u8>=message.to_string().into_bytes();
            assert!(message.len() <= 125);
            let mut payload: Vec<u8> = Vec::with_capacity(2 + message_u8.len());
           /*
              We are sending a single framed unmasked text message. Referring to http://tools.ietf.org/html/rfc6455#section-5.7.
              10000001 this indicates FIN bit=1 and the opcode is 0001 which means it is a text frame and the decimal equivalent is 129
           */
            const ENTRY1: u8 = 0x81;
            payload.push(ENTRY1);
            payload.push(message.len() as u8);
            payload.push_all(message_u8.as_slice());
        } else {
             return;
        }
    }

    fn Close(self) {
    }

    fn Url(self) -> DOMString {
        self.url.clone()
    }
}
<|endoftext|>


<commit_before>#[macro_use]
pub mod mem_cursor;

pub mod cell;
pub mod chunk;
pub mod cleaner;
pub mod entry;
pub mod io;
pub mod schema;
pub mod tombstone;
pub mod types;
pub mod segs;

mod clock;
<commit_msg>cargo fmt<commit_after>#[macro_use]
pub mod mem_cursor;

pub mod cell;
pub mod chunk;
pub mod cleaner;
pub mod entry;
pub mod io;
pub mod schema;
pub mod segs;
pub mod tombstone;
pub mod types;

mod clock;
<|endoftext|>