<commit_before>use std::*;
use std::iter::*;
use std::sync::atomic::*;
use rand::{Rng, XorShiftRng};
use types::*;
use config::*;
use player::*;
use field::*;

#[unsafe_no_drop_flag]
struct UctNode {
  wins: AtomicUsize,
  draws: AtomicUsize,
  visits: AtomicUsize,
  pos: Pos,
  child: AtomicPtr<UctNode>,
  sibling: Option<Box<UctNode>>
}

impl Drop for UctNode {
  fn drop(&mut self) {
    self.clear_child();
  }
}

impl UctNode {
  pub fn new(pos: Pos) -> UctNode {
    UctNode {
      wins: AtomicUsize::new(0),
      draws: AtomicUsize::new(0),
      visits: AtomicUsize::new(0),
      pos: pos,
      child: AtomicPtr::new(ptr::null_mut()),
      sibling: None
    }
  }

  pub fn get_pos(&self) -> Pos {
    self.pos
  }

  pub fn set_pos(&mut self, pos: Pos) {
    self.pos = pos;
  }

  pub fn get_sibling(&mut self) -> Option<Box<UctNode>> {
    mem::replace(&mut self.sibling, None)
  }

  pub fn get_sibling_ref<'a>(&'a self) -> Option<&'a UctNode> {
    self.sibling.as_ref().map(|b| &**b)
  }

  pub fn get_sibling_mut<'a>(&'a mut self) -> Option<&'a mut UctNode> {
    self.sibling.as_mut().map(|b| &mut **b)
  }

  pub fn clear_sibling(&mut self) {
    self.sibling = None;
  }

  pub fn set_sibling(&mut self, sibling: Box<UctNode>) {
    self.sibling = Some(sibling);
  }

  pub fn set_sibling_option(&mut self, sibling: Option<Box<UctNode>>) {
    self.sibling = sibling;
  }

  pub fn get_child(&self) -> Option<Box<UctNode>> {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { mem::transmute(ptr) })
    } else {
      None
    }
  }

  pub fn get_child_ref<'a>(&'a self) -> Option<&'a UctNode> {
    let ptr = self.child.load(Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { &*ptr })
    } else {
      None
    }
  }

  pub fn get_child_mut<'a>(&'a mut self) -> Option<&'a mut UctNode> {
    let ptr = self.child.load(Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { &mut *ptr })
    } else {
      None
    }
  }

  pub fn clear_child(&self) {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child(&self, child: Box<UctNode>) {
    let ptr = self.child.swap(unsafe { mem::transmute(child) }, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child_if_empty(&self, child: Box<UctNode>) {
    let child_ptr = unsafe { mem::transmute(child) };
    let ptr = self.child.compare_and_swap(ptr::null_mut(), child_ptr, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(child_ptr) });
    }
  }

  pub fn get_visits(&self) -> usize {
    self.visits.load(Ordering::Relaxed)
  }

  pub fn get_wins(&self) -> usize {
    self.wins.load(Ordering::Relaxed)
  }

  pub fn get_draws(&self) -> usize {
    self.draws.load(Ordering::Relaxed)
  }

  pub fn add_win(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.wins.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_draw(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.draws.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_loose(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
  }

  pub fn clear_stats(&self) {
    self.wins.store(0, Ordering::Relaxed);
    self.draws.store(0, Ordering::Relaxed);
    self.visits.store(0, Ordering::Relaxed);
  }
}

pub struct UctRoot {
  node: Option<Box<UctNode>>,
  moves: Vec<Pos>,
  moves_field: Vec<Pos>,
  player: Player,
  moves_count: usize,
  hash: u64
}

impl UctRoot {
  fn clear(&mut self) {
    self.node = None;
    self.moves.clear();
    for i in self.moves_field.iter_mut() {
      *i = 0;
    }
    self.player = Player::Red;
    self.moves_count = 0;
    self.hash = 0;
  }

  fn init(&mut self, field: &Field, player: Player) {
    self.node = Some(Box::new(UctNode::new(0)));
    self.player = player;
    let width = field.width();
    for &start_pos in field.points_seq() {
      wave(width, start_pos, |pos| {
        if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && manhattan(width, start_pos, pos) <= UCT_RADIUS {
          if self.moves_field[pos] == 0 {
            self.moves.push(pos);
          }
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
    }
  }

  fn expand_node(node: &mut UctNode, moves: &Vec<Pos>) {
    if node.get_child_ref().is_none() {
      if node.get_visits() == usize::max_value() {
        node.clear_stats();
      }
    } else {
      let mut next = node.get_child_mut();
      while next.as_ref().unwrap().get_sibling_ref().is_some() {
        UctRoot::expand_node(*next.as_mut().unwrap(), moves);
        next = next.unwrap().get_sibling_mut();
      }
      UctRoot::expand_node(*next.as_mut().unwrap(), moves);
      for &pos in moves {
        next.as_mut().unwrap().set_sibling(Box::new(UctNode::new(pos)));
        next = next.unwrap().get_sibling_mut();
      }
    }
  }

  fn update(&mut self, field: &Field, player: Player) {
    if self.node.is_some() && field.hash_at(self.moves_count) != Some(self.hash) {
      self.clear();
    }
    if self.node.is_none() {
      self.init(field, player);
    } else {
      let points_seq = field.points_seq();
      let moves_count = field.moves_count();
      loop {
        if self.moves_count == moves_count {
          break;
        }
        let next_pos = points_seq[self.moves_count];
        if !field.is_players_point(next_pos, self.player) {
          self.clear();
          self.init(field, player);
          break;
        }
        let mut next = self.node.as_ref().unwrap().get_child();
        while next.is_some() && next.as_ref().unwrap().pos != next_pos {
          next = next.unwrap().get_sibling();
        }
        if let Some(ref mut node) = next {
          node.clear_sibling();
        } else {
          self.clear();
          self.init(field, player);
          break;
        }
        self.node = next;
        let moves_field = &mut self.moves_field;
        self.moves.retain(|&pos| {
          if field.is_putting_allowed(pos) {
            true
          } else {
            moves_field[pos] = 0;
            false
          }
        });
        let mut added_moves = Vec::new();
        let width = field.width();
        wave(width, next_pos, |pos| {
          if moves_field[pos] != next_pos && field.is_putting_allowed(pos) && manhattan(width, next_pos, pos) <= UCT_RADIUS {
            if moves_field[pos] == 0 {
              added_moves.push(pos);
            }
            moves_field[pos] = next_pos;
            true
          } else {
            false
          }
        });
        UctRoot::expand_node(self.node.as_mut().unwrap(), &added_moves);
        self.moves_count += 1;
        self.player = self.player.next();
      }
    }
  }

  pub fn new(length: Pos) -> UctRoot {
    UctRoot {
      node: None,
      moves: Vec::with_capacity(length),
      moves_field: repeat(0).take(length).collect(),
      player: Player::Red,
      moves_count: 0,
      hash: 0
    }
  }

  fn play_random_game<T: Rng>(field: &mut Field, mut player: Player, rng: &mut T, possible_moves: &mut Vec<Pos>) -> Option<Player> {
    rng.shuffle(possible_moves);
    let mut putted: CoordProd = 0;
    for &pos in possible_moves.iter() {
      if field.is_putting_allowed(pos) && !field.is_empty_base(pos) {
        field.put_point(pos, player);
        player = player.next();
        putted += 1;
      }
    }
    let red_score = field.score(Player::Red);
    let result = if red_score > 0 {
      Some(Player::Red)
    } else if red_score < 0 {
      Some(Player::Black)
    } else {
      None
    };
    for _ in 0 .. putted {
      field.undo();
    }
    result
  }

  fn ucb(parent: &UctNode, node: &UctNode) -> f32 {
    let wins = node.get_wins() as f32;
    let draws = node.get_draws() as f32;
    let visits = node.get_visits() as f32;
    let parent_visits = parent.get_visits() as f32;
    let win_rate = (wins + draws * UCT_DRAW_WEIGHT) / visits;
    let uct = match UCB_TYPE {
      UcbType::Ucb1 => UCTK * f32::sqrt(2.0 * f32::ln(parent_visits) / visits),
      UcbType::Ucb1Tuned => {
        let v = (wins + draws * UCT_DRAW_WEIGHT * UCT_DRAW_WEIGHT) / visits - win_rate * win_rate + f32::sqrt(2.0 * f32::ln(parent_visits) / visits);
        UCTK * f32::sqrt(v.min(0.25) * f32::ln(parent_visits) / visits)
      }
    };
    win_rate + uct
  }

  fn create_children(field: &Field, possible_moves: &Vec<Pos>, node: &UctNode) {
    let mut children = None;
    for &pos in possible_moves {
      if field.is_putting_allowed(pos) {
        let mut cur_child = Box::new(UctNode::new(pos));
        cur_child.set_sibling_option(children);
        children = Some(cur_child);
      }
    }
    if let Some(child) = children {
      node.set_child_if_empty(child)
    }
  }

  fn uct_select<'a, T: Rng>(node: &'a UctNode, rng: &mut T) -> Option<&'a UctNode> {
    let mut best_uct = 0f32;
    let mut result = None;
    let mut next = node.get_child_ref();
    while let Some(next_node) = next {
      let visits = next_node.get_visits();
      let wins = next_node.get_wins();
      let uct_value = if visits == usize::max_value() {
        if wins == usize::max_value() {
          100000.0
        } else {
          -1.0
        }
      } else if visits > 0 {
        UctRoot::ucb(node, next_node)
      } else {
        10000.0 + (rng.gen::<u16>() % 1000) as f32
      };
      if uct_value > best_uct {
        best_uct = uct_value;
        result = Some(next_node);
      }
      next = next_node.get_sibling_ref();
    }
    result
  }

  fn play_simulation_rec<T: Rng>(field: &mut Field, node: &UctNode, possible_moves: &mut Vec<Pos>, rng: &mut T, depth: Depth) {

  }

  fn play_simulation<T: Rng>(field: &mut Field, rng: &mut T) {

  }

  fn best_move_generic<T: Rng>(&mut self, field: &Field, player: Player, rng: &mut T, should_stop: &AtomicBool) -> Option<Pos> {
    self.update(field, player);
    let mut guards = Vec::with_capacity(4);
    for _ in 0 .. 4 {
      let xor_shift_rng = rng.gen::<XorShiftRng>();
      guards.push(thread::scoped(|| {
        let mut local_field = field.clone();
        let mut local_rng = xor_shift_rng;
        while !should_stop.load(Ordering::Relaxed) {
          UctRoot::play_simulation(&mut local_field, &mut local_rng);
        }
      }));
    }
    drop(guards);
    let mut best_uct = 0f32;
    let mut result = None;
    if let Some(ref root) = self.node {
      let mut next = root.get_child_ref();
      while let Some(next_node) = next {
        let uct_value = UctRoot::ucb(root, next_node);
        if uct_value > best_uct {
          best_uct = uct_value;
          result = Some(next_node.get_pos());
        }
        next = next_node.get_sibling_ref();
      }
    }
    result
  }

  pub fn best_move<T: Rng>(&mut self, field: &Field, player: Player, rng: &mut T, time: Time) -> Option<Pos> {
    let should_stop = AtomicBool::new(false);
    let guard = thread::scoped(|| {
      thread::sleep_ms(time);
      should_stop.store(true, Ordering::Relaxed);
    });
    let result = self.best_move_generic(field, player, rng, &should_stop);
    drop(guard);
    result
  }

  //pub fn estimates
}
<commit_msg>Small refactoring.<commit_after>use std::*;
use std::iter::*;
use std::sync::atomic::*;
use rand::{Rng, XorShiftRng};
use types::*;
use config::*;
use player::*;
use field::*;

#[unsafe_no_drop_flag]
struct UctNode {
  wins: AtomicUsize,
  draws: AtomicUsize,
  visits: AtomicUsize,
  pos: Pos,
  child: AtomicPtr<UctNode>,
  sibling: Option<Box<UctNode>>
}

impl Drop for UctNode {
  fn drop(&mut self) {
    self.clear_child();
  }
}

impl UctNode {
  pub fn new(pos: Pos) -> UctNode {
    UctNode {
      wins: AtomicUsize::new(0),
      draws: AtomicUsize::new(0),
      visits: AtomicUsize::new(0),
      pos: pos,
      child: AtomicPtr::new(ptr::null_mut()),
      sibling: None
    }
  }

  pub fn get_pos(&self) -> Pos {
    self.pos
  }

  pub fn set_pos(&mut self, pos: Pos) {
    self.pos = pos;
  }

  pub fn get_sibling(&mut self) -> Option<Box<UctNode>> {
    mem::replace(&mut self.sibling, None)
  }

  pub fn get_sibling_ref(&self) -> Option<&UctNode> {
    self.sibling.as_ref().map(|b| &**b)
  }

  pub fn get_sibling_mut(&mut self) -> Option<&mut UctNode> {
    self.sibling.as_mut().map(|b| &mut **b)
  }

  pub fn clear_sibling(&mut self) {
    self.sibling = None;
  }

  pub fn set_sibling(&mut self, sibling: Box<UctNode>) {
    self.sibling = Some(sibling);
  }

  pub fn set_sibling_option(&mut self, sibling: Option<Box<UctNode>>) {
    self.sibling = sibling;
  }

  pub fn get_child(&self) -> Option<Box<UctNode>> {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { mem::transmute(ptr) })
    } else {
      None
    }
  }

  pub fn get_child_ref(&self) -> Option<&UctNode> {
    let ptr = self.child.load(Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { &*ptr })
    } else {
      None
    }
  }

  pub fn get_child_mut(&mut self) -> Option<&mut UctNode> {
    let ptr = self.child.load(Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { &mut *ptr })
    } else {
      None
    }
  }

  pub fn clear_child(&self) {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child(&self, child: Box<UctNode>) {
    let ptr = self.child.swap(unsafe { mem::transmute(child) }, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child_if_empty(&self, child: Box<UctNode>) {
    let child_ptr = unsafe { mem::transmute(child) };
    let ptr = self.child.compare_and_swap(ptr::null_mut(), child_ptr, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(child_ptr) });
    }
  }

  pub fn get_visits(&self) -> usize {
    self.visits.load(Ordering::Relaxed)
  }

  pub fn get_wins(&self) -> usize {
    self.wins.load(Ordering::Relaxed)
  }

  pub fn get_draws(&self) -> usize {
    self.draws.load(Ordering::Relaxed)
  }

  pub fn add_win(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.wins.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_draw(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.draws.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_loose(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
  }

  pub fn clear_stats(&self) {
    self.wins.store(0, Ordering::Relaxed);
    self.draws.store(0, Ordering::Relaxed);
    self.visits.store(0, Ordering::Relaxed);
  }
}

pub struct UctRoot {
  node: Option<Box<UctNode>>,
  moves: Vec<Pos>,
  moves_field: Vec<Pos>,
  player: Player,
  moves_count: usize,
  hash: u64
}

impl UctRoot {
  fn clear(&mut self) {
    self.node = None;
    self.moves.clear();
    for i in self.moves_field.iter_mut() {
      *i = 0;
    }
    self.player = Player::Red;
    self.moves_count = 0;
    self.hash = 0;
  }

  fn init(&mut self, field: &Field, player: Player) {
    self.node = Some(Box::new(UctNode::new(0)));
    self.player = player;
    let width = field.width();
    for &start_pos in field.points_seq() {
      wave(width, start_pos, |pos| {
        if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && manhattan(width, start_pos, pos) <= UCT_RADIUS {
          if self.moves_field[pos] == 0 {
            self.moves.push(pos);
          }
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
    }
  }

  fn expand_node(node: &mut UctNode, moves: &Vec<Pos>) {
    if node.get_child_ref().is_none() {
      if node.get_visits() == usize::max_value() {
        node.clear_stats();
      }
    } else {
      let mut next = node.get_child_mut();
      while next.as_ref().unwrap().get_sibling_ref().is_some() {
        UctRoot::expand_node(*next.as_mut().unwrap(), moves);
        next = next.unwrap().get_sibling_mut();
      }
      UctRoot::expand_node(*next.as_mut().unwrap(), moves);
      for &pos in moves {
        next.as_mut().unwrap().set_sibling(Box::new(UctNode::new(pos)));
        next = next.unwrap().get_sibling_mut();
      }
    }
  }

  fn update(&mut self, field: &Field, player: Player) {
    if self.node.is_some() && field.hash_at(self.moves_count) != Some(self.hash) {
      self.clear();
    }
    if self.node.is_none() {
      self.init(field, player);
    } else {
      let points_seq = field.points_seq();
      let moves_count = field.moves_count();
      loop {
        if self.moves_count == moves_count {
          break;
        }
        let next_pos = points_seq[self.moves_count];
        if !field.is_players_point(next_pos, self.player) {
          self.clear();
          self.init(field, player);
          break;
        }
        let mut next = self.node.as_ref().unwrap().get_child();
        while next.is_some() && next.as_ref().unwrap().pos != next_pos {
          next = next.unwrap().get_sibling();
        }
        if let Some(ref mut node) = next {
          node.clear_sibling();
        } else {
          self.clear();
          self.init(field, player);
          break;
        }
        self.node = next;
        let moves_field = &mut self.moves_field;
        self.moves.retain(|&pos| {
          if field.is_putting_allowed(pos) {
            true
          } else {
            moves_field[pos] = 0;
            false
          }
        });
        let mut added_moves = Vec::new();
        let width = field.width();
        wave(width, next_pos, |pos| {
          if moves_field[pos] != next_pos && field.is_putting_allowed(pos) && manhattan(width, next_pos, pos) <= UCT_RADIUS {
            if moves_field[pos] == 0 {
              added_moves.push(pos);
            }
            moves_field[pos] = next_pos;
            true
          } else {
            false
          }
        });
        UctRoot::expand_node(self.node.as_mut().unwrap(), &added_moves);
        self.moves_count += 1;
        self.player = self.player.next();
      }
    }
  }

  pub fn new(length: Pos) -> UctRoot {
    UctRoot {
      node: None,
      moves: Vec::with_capacity(length),
      moves_field: repeat(0).take(length).collect(),
      player: Player::Red,
      moves_count: 0,
      hash: 0
    }
  }

  fn play_random_game<T: Rng>(field: &mut Field, mut player: Player, rng: &mut T, possible_moves: &mut Vec<Pos>) -> Option<Player> {
    rng.shuffle(possible_moves);
    let mut putted: CoordProd = 0;
    for &pos in possible_moves.iter() {
      if field.is_putting_allowed(pos) && !field.is_empty_base(pos) {
        field.put_point(pos, player);
        player = player.next();
        putted += 1;
      }
    }
    let red_score = field.score(Player::Red);
    let result = if red_score > 0 {
      Some(Player::Red)
    } else if red_score < 0 {
      Some(Player::Black)
    } else {
      None
    };
    for _ in 0 .. putted {
      field.undo();
    }
    result
  }

  fn ucb(parent: &UctNode, node: &UctNode) -> f32 {
    let wins = node.get_wins() as f32;
    let draws = node.get_draws() as f32;
    let visits = node.get_visits() as f32;
    let parent_visits = parent.get_visits() as f32;
    let win_rate = (wins + draws * UCT_DRAW_WEIGHT) / visits;
    let uct = match UCB_TYPE {
      UcbType::Ucb1 => UCTK * f32::sqrt(2.0 * f32::ln(parent_visits) / visits),
      UcbType::Ucb1Tuned => {
        let v = (wins + draws * UCT_DRAW_WEIGHT * UCT_DRAW_WEIGHT) / visits - win_rate * win_rate + f32::sqrt(2.0 * f32::ln(parent_visits) / visits);
        UCTK * f32::sqrt(v.min(0.25) * f32::ln(parent_visits) / visits)
      }
    };
    win_rate + uct
  }

  fn create_children(field: &Field, possible_moves: &Vec<Pos>, node: &UctNode) {
    let mut children = None;
    for &pos in possible_moves {
      if field.is_putting_allowed(pos) {
        let mut cur_child = Box::new(UctNode::new(pos));
        cur_child.set_sibling_option(children);
        children = Some(cur_child);
      }
    }
    if let Some(child) = children {
      node.set_child_if_empty(child)
    }
  }

  fn uct_select<'a, T: Rng>(node: &'a UctNode, rng: &mut T) -> Option<&'a UctNode> {
    let mut best_uct = 0f32;
    let mut result = None;
    let mut next = node.get_child_ref();
    while let Some(next_node) = next {
      let visits = next_node.get_visits();
      let wins = next_node.get_wins();
      let uct_value = if visits == usize::max_value() {
        if wins == usize::max_value() {
          100000.0
        } else {
          -1.0
        }
      } else if visits > 0 {
        UctRoot::ucb(node, next_node)
      } else {
        10000.0 + (rng.gen::<u16>() % 1000) as f32
      };
      if uct_value > best_uct {
        best_uct = uct_value;
        result = Some(next_node);
      }
      next = next_node.get_sibling_ref();
    }
    result
  }

  fn play_simulation_rec<T: Rng>(field: &mut Field, node: &UctNode, possible_moves: &mut Vec<Pos>, rng: &mut T, depth: Depth) {

  }

  fn play_simulation<T: Rng>(field: &mut Field, rng: &mut T) {

  }

  fn best_move_generic<T: Rng>(&mut self, field: &Field, player: Player, rng: &mut T, should_stop: &AtomicBool) -> Option<Pos> {
    self.update(field, player);
    let mut guards = Vec::with_capacity(4);
    for _ in 0 .. 4 {
      let xor_shift_rng = rng.gen::<XorShiftRng>();
      guards.push(thread::scoped(|| {
        let mut local_field = field.clone();
        let mut local_rng = xor_shift_rng;
        while !should_stop.load(Ordering::Relaxed) {
          UctRoot::play_simulation(&mut local_field, &mut local_rng);
        }
      }));
    }
    drop(guards);
    let mut best_uct = 0f32;
    let mut result = None;
    if let Some(ref root) = self.node {
      let mut next = root.get_child_ref();
      while let Some(next_node) = next {
        let uct_value = UctRoot::ucb(root, next_node);
        if uct_value > best_uct {
          best_uct = uct_value;
          result = Some(next_node.get_pos());
        }
        next = next_node.get_sibling_ref();
      }
    }
    result
  }

  pub fn best_move<T: Rng>(&mut self, field: &Field, player: Player, rng: &mut T, time: Time) -> Option<Pos> {
    let should_stop = AtomicBool::new(false);
    let guard = thread::scoped(|| {
      thread::sleep_ms(time);
      should_stop.store(true, Ordering::Relaxed);
    });
    let result = self.best_move_generic(field, player, rng, &should_stop);
    drop(guard);
    result
  }

  //pub fn estimates
}
<|endoftext|>


<commit_before>trait StrParseExt {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool;
}

impl<'a> StrParseExt for &'a str {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool,
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }
}

pub trait XmlStr {
    /// Find the end of the quoted attribute value, not including the quote
    fn end_of_attribute(&self, quote: &str) -> Option<usize>;
    /// Find the end of the direct character data
    fn end_of_char_data(&self) -> Option<usize>;
    /// Find the end of the CData section, not including the ]]>
    fn end_of_cdata(&self) -> Option<usize>;
    /// Find the end of a run of decimal characters
    fn end_of_decimal_chars(&self) -> Option<usize>;
    /// Find the end of a run of hexidecimal characters
    fn end_of_hex_chars(&self) -> Option<usize>;
    /// Find the end of the comment, not including the -->
    fn end_of_comment(&self) -> Option<usize>;
    /// Find the end of the processing instruction, not including the ?>
    fn end_of_pi_value(&self) -> Option<usize>;
    /// Find the end of the [Name](http://www.w3.org/TR/xml/#NT-Name)
    fn end_of_name(&self) -> Option<usize>;
    /// Find the end of the [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)
    fn end_of_ncname(&self) -> Option<usize>;
    /// Find the end of a run of space characters
    fn end_of_space(&self) -> Option<usize>;
    /// Find the end of the starting tag
    fn end_of_start_tag(&self) -> Option<usize>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<usize> {
        if self.len() == 0 ||
           self.starts_with("&") ||
           self.starts_with("<") ||
           self.starts_with(quote)
        {
            return None;
        }

        let quote_char = quote.chars().next().expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_char_data(&self) -> Option<usize> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        let mut indices = self.char_indices();

        loop {
            let mut positions = indices.by_ref().skip_while(|&(_, c)| {
                c != '<' && c != '&' && c != ']'
            });

            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = &self[offset..];
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<usize> {
        match self.find("]]>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_decimal_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<usize> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        match self.find("--") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_pi_value(&self) -> Option<usize> {
        match self.find("?>") {
            None => None,
            Some(offset) => Some(offset),
        }
    }

    fn end_of_name(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_ncname(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_ncname_start_char(), |c| c.is_ncname_char())
    }

    fn end_of_space(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<usize> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

/// Predicates used when parsing an characters in an XML document.
pub trait XmlChar {
    /// Is this a [NameStartChar](http://www.w3.org/TR/xml/#NT-NameStartChar)?
    fn is_name_start_char(self) -> bool;
    /// Is this a [NameChar](http://www.w3.org/TR/xml/#NT-NameChar)?
    fn is_name_char(self) -> bool;
    /// Does this start a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_start_char(self) -> bool;
    /// Is this a component of a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_char(self) -> bool;
    /// Is this an [XML space](http://www.w3.org/TR/xml/#NT-S)?
    fn is_space_char(self) -> bool;
    fn is_decimal_char(self) -> bool;
    fn is_hex_char(self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(self) -> bool {
        self == ':' || self.is_ncname_start_char()
    }

    fn is_name_char(self) -> bool {
        self.is_name_start_char() || self.is_ncname_char()
    }

    fn is_ncname_start_char(self) -> bool {
        match self {
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\u{0000C0}'...'\u{0000D6}' |
            '\u{0000D8}'...'\u{0000F6}' |
            '\u{0000F8}'...'\u{0002FF}' |
            '\u{000370}'...'\u{00037D}' |
            '\u{00037F}'...'\u{001FFF}' |
            '\u{00200C}'...'\u{00200D}' |
            '\u{002070}'...'\u{00218F}' |
            '\u{002C00}'...'\u{002FEF}' |
            '\u{003001}'...'\u{00D7FF}' |
            '\u{00F900}'...'\u{00FDCF}' |
            '\u{00FDF0}'...'\u{00FFFD}' |
            '\u{010000}'...'\u{0EFFFF}' => true,
            _ => false,
        }
    }

    fn is_ncname_char(self) -> bool {
        if self.is_ncname_start_char() { return true; }
        match self {
            '-'                     |
            '.'                     |
            '0'...'9'               |
            '\u{00B7}'              |
            '\u{0300}'...'\u{036F}' |
            '\u{203F}'...'\u{2040}' => true,
            _ => false
        }
    }

    fn is_space_char(self) -> bool {
        match self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(self) -> bool {
        match self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(self) -> bool {
        match self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod test {
    use super::XmlStr;

    #[test]
    fn end_of_char_data_leading_ampersand() {
        assert_eq!("&".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_less_than() {
        assert_eq!("<".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_cdata_end() {
        assert_eq!("]]>".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_until_ampersand() {
        assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_less_than() {
        assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_cdata_end() {
        assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_includes_right_square() {
        assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
    }

    #[test]
    fn end_of_char_data_includes_multiple_right_squares() {
        assert_eq!("hello]]world".end_of_char_data(), Some("hello]]world".len()));
    }
}
<commit_msg>Remove super-redundant matching<commit_after>trait StrParseExt {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool;
}

impl<'a> StrParseExt for &'a str {
    fn end_of_start_rest<F1, F2>(&self, is_first: F1, is_rest: F2) -> Option<usize>
        where F1: Fn(char) -> bool,
              F2: Fn(char) -> bool,
    {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if is_first(c) => (),
            Some((_, _)) => return None,
            None => return None,
        };

        let mut positions = positions.skip_while(|&(_, c)| is_rest(c));
        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len()),
        }
    }
}

pub trait XmlStr {
    /// Find the end of the quoted attribute value, not including the quote
    fn end_of_attribute(&self, quote: &str) -> Option<usize>;
    /// Find the end of the direct character data
    fn end_of_char_data(&self) -> Option<usize>;
    /// Find the end of the CData section, not including the ]]>
    fn end_of_cdata(&self) -> Option<usize>;
    /// Find the end of a run of decimal characters
    fn end_of_decimal_chars(&self) -> Option<usize>;
    /// Find the end of a run of hexidecimal characters
    fn end_of_hex_chars(&self) -> Option<usize>;
    /// Find the end of the comment, not including the -->
    fn end_of_comment(&self) -> Option<usize>;
    /// Find the end of the processing instruction, not including the ?>
    fn end_of_pi_value(&self) -> Option<usize>;
    /// Find the end of the [Name](http://www.w3.org/TR/xml/#NT-Name)
    fn end_of_name(&self) -> Option<usize>;
    /// Find the end of the [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)
    fn end_of_ncname(&self) -> Option<usize>;
    /// Find the end of a run of space characters
    fn end_of_space(&self) -> Option<usize>;
    /// Find the end of the starting tag
    fn end_of_start_tag(&self) -> Option<usize>;
}

impl<'a> XmlStr for &'a str {
    fn end_of_attribute(&self, quote: &str) -> Option<usize> {
        if self.len() == 0 ||
           self.starts_with("&") ||
           self.starts_with("<") ||
           self.starts_with(quote)
        {
            return None;
        }

        let quote_char = quote.chars().next().expect("Cant have null quote");

        let mut positions = self.char_indices().skip_while(|&(_, c)| c != '&' && c != '<' && c != quote_char);

        match positions.next() {
            Some((offset, _)) => Some(offset),
            None => Some(self.len())
        }
    }

    fn end_of_char_data(&self) -> Option<usize> {
        if self.starts_with("<") ||
           self.starts_with("&") ||
           self.starts_with("]]>")
        {
            return None
        }

        let mut indices = self.char_indices();

        loop {
            let mut positions = indices.by_ref().skip_while(|&(_, c)| {
                c != '<' && c != '&' && c != ']'
            });

            match positions.next() {
                None => return Some(self.len()),
                Some((offset, c)) if c == '<' || c == '&' => return Some(offset),
                Some((offset, _)) => {
                    let tail = &self[offset..];
                    if tail.starts_with("]]>") {
                        return Some(offset)
                    } else {
                        // False alarm, resume scanning
                        continue;
                    }
                },
            }
        }
    }

    fn end_of_cdata(&self) -> Option<usize> {
        self.find("]]>")
    }

    fn end_of_decimal_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_decimal_char(),
                               |c| c.is_decimal_char())
    }

    fn end_of_hex_chars(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_hex_char(),
                               |c| c.is_hex_char())
    }

    fn end_of_comment(&self) -> Option<usize> {
        // This deliberately does not include the >. -- is not allowed
        // in a comment, so we can just test the end if it matches the
        // complete close delimiter.
        self.find("--")
    }

    fn end_of_pi_value(&self) -> Option<usize> {
        self.find("?>")
    }

    fn end_of_name(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_name_start_char(), |c| c.is_name_char())
    }

    fn end_of_ncname(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_ncname_start_char(), |c| c.is_ncname_char())
    }

    fn end_of_space(&self) -> Option<usize> {
        self.end_of_start_rest(|c| c.is_space_char(), |c| c.is_space_char())
    }

    fn end_of_start_tag(&self) -> Option<usize> {
        let mut positions = self.char_indices();

        match positions.next() {
            Some((_, c)) if '<' == c => (),
            _ => return None,
        };

        match positions.next() {
            Some((offset, c)) =>
                match c {
                    '?' | '!' | '/' => None,
                    _ => Some(offset),
                },
            None => Some(self.len()),
        }
    }
}

/// Predicates used when parsing an characters in an XML document.
pub trait XmlChar {
    /// Is this a [NameStartChar](http://www.w3.org/TR/xml/#NT-NameStartChar)?
    fn is_name_start_char(self) -> bool;
    /// Is this a [NameChar](http://www.w3.org/TR/xml/#NT-NameChar)?
    fn is_name_char(self) -> bool;
    /// Does this start a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_start_char(self) -> bool;
    /// Is this a component of a [NCName](http://www.w3.org/TR/REC-xml-names/#NT-NCName)?
    fn is_ncname_char(self) -> bool;
    /// Is this an [XML space](http://www.w3.org/TR/xml/#NT-S)?
    fn is_space_char(self) -> bool;
    fn is_decimal_char(self) -> bool;
    fn is_hex_char(self) -> bool;
}

impl XmlChar for char {
    fn is_name_start_char(self) -> bool {
        self == ':' || self.is_ncname_start_char()
    }

    fn is_name_char(self) -> bool {
        self.is_name_start_char() || self.is_ncname_char()
    }

    fn is_ncname_start_char(self) -> bool {
        match self {
            'A'...'Z'                   |
            '_'                         |
            'a'...'z'                   |
            '\u{0000C0}'...'\u{0000D6}' |
            '\u{0000D8}'...'\u{0000F6}' |
            '\u{0000F8}'...'\u{0002FF}' |
            '\u{000370}'...'\u{00037D}' |
            '\u{00037F}'...'\u{001FFF}' |
            '\u{00200C}'...'\u{00200D}' |
            '\u{002070}'...'\u{00218F}' |
            '\u{002C00}'...'\u{002FEF}' |
            '\u{003001}'...'\u{00D7FF}' |
            '\u{00F900}'...'\u{00FDCF}' |
            '\u{00FDF0}'...'\u{00FFFD}' |
            '\u{010000}'...'\u{0EFFFF}' => true,
            _ => false,
        }
    }

    fn is_ncname_char(self) -> bool {
        if self.is_ncname_start_char() { return true; }
        match self {
            '-'                     |
            '.'                     |
            '0'...'9'               |
            '\u{00B7}'              |
            '\u{0300}'...'\u{036F}' |
            '\u{203F}'...'\u{2040}' => true,
            _ => false
        }
    }

    fn is_space_char(self) -> bool {
        match self {
            '\x20' |
            '\x09' |
            '\x0D' |
            '\x0A' => true,
            _ => false,
        }
    }

    fn is_decimal_char(self) -> bool {
        match self {
            '0'...'9' => true,
            _ => false,
        }
    }

    fn is_hex_char(self) -> bool {
        match self {
            '0'...'9' |
            'a'...'f' |
            'A'...'F' => true,
            _ => false,
        }
    }
}

#[cfg(test)]
mod test {
    use super::XmlStr;

    #[test]
    fn end_of_char_data_leading_ampersand() {
        assert_eq!("&".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_less_than() {
        assert_eq!("<".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_leading_cdata_end() {
        assert_eq!("]]>".end_of_char_data(), None);
    }

    #[test]
    fn end_of_char_data_until_ampersand() {
        assert_eq!("hello&world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_less_than() {
        assert_eq!("hello<world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_until_cdata_end() {
        assert_eq!("hello]]>world".end_of_char_data(), Some("hello".len()));
    }

    #[test]
    fn end_of_char_data_includes_right_square() {
        assert_eq!("hello]world".end_of_char_data(), Some("hello]world".len()));
    }

    #[test]
    fn end_of_char_data_includes_multiple_right_squares() {
        assert_eq!("hello]]world".end_of_char_data(), Some("hello]]world".len()));
    }
}
<|endoftext|>


<commit_before>use std::*;
use std::iter::*;
use std::sync::atomic::*;
use types::*;
use config::*;
use player::*;
use field::*;

#[unsafe_no_drop_flag]
struct UctNode {
  wins: AtomicUsize,
  draws: AtomicUsize,
  visits: AtomicUsize,
  pos: Pos,
  child: AtomicPtr<UctNode>,
  sibling: Option<Box<UctNode>>
}

unsafe impl Send for UctNode { }

impl Drop for UctNode {
  fn drop(&mut self) {
    self.clear_child();
  }
}

impl UctNode {
  pub fn new(pos: Pos) -> UctNode {
    UctNode {
      wins: AtomicUsize::new(0),
      draws: AtomicUsize::new(0),
      visits: AtomicUsize::new(0),
      pos: pos,
      child: AtomicPtr::new(ptr::null_mut()),
      sibling: None
    }
  }

  pub fn get_pos(&self) -> Pos {
    self.pos
  }

  pub fn set_pos(&mut self, pos: Pos) {
    self.pos = pos;
  }

  pub fn get_sibling(&mut self) -> Option<Box<UctNode>> {
    mem::replace(&mut self.sibling, None)
  }

  pub fn get_sibling_ref<'a>(&'a self) -> Option<&'a UctNode> {
    self.sibling.as_ref().map(|b| &**b)
  }

  pub fn clear_sibling(&mut self) {
    self.sibling = None;
  }

  pub fn set_sibling(&mut self, sibling: Box<UctNode>) {
    self.sibling = Some(sibling);
  }

  pub fn get_child(&self) -> Option<Box<UctNode>> {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { mem::transmute(ptr) })
    } else {
      None
    }
  }

  pub fn get_child_ref<'a>(&'a self) -> Option<&'a UctNode> {
    let ptr = self.child.load(Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { &*ptr })
    } else {
      None
    }
  }

  pub fn clear_child(&self) {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child(&self, child: Box<UctNode>) {
    let ptr = self.child.swap(unsafe { mem::transmute(child) }, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child_if_empty(&self, child: Box<UctNode>) {
    let child_ptr = unsafe { mem::transmute(child) };
    let ptr = self.child.compare_and_swap(ptr::null_mut(), child_ptr, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(child_ptr) });
    }
  }

  pub fn add_win(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.wins.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_draw(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.draws.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_loose(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
  }
}

pub struct UctRoot {
  node: Option<Box<UctNode>>,
  moves: Vec<Pos>,
  moves_field: Vec<Pos>,
  player: Player,
  moves_count: usize,
  hash: u64
}

impl UctRoot {
  fn clear(&mut self) {
    self.node = None;
    self.moves.clear();
    for i in self.moves_field.iter_mut() {
      *i = 0;
    }
    self.player = Player::Red;
    self.moves_count = 0;
    self.hash = 0;
  }

  fn init(&mut self, field: &Field, player: Player) {
    self.node = Some(Box::new(UctNode::new(0)));
    self.player = player;
    let width = field.width();
    for &start_pos in field.points_seq() {
      wave(width, start_pos, |pos| {
        if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && manhattan(width, start_pos, pos) <= UCT_RADIUS {
          if self.moves_field[pos] == 0 {
            self.moves.push(pos);
          }
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
    }
  }

  fn expand_node(node: &UctNode, moves: &Vec<Pos>) {

  }

  fn update(&mut self, field: &Field, player: Player) {
    if !self.node.is_none() && field.hash_at(self.moves_count) != Some(self.hash) {
      self.clear();
    }
    if self.node.is_none() {
      self.init(field, player);
    } else {
      let points_seq = field.points_seq();
      let moves_count = field.moves_count();
      loop {
        if self.moves_count == moves_count {
          break;
        }
        let next_pos = points_seq[self.moves_count];
        if !field.is_players_point(next_pos, self.player) {
          self.clear();
          self.init(field, player);
          break;
        }
        let mut next = self.node.as_ref().unwrap().get_child();
        while next.is_some() && next.as_ref().unwrap().pos != next_pos {
          next = next.unwrap().get_sibling();
        }
        match next.as_mut() {
          Some(node) => {
            node.clear_sibling();
          },
          None => {
            self.clear();
            self.init(field, player);
            break;
          }
        }
        self.node = next;
        let moves_field = &mut self.moves_field;
        self.moves.retain(|&pos| {
          if field.is_putting_allowed(pos) {
            true
          } else {
            moves_field[pos] = 0;
            false
          }
        });
        let mut added_moves = Vec::new();
        let width = field.width();
        wave(width, next_pos, |pos| {
          if moves_field[pos] != next_pos && field.is_putting_allowed(pos) && manhattan(width, next_pos, pos) <= UCT_RADIUS {
            if moves_field[pos] == 0 {
              added_moves.push(pos);
            }
            moves_field[pos] = next_pos;
            true
          } else {
            false
          }
        });
        UctRoot::expand_node(self.node.as_ref().unwrap(), &added_moves);
        self.moves_count += 1;
        self.player = self.player.next();
      }
    }
  }

  pub fn new(length: Pos) -> UctRoot {
    UctRoot {
      node: None,
      moves: Vec::new(),
      moves_field: repeat(0).take(length).collect(),
      player: Player::Red,
      moves_count: 0,
      hash: 0
    }
  }

  pub fn best_move(&mut self, field: &Field, player: Player) -> Pos {
    self.update(field, player);
    0
  }

  //pub fn estimates
}
<commit_msg>expand_node implemented.<commit_after>use std::*;
use std::iter::*;
use std::sync::atomic::*;
use types::*;
use config::*;
use player::*;
use field::*;

#[unsafe_no_drop_flag]
struct UctNode {
  wins: AtomicUsize,
  draws: AtomicUsize,
  visits: AtomicUsize,
  pos: Pos,
  child: AtomicPtr<UctNode>,
  sibling: Option<Box<UctNode>>
}

unsafe impl Send for UctNode { }

impl Drop for UctNode {
  fn drop(&mut self) {
    self.clear_child();
  }
}

impl UctNode {
  pub fn new(pos: Pos) -> UctNode {
    UctNode {
      wins: AtomicUsize::new(0),
      draws: AtomicUsize::new(0),
      visits: AtomicUsize::new(0),
      pos: pos,
      child: AtomicPtr::new(ptr::null_mut()),
      sibling: None
    }
  }

  pub fn get_pos(&self) -> Pos {
    self.pos
  }

  pub fn set_pos(&mut self, pos: Pos) {
    self.pos = pos;
  }

  pub fn get_sibling(&mut self) -> Option<Box<UctNode>> {
    mem::replace(&mut self.sibling, None)
  }

  pub fn get_sibling_ref<'a>(&'a self) -> Option<&'a UctNode> {
    self.sibling.as_ref().map(|b| &**b)
  }

  pub fn get_sibling_mut<'a>(&'a mut self) -> Option<&'a mut UctNode> {
    self.sibling.as_mut().map(|b| &mut **b)
  }

  pub fn clear_sibling(&mut self) {
    self.sibling = None;
  }

  pub fn set_sibling(&mut self, sibling: Box<UctNode>) {
    self.sibling = Some(sibling);
  }

  pub fn get_child(&self) -> Option<Box<UctNode>> {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { mem::transmute(ptr) })
    } else {
      None
    }
  }

  pub fn get_child_ref<'a>(&'a self) -> Option<&'a UctNode> {
    let ptr = self.child.load(Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { &*ptr })
    } else {
      None
    }
  }

  pub fn get_child_mut<'a>(&'a mut self) -> Option<&'a mut UctNode> {
    let ptr = self.child.load(Ordering::Relaxed);
    if !ptr.is_null() {
      Some(unsafe { &mut *ptr })
    } else {
      None
    }
  }

  pub fn clear_child(&self) {
    let ptr = self.child.swap(ptr::null_mut(), Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child(&self, child: Box<UctNode>) {
    let ptr = self.child.swap(unsafe { mem::transmute(child) }, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(ptr) });
    }
  }

  pub fn set_child_if_empty(&self, child: Box<UctNode>) {
    let child_ptr = unsafe { mem::transmute(child) };
    let ptr = self.child.compare_and_swap(ptr::null_mut(), child_ptr, Ordering::Relaxed);
    if !ptr.is_null() {
      drop::<Box<UctNode>>(unsafe { mem::transmute(child_ptr) });
    }
  }

  pub fn get_visits(&self) -> usize {
    self.visits.load(Ordering::Relaxed)
  }

  pub fn get_wins(&self) -> usize {
    self.wins.load(Ordering::Relaxed)
  }

  pub fn get_draws(&self) -> usize {
    self.draws.load(Ordering::Relaxed)
  }

  pub fn add_win(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.wins.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_draw(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
    self.draws.fetch_add(1, Ordering::Relaxed);
  }

  pub fn add_loose(&self) {
    self.visits.fetch_add(1, Ordering::Relaxed);
  }

  pub fn clear_stats(&self) {
    self.wins.store(0, Ordering::Relaxed);
    self.draws.store(0, Ordering::Relaxed);
    self.visits.store(0, Ordering::Relaxed);
  }
}

pub struct UctRoot {
  node: Option<Box<UctNode>>,
  moves: Vec<Pos>,
  moves_field: Vec<Pos>,
  player: Player,
  moves_count: usize,
  hash: u64
}

impl UctRoot {
  fn clear(&mut self) {
    self.node = None;
    self.moves.clear();
    for i in self.moves_field.iter_mut() {
      *i = 0;
    }
    self.player = Player::Red;
    self.moves_count = 0;
    self.hash = 0;
  }

  fn init(&mut self, field: &Field, player: Player) {
    self.node = Some(Box::new(UctNode::new(0)));
    self.player = player;
    let width = field.width();
    for &start_pos in field.points_seq() {
      wave(width, start_pos, |pos| {
        if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && manhattan(width, start_pos, pos) <= UCT_RADIUS {
          if self.moves_field[pos] == 0 {
            self.moves.push(pos);
          }
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
    }
  }

  fn expand_node(node: &mut UctNode, moves: &Vec<Pos>) {
    if node.get_child_ref().is_none() {
      if node.get_visits() == usize::max_value() {
        node.clear_stats();
      }
    } else {
      let mut next = node.get_child_mut();
      while next.as_ref().unwrap().get_sibling_ref().is_some() {
        UctRoot::expand_node(*next.as_mut().unwrap(), moves);
        next = next.unwrap().get_sibling_mut();
      }
      UctRoot::expand_node(*next.as_mut().unwrap(), moves);
      for &pos in moves {
        next.as_mut().unwrap().set_sibling(Box::new(UctNode::new(pos)));
        next = next.unwrap().get_sibling_mut();
      }
    }
  }

  fn update(&mut self, field: &Field, player: Player) {
    if self.node.is_some() && field.hash_at(self.moves_count) != Some(self.hash) {
      self.clear();
    }
    if self.node.is_none() {
      self.init(field, player);
    } else {
      let points_seq = field.points_seq();
      let moves_count = field.moves_count();
      loop {
        if self.moves_count == moves_count {
          break;
        }
        let next_pos = points_seq[self.moves_count];
        if !field.is_players_point(next_pos, self.player) {
          self.clear();
          self.init(field, player);
          break;
        }
        let mut next = self.node.as_ref().unwrap().get_child();
        while next.is_some() && next.as_ref().unwrap().pos != next_pos {
          next = next.unwrap().get_sibling();
        }
        match next.as_mut() {
          Some(node) => {
            node.clear_sibling();
          },
          None => {
            self.clear();
            self.init(field, player);
            break;
          }
        }
        self.node = next;
        let moves_field = &mut self.moves_field;
        self.moves.retain(|&pos| {
          if field.is_putting_allowed(pos) {
            true
          } else {
            moves_field[pos] = 0;
            false
          }
        });
        let mut added_moves = Vec::new();
        let width = field.width();
        wave(width, next_pos, |pos| {
          if moves_field[pos] != next_pos && field.is_putting_allowed(pos) && manhattan(width, next_pos, pos) <= UCT_RADIUS {
            if moves_field[pos] == 0 {
              added_moves.push(pos);
            }
            moves_field[pos] = next_pos;
            true
          } else {
            false
          }
        });
        UctRoot::expand_node(self.node.as_mut().unwrap(), &added_moves);
        self.moves_count += 1;
        self.player = self.player.next();
      }
    }
  }

  pub fn new(length: Pos) -> UctRoot {
    UctRoot {
      node: None,
      moves: Vec::new(),
      moves_field: repeat(0).take(length).collect(),
      player: Player::Red,
      moves_count: 0,
      hash: 0
    }
  }

  pub fn best_move(&mut self, field: &Field, player: Player) -> Pos {
    self.update(field, player);
    0
  }

  //pub fn estimates
}
<|endoftext|>


<commit_before>use std::io;
use std::fmt;
use std::error;
use std::vec::Vec;
use byteorder;
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};

#[derive(Debug)]
pub enum Error {
	Io(byteorder::Error),
	InvalidValue,
	InvalidType
}

impl From<byteorder::Error> for Error {
	fn from(err: byteorder::Error) -> Error { Error::Io(err) }
}

impl From<Error> for byteorder::Error {
	fn from(err: Error) -> byteorder::Error {
		match err {
			Error::Io(err) => err,
			Error::InvalidValue => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid value")),
			Error::InvalidType => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid type")),
		}
	}
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
	        match *self {
				Error::InvalidValue => write!(f, "Invalid value."),
				Error::InvalidType => write!(f, "Invalid type."),
				Error::Io(ref err) => err.fmt(f),
			}
	}
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidValue => "Invalid value.",
            Error::InvalidType => "Invalid type.",
            Error::Io(ref err) => error::Error::description(err),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::InvalidValue => None,
            Error::InvalidType => None,
            Error::Io(ref err) => err.cause(),
        }
    }
}

pub struct XdrReader<'a> {
	reader : io::Cursor<&'a [u8]>
}

pub struct XdrWriter {
	writer : io::Cursor<Vec<u8>>
}

impl XdrWriter {
	pub fn new() -> XdrWriter {
		let v : Vec<u8>= Vec::new();
		XdrWriter{ writer: io::Cursor::new(v)}
	}

	pub fn get_buffer(self) -> Vec<u8> {
		self.writer.into_inner()
	}

	pub fn pack<T:XdrPrimitive>(&mut self, x:T) {
		XdrPrimitive::write_to_xdr(self, x)
	}

}
impl<'a> XdrReader<'a> {
	pub fn new(x:&'a Vec<u8>) -> XdrReader<'a> {
		XdrReader{ reader : io::Cursor::new(x.as_slice()) }
	}

	pub fn from_array(x: &'a [u8]) -> XdrReader<'a> {
		XdrReader{ reader: io::Cursor::new(x) }
	}

	pub fn unpack<T: XdrPrimitive>(&mut self) -> Result<T,Error> {
		T::read_from_xdr(self)
	}
}

pub trait XdrPrimitive {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>;
	fn write_to_xdr(x: &mut XdrWriter, v: Self);
}

impl<T:XdrPrimitive> XdrPrimitive for Vec<T> {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>{
		let count = x.unpack::<u32>().unwrap() as usize;
		let mut result : Vec<T> = Vec::with_capacity(count);

		for _ in 0..count {
			result.push(x.unpack::<T>().unwrap());
		};
		Ok(result)
	}
	fn write_to_xdr(x: &mut XdrWriter, v: Self) {
		x.pack( v.len() as u32 );
		for t in v {
			x.pack(t);
		};
	}
}

impl XdrPrimitive for u32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u32, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u16, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for u8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u8, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for i8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i8, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i16, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i32, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for i64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i64, Error>{
		match x.reader.read_i64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i64::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u64, Error>{
		match x.reader.read_u64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u64::<byteorder::BigEndian>(v).unwrap();
	}

}

impl XdrPrimitive for f32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f32, Error>{
		match x.reader.read_f32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for f64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f64, Error>{
		match x.reader.read_f64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f64::<byteorder::BigEndian>(v).unwrap();
	}
}

impl XdrPrimitive for bool {
	fn read_from_xdr(x: &mut XdrReader) -> Result<bool, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(0) => Ok(false),
			Ok(1) => Ok(true),
			Ok(_) => Err(Error::InvalidValue),
			Err(v) => Err(Error::Io(v))
		}
	}

	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		match v {
			true => x.writer.write_u32::<byteorder::BigEndian>(1).unwrap(),
			false => x.writer.write_u32::<byteorder::BigEndian>(0).unwrap(),
		}
	}
}
<commit_msg>add pack_/unpack_array for packing/unpacking fixed length arrays to xdr<commit_after>use std::io;
use std::fmt;
use std::error;
use std::vec::Vec;
use byteorder;
use byteorder::{BigEndian,ReadBytesExt,WriteBytesExt};

#[derive(Debug)]
pub enum Error {
	Io(byteorder::Error),
	InvalidValue,
	InvalidType
}

impl From<byteorder::Error> for Error {
	fn from(err: byteorder::Error) -> Error { Error::Io(err) }
}

impl From<Error> for byteorder::Error {
	fn from(err: Error) -> byteorder::Error {
		match err {
			Error::Io(err) => err,
			Error::InvalidValue => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid value")),
			Error::InvalidType => byteorder::Error::Io(io::Error::new(io::ErrorKind::Other, "Invalid type")),
		}
	}
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
	        match *self {
				Error::InvalidValue => write!(f, "Invalid value."),
				Error::InvalidType => write!(f, "Invalid type."),
				Error::Io(ref err) => err.fmt(f),
			}
	}
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::InvalidValue => "Invalid value.",
            Error::InvalidType => "Invalid type.",
            Error::Io(ref err) => error::Error::description(err),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::InvalidValue => None,
            Error::InvalidType => None,
            Error::Io(ref err) => err.cause(),
        }
    }
}

pub struct XdrReader<'a> {
	reader : io::Cursor<&'a [u8]>
}

pub struct XdrWriter {
	writer : io::Cursor<Vec<u8>>
}

impl XdrWriter {
	pub fn new() -> XdrWriter {
		let v : Vec<u8>= Vec::new();
		XdrWriter{ writer: io::Cursor::new(v)}
	}

	pub fn get_buffer(self) -> Vec<u8> {
		self.writer.into_inner()
	}

	pub fn pack<T:XdrPrimitive>(&mut self, x:T) {
		XdrPrimitive::write_to_xdr(self, x)
	}

	pub fn pack_array<T:XdrPrimitive>(&mut self, x:Vec<T>) {
		for t in x {
			XdrPrimitive::write_to_xdr(self,t);
		};
	}

}
impl<'a> XdrReader<'a> {
	pub fn new(x:&'a Vec<u8>) -> XdrReader<'a> {
		XdrReader{ reader : io::Cursor::new(x.as_slice()) }
	}

	pub fn from_array(x: &'a [u8]) -> XdrReader<'a> {
		XdrReader{ reader: io::Cursor::new(x) }
	}

	pub fn unpack<T: XdrPrimitive>(&mut self) -> Result<T,Error> {
		T::read_from_xdr(self)
	}

	pub fn unpack_array<T:XdrPrimitive>(&mut self, n : usize) -> Result<Vec<T>,Error> {
		let mut result : Vec<T> = Vec::with_capacity(n);

		for _ in 0..n {
			let t =  T::read_from_xdr(self).unwrap();
			result.push(t)
		};
		Ok(result)
	}
}

pub trait XdrPrimitive {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>;
	fn write_to_xdr(x: &mut XdrWriter, v: Self);
}

impl<T:XdrPrimitive> XdrPrimitive for Vec<T> {
	fn read_from_xdr(x: &mut XdrReader) -> Result<Self, Error>{
		let count = x.unpack::<u32>().unwrap() as usize;
		let mut result : Vec<T> = Vec::with_capacity(count);

		for _ in 0..count {
			result.push(x.unpack::<T>().unwrap());
		};
		Ok(result)
	}
	fn write_to_xdr(x: &mut XdrWriter, v: Self) {
		x.pack( v.len() as u32 );
		for t in v {
			x.pack(t);
		};
	}
}

impl XdrPrimitive for u32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u32, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u16, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for u8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u8, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as u8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u32::<byteorder::BigEndian>(v as u32).unwrap();
	}
}
impl XdrPrimitive for i8 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i8, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i8),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i16 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i16, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v as i16),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v as i32).unwrap();
	}
}
impl XdrPrimitive for i32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i32, Error>{
		match x.reader.read_i32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for i64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<i64, Error>{
		match x.reader.read_i64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_i64::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for u64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<u64, Error>{
		match x.reader.read_u64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_u64::<byteorder::BigEndian>(v).unwrap();
	}

}

impl XdrPrimitive for f32 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f32, Error>{
		match x.reader.read_f32::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f32::<byteorder::BigEndian>(v).unwrap();
	}
}
impl XdrPrimitive for f64 {
	fn read_from_xdr(x: &mut XdrReader) -> Result<f64, Error>{
		match x.reader.read_f64::<byteorder::BigEndian>() {
			Ok(v) => Ok(v),
			Err(v) => Err(Error::Io(v))
		}

	}
	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		x.writer.write_f64::<byteorder::BigEndian>(v).unwrap();
	}
}

impl XdrPrimitive for bool {
	fn read_from_xdr(x: &mut XdrReader) -> Result<bool, Error>{
		match x.reader.read_u32::<byteorder::BigEndian>() {
			Ok(0) => Ok(false),
			Ok(1) => Ok(true),
			Ok(_) => Err(Error::InvalidValue),
			Err(v) => Err(Error::Io(v))
		}
	}

	fn write_to_xdr(x: &mut XdrWriter, v:Self) {
		match v {
			true => x.writer.write_u32::<byteorder::BigEndian>(1).unwrap(),
			false => x.writer.write_u32::<byteorder::BigEndian>(0).unwrap(),
		}
	}
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

#![link(name="xcb",
       vers="0.3",
       uuid="ef466d26-0620-4f5f-a1d2-1bb9c628e101",
       url= "https://github.com/Aatch/rust-xcb")]

#![license = "MIT"]
#![crate_type="lib"]
#![feature(globs)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]
extern crate libc;

pub mod ffi {
    pub mod xproto;
    pub mod base;

    pub mod bigreq;
    pub mod composite;
    pub mod damage;
    pub mod dpms;
    pub mod dri2;

    //pub mod ge; not sure about this one...

    pub mod glx;
    pub mod randr;
    pub mod record;
    pub mod render;
    pub mod screensaver;
    pub mod shape;
    pub mod shm;
    pub mod sync;
    pub mod xc_misc;
    pub mod xevie;
    pub mod xf86dri;
    //pub mod xf86vidmode; Same with this one...
    pub mod xfixes;
    pub mod xinerama;
    pub mod xinput;
    //pub mod xkb;
    pub mod xprint;

    #[cfg(enable_xselinux)]
    pub mod xselinux;
    pub mod xtest;
    pub mod xv;
    pub mod xvmc;
}

pub mod base;
pub mod macro;

pub mod xproto;

pub mod xinerama;

pub mod bigreq;
pub mod composite;
pub mod xfixes;
pub mod render;
pub mod shape;
/*
pub mod damage;
pub mod dpms;
pub mod dri2;
//pub mod ge; not sure about this one...

pub mod glx;
pub mod randr;
pub mod record;
pub mod screensaver;
pub mod shm;
pub mod sync;
pub mod xc_misc;
pub mod xevie;
pub mod xf86dri;
//pub mod xf86vidmode; Same with this one...
pub mod xinput;
//pub mod xkb;
pub mod xprint;

#[cfg(enable_xselinux)]
pub mod xselinux;
pub mod xtest;
pub mod xv;
pub mod xvmc;
*/
<commit_msg>Removed the export of wrapper modules that don't work yet. ffi compiles fine.<commit_after>/*
Copyright (C) 2013 James Miller <james@aatch.net>

Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

#![link(name="xcb",
       vers="0.3",
       uuid="ef466d26-0620-4f5f-a1d2-1bb9c628e101",
       url= "https://github.com/Aatch/rust-xcb")]

#![license = "MIT"]
#![crate_type="lib"]
#![feature(globs)]
#![feature(macro_rules)]
#![feature(unsafe_destructor)]
extern crate libc;

pub mod ffi {
    pub mod xproto;
    pub mod base;

    pub mod bigreq;
    pub mod composite;
    pub mod damage;
    pub mod dpms;
    pub mod dri2;

    //pub mod ge; not sure about this one...

    pub mod glx;
    pub mod randr;
    pub mod record;
    pub mod render;
    pub mod screensaver;
    pub mod shape;
    pub mod shm;
    pub mod sync;
    pub mod xc_misc;
    pub mod xevie;
    pub mod xf86dri;
    //pub mod xf86vidmode; Same with this one...
    pub mod xfixes;
    pub mod xinerama;
    pub mod xinput;
    //pub mod xkb;
    pub mod xprint;

    #[cfg(enable_xselinux)]
    pub mod xselinux;
    pub mod xtest;
    pub mod xv;
    pub mod xvmc;
}

/*
pub mod base;
pub mod macro;

pub mod xproto;

pub mod xinerama;

pub mod bigreq;
pub mod composite;
pub mod xfixes;
pub mod render;
pub mod shape;

pub mod damage;
pub mod dpms;
pub mod dri2;
//pub mod ge; not sure about this one...

pub mod glx;
pub mod randr;
pub mod record;
pub mod screensaver;
pub mod shm;
pub mod sync;
pub mod xc_misc;
pub mod xevie;
pub mod xf86dri;
//pub mod xf86vidmode; Same with this one...
pub mod xinput;
//pub mod xkb;
pub mod xprint;

#[cfg(enable_xselinux)]
pub mod xselinux;
pub mod xtest;
pub mod xv;
pub mod xvmc;
*/
<|endoftext|>


<commit_before>#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
#![doc(html_root_url = "https://docs.rs/amq-protocol-tcp/6.0.0-alpha6/")]

//! # AMQP URI TCP connection handling
//!
//! amq-protocol-tcp is a library aiming at providing tools to help
//! connecting to an AMQP URI

use amq_protocol_uri::{AMQPScheme, AMQPUri};
use log::trace;

/// Re-export TcpStream
pub use tcp_stream::{HandshakeResult, Identity, TcpStream};

/// Trait providing a method to connect to a TcpStream
pub trait AMQPUriTcpExt {
    /// connect to a TcpStream
    fn connect(&self) -> HandshakeResult
    where
        Self: Sized,
    {
        self.connect_with_identity(None)
    }

    /// connect to a TcpStream with the given identity
    fn connect_with_identity(&self, identity: Option<Identity<'_, '_>>) -> HandshakeResult;
}

impl AMQPUriTcpExt for AMQPUri {
    fn connect_with_identity(&self, identity: Option<Identity<'_, '_>>) -> HandshakeResult {
        let uri = format!("{}:{}", self.authority.host, self.authority.port);
        trace!("Connecting to {}", uri);
        let stream = TcpStream::connect(uri)?;

        match self.scheme {
            AMQPScheme::AMQP => Ok(stream),
            AMQPScheme::AMQPS => stream.into_tls(&self.authority.host, identity),
        }
    }
}
<commit_msg>tcp: reexport HandshakeError<commit_after>#![deny(missing_docs)]
#![warn(rust_2018_idioms)]
#![doc(html_root_url = "https://docs.rs/amq-protocol-tcp/6.0.0-alpha6/")]

//! # AMQP URI TCP connection handling
//!
//! amq-protocol-tcp is a library aiming at providing tools to help
//! connecting to an AMQP URI

use amq_protocol_uri::{AMQPScheme, AMQPUri};
use log::trace;

/// Re-export TcpStream
pub use tcp_stream::{HandshakeError, HandshakeResult, Identity, TcpStream};

/// Trait providing a method to connect to a TcpStream
pub trait AMQPUriTcpExt {
    /// connect to a TcpStream
    fn connect(&self) -> HandshakeResult
    where
        Self: Sized,
    {
        self.connect_with_identity(None)
    }

    /// connect to a TcpStream with the given identity
    fn connect_with_identity(&self, identity: Option<Identity<'_, '_>>) -> HandshakeResult;
}

impl AMQPUriTcpExt for AMQPUri {
    fn connect_with_identity(&self, identity: Option<Identity<'_, '_>>) -> HandshakeResult {
        let uri = format!("{}:{}", self.authority.host, self.authority.port);
        trace!("Connecting to {}", uri);
        let stream = TcpStream::connect(uri)?;

        match self.scheme {
            AMQPScheme::AMQP => Ok(stream),
            AMQPScheme::AMQPS => stream.into_tls(&self.authority.host, identity),
        }
    }
}
<|endoftext|>


<commit_before>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/
use game::{Move, Position, Side};
use nimstring;
use std::collections::HashMap;
use std::isize;

// Evaluate a position given a set of moves to consider
fn eval_moves(pos: &mut Position, moves: &Vec<Move>,
              cache: &mut HashMap<usize, (isize, Move)>) -> (isize, Option<Move>) {
    if moves.is_empty() {
        return (0, None);
    }
    let mut value = isize::MIN;
    let mut best_move = moves[0];
    for &m in moves {
        let outcome = pos.make_move(m.x, m.y, m.side);
        let sign = if outcome.coins_captured > 0 { 1 } else { -1 };
        let (next_val, _) = eval_cache(pos, cache);
        let sub_val = (outcome.coins_captured as isize) + sign * next_val;
        pos.undo_move(m.x, m.y, m.side);
        if sub_val > value {
            value = sub_val;
            best_move = m;
        }
    }
    cache.insert(pos.zhash(), (value, best_move));
    (value, Some(best_move))
}

// Given a loony position and the capture, find the corresponding double-dealing move
fn find_ddeal_move(pos: &Position, capture: Move) -> Move {
    // (capture.x, capture.y) might be the valency-1 coin or the valency-2 one
    let (v2_x, v2_y, excl_side) = if pos.valency(capture.x, capture.y) == 1 {
        let (x, y) = pos.offset(capture.x, capture.y, capture.side).unwrap();
        (x, y, capture.side.opposite())
    } else {
        (capture.x, capture.y, capture.side)
    };

    if pos.valency(v2_x, v2_y) != 2 {
        panic!("Expected ({},{}) to have valency 2, found {} in {}",
               v2_x, v2_y, pos.valency(v2_x, v2_y), pos);
    }

    for s in Side::all_except(excl_side) {
        if pos.is_legal_move(v2_x, v2_y, s) {
            return Move{x: v2_x, y: v2_y, side: s};
        }
    }

    panic!("Could not find double-dealing move corresponding to {} in {}", capture, pos);
}

// Determine what moves deserve consideration in a given position
fn moves_to_consider(pos: &mut Position) -> Vec<Move> {
    let legal_moves = pos.legal_moves();

    // If there are any captures which don't affect looniness, just go ahead and make those
    let is_loony = nimstring::is_loony(pos);
    let mut capture: Option<Move> = None;
    for &m in &legal_moves {
        let captures = pos.would_capture(m.x, m.y, m.side);
        if captures == 0 {
            continue;
        }
        capture = Some(m);
        if !is_loony || nimstring::would_be_loony(pos, m.x, m.y, m.side) {
            return vec!(m);
        }
    }

    // Consider only capturing all and double-dealing in the loony case
    // TODO: Use other canonical play results to further reduce the set of moves considered
    if is_loony {
        let capture = capture.unwrap();
        let ddeal_move = find_ddeal_move(pos, capture);
        vec!(capture, ddeal_move)
    } else {
        legal_moves
    }
}

fn eval_cache(pos: &mut Position, cache: &mut HashMap<usize, (isize, Move)>) -> (isize, Option<Move>) {
    if let Some(&(val, best_move)) = cache.get(&pos.zhash()) {
        return (val, Some(best_move));
    }

    let moves = moves_to_consider(pos);
    eval_moves(pos, &moves, cache)
}

// Calculate the value function of a given position and a move which achieves that value
pub fn eval(pos: &Position) -> (isize, Option<Move>) {
    let mut cache = HashMap::new();
    let mut pos = pos.clone();
    eval_cache(&mut pos, &mut cache)
}

#[cfg(test)]
mod test {
    use eval::*;
    use examples::*;

    #[test]
    fn eval_chain() {
        for i in 1..10 {
            let mut chain = make_chain(i);
            let (val, _) = eval(&mut chain);
            let expected_val = -(i as isize);
            assert_eq!(expected_val, val, "Closed {}-chain", i);
            chain.make_move(0, 0, Side::Left);
            let (val, best_move) = eval(&mut chain);
            assert_eq!(-expected_val, val, "Opened {}-chain", i);
            assert!(chain.moves_equivalent(best_move.unwrap(), Move{x: 0, y: 0, side: Side::Right}));
        }
    }

    #[test]
    fn eval_double_chain() {
        let (val, _) = eval(&mut double_chain(1));
        assert_eq!(0, val);
        for i in 2..10 {
            let mut pos = double_chain(i);
            let (val, _) = eval(&mut pos);
            let expected_val = 4 - 2*(i as isize);
            assert_eq!(expected_val, val, "Evaluation of double chain length {}", i);
            pos.make_move(0, 0, Side::Left);
            let (val, best_move) = eval(&mut pos);
            assert_eq!(-expected_val, val, "Evaluation of opened double chain length {}", i);
            assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 0, y: 0, side: Side::Right}));
        }
    }

    #[test]
    fn eval_multi_chains() {
        let mut pos = multi_chains(3, 4);

        let (val, _) = eval(&mut pos);
        assert_eq!(-2, val);
        pos.make_move(0, 0, Side::Left);

        let (val, best_move) = eval(&mut pos);
        assert_eq!(2, val);
        assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 0, y: 0, side: Side::Right}));
        pos.make_move(0, 0, Side::Right);

        let (val, best_move) = eval(&mut pos);
        assert_eq!(1, val);
        assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 1, y: 0, side: Side::Right}));
        pos.make_move(1, 0, Side::Right);

        let (val, best_move) = eval(&mut pos);
        assert_eq!(0, val);
        assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 2, y: 0, side: Side::Right}));
        pos.make_move(2, 0, Side::Right);

        let (val, _) = eval(&mut pos);
        assert_eq!(-1, val);
    }

    #[test]
    fn eval_double_loop() {
        for i in 2..8 {
            let mut pos = double_loop(i);
            let (val, _) = eval(&mut pos);
            let expected_val = 8 - 4*(i as isize);
            assert_eq!(expected_val, val, "Evaluation of double loop width {}", i);
            pos.make_move(0, 0, Side::Right);
            let (val, _) = eval(&mut pos);
            assert_eq!(-expected_val, val, "Evaluation of opened double loop width {}", i);
        }
    }

    #[test]
    fn eval_ex3p1() {
        let mut pos = ex3p1();
        let (val, best_move) = eval(&mut pos);
        let best_move = best_move.unwrap();
        assert_eq!(3, val);
        assert!(pos.moves_equivalent(best_move, Move{x: 2, y: 1, side: Side::Bottom}));

        pos.make_move(2, 1, Side::Bottom);
        let (val, best_move) = eval(&mut pos);
        let best_move = best_move.unwrap();
        assert_eq!(-3, val);
        assert!(pos.moves_equivalent(best_move, Move{x: 0, y: 0, side: Side::Bottom}));

        pos.make_move(0, 0, Side::Bottom);
        let (val, _) = eval(&mut pos);
        assert_eq!(3, val);

        pos.undo_move(0, 0, Side::Bottom);
        pos.make_move(0, 2, Side::Left);
        let (val, _) = eval(&mut pos);
        assert_eq!(5, val);
    }

    #[test]
    fn eval_ex3p12() {
        let mut pos = ex3p12();
        let (val, best_move) = eval(&mut pos);
        let best_move = best_move.unwrap();
        let expected_val = 9;
        assert_eq!(expected_val, val);
        assert!(pos.moves_equivalent(best_move, Move{x: 4, y: 0, side: Side::Bottom}));

        pos.make_move(4, 0, Side::Bottom);
        let (val, _) = eval(&mut pos);
        assert_eq!(-expected_val, val);
    }

//    #[test]
//    fn eval_p50() {
//        let mut pos = p50();
//        let (val, best_move) = eval(&mut pos);
//        let best_move = best_move.unwrap();
//        assert_eq!(4, val);
//        assert!(pos.moves_equivalent(best_move, Move{x: 0, y: 3, side: Side::Right})
//                || pos.moves_equivalent(best_move, Move{x: 0, y: 3, side: Side::Bottom})
//                || pos.moves_equivalent(best_move, Move{x: 0, y: 3, side: Side::Left}));
//    }
}
<commit_msg>Add generative eval tests<commit_after>/*
    Copyright 2017 Andrew Medworth <github@medworth.org.uk>

    This file is part of Dots-and-Boxes Engine.

    Dots-and-Boxes Engine is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Dots-and-Boxes Engine is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with Dots-and-Boxes Engine.  If not, see <http://www.gnu.org/licenses/>.
*/
use game::{Move, Position, Side};
use nimstring;
use std::collections::HashMap;
use std::isize;

// Evaluate a position given a set of moves to consider
fn eval_moves(pos: &mut Position, moves: &Vec<Move>,
              cache: &mut HashMap<usize, (isize, Move)>) -> (isize, Option<Move>) {
    if moves.is_empty() {
        return (0, None);
    }
    let mut value = isize::MIN;
    let mut best_move = moves[0];
    for &m in moves {
        let outcome = pos.make_move(m.x, m.y, m.side);
        let sign = if outcome.coins_captured > 0 { 1 } else { -1 };
        let (next_val, _) = eval_cache(pos, cache);
        let sub_val = (outcome.coins_captured as isize) + sign * next_val;
        pos.undo_move(m.x, m.y, m.side);
        if sub_val > value {
            value = sub_val;
            best_move = m;
        }
    }
    cache.insert(pos.zhash(), (value, best_move));
    (value, Some(best_move))
}

// Given a loony position and the capture, find the corresponding double-dealing move
fn find_ddeal_move(pos: &Position, capture: Move) -> Move {
    // (capture.x, capture.y) might be the valency-1 coin or the valency-2 one
    let (v2_x, v2_y, excl_side) = if pos.valency(capture.x, capture.y) == 1 {
        let (x, y) = pos.offset(capture.x, capture.y, capture.side).unwrap();
        (x, y, capture.side.opposite())
    } else {
        (capture.x, capture.y, capture.side)
    };

    if pos.valency(v2_x, v2_y) != 2 {
        panic!("Expected ({},{}) to have valency 2, found {} in {}",
               v2_x, v2_y, pos.valency(v2_x, v2_y), pos);
    }

    for s in Side::all_except(excl_side) {
        if pos.is_legal_move(v2_x, v2_y, s) {
            return Move{x: v2_x, y: v2_y, side: s};
        }
    }

    panic!("Could not find double-dealing move corresponding to {} in {}", capture, pos);
}

// Determine what moves deserve consideration in a given position
fn moves_to_consider(pos: &mut Position) -> Vec<Move> {
    let legal_moves = pos.legal_moves();

    // If there are any captures which don't affect looniness, just go ahead and make those
    let is_loony = nimstring::is_loony(pos);
    let mut capture: Option<Move> = None;
    for &m in &legal_moves {
        let captures = pos.would_capture(m.x, m.y, m.side);
        if captures == 0 {
            continue;
        }
        capture = Some(m);
        if !is_loony || nimstring::would_be_loony(pos, m.x, m.y, m.side) {
            return vec!(m);
        }
    }

    // Consider only capturing all and double-dealing in the loony case
    // TODO: Use other canonical play results to further reduce the set of moves considered
    if is_loony {
        let capture = capture.unwrap();
        let ddeal_move = find_ddeal_move(pos, capture);
        vec!(capture, ddeal_move)
    } else {
        legal_moves
    }
}

fn eval_cache(pos: &mut Position, cache: &mut HashMap<usize, (isize, Move)>) -> (isize, Option<Move>) {
    if let Some(&(val, best_move)) = cache.get(&pos.zhash()) {
        return (val, Some(best_move));
    }

    let moves = moves_to_consider(pos);
    eval_moves(pos, &moves, cache)
}

// Calculate the value function of a given position and a move which achieves that value
pub fn eval(pos: &Position) -> (isize, Option<Move>) {
    let mut cache = HashMap::new();
    let mut pos = pos.clone();
    eval_cache(&mut pos, &mut cache)
}

#[cfg(test)]
mod test {
    use eval::*;
    use examples::*;

    use rand::{Rng, SeedableRng, StdRng};
    use std::cmp;
    use time;

    #[test]
    fn eval_chain() {
        for i in 1..10 {
            let mut chain = make_chain(i);
            let (val, _) = eval(&mut chain);
            let expected_val = -(i as isize);
            assert_eq!(expected_val, val, "Closed {}-chain", i);
            chain.make_move(0, 0, Side::Left);
            let (val, best_move) = eval(&mut chain);
            assert_eq!(-expected_val, val, "Opened {}-chain", i);
            assert!(chain.moves_equivalent(best_move.unwrap(), Move{x: 0, y: 0, side: Side::Right}));
        }
    }

    #[test]
    fn eval_double_chain() {
        let (val, _) = eval(&mut double_chain(1));
        assert_eq!(0, val);
        for i in 2..10 {
            let mut pos = double_chain(i);
            let (val, _) = eval(&mut pos);
            let expected_val = 4 - 2*(i as isize);
            assert_eq!(expected_val, val, "Evaluation of double chain length {}", i);
            pos.make_move(0, 0, Side::Left);
            let (val, best_move) = eval(&mut pos);
            assert_eq!(-expected_val, val, "Evaluation of opened double chain length {}", i);
            assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 0, y: 0, side: Side::Right}));
        }
    }

    #[test]
    fn eval_multi_chains() {
        let mut pos = multi_chains(3, 4);

        let (val, _) = eval(&mut pos);
        assert_eq!(-2, val);
        pos.make_move(0, 0, Side::Left);

        let (val, best_move) = eval(&mut pos);
        assert_eq!(2, val);
        assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 0, y: 0, side: Side::Right}));
        pos.make_move(0, 0, Side::Right);

        let (val, best_move) = eval(&mut pos);
        assert_eq!(1, val);
        assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 1, y: 0, side: Side::Right}));
        pos.make_move(1, 0, Side::Right);

        let (val, best_move) = eval(&mut pos);
        assert_eq!(0, val);
        assert!(pos.moves_equivalent(best_move.unwrap(), Move{x: 2, y: 0, side: Side::Right}));
        pos.make_move(2, 0, Side::Right);

        let (val, _) = eval(&mut pos);
        assert_eq!(-1, val);
    }

    #[test]
    fn eval_double_loop() {
        for i in 2..8 {
            let mut pos = double_loop(i);
            let (val, _) = eval(&mut pos);
            let expected_val = 8 - 4*(i as isize);
            assert_eq!(expected_val, val, "Evaluation of double loop width {}", i);
            pos.make_move(0, 0, Side::Right);
            let (val, _) = eval(&mut pos);
            assert_eq!(-expected_val, val, "Evaluation of opened double loop width {}", i);
        }
    }

    #[test]
    fn eval_ex3p1() {
        let mut pos = ex3p1();
        let (val, best_move) = eval(&mut pos);
        let best_move = best_move.unwrap();
        assert_eq!(3, val);
        assert!(pos.moves_equivalent(best_move, Move{x: 2, y: 1, side: Side::Bottom}));

        pos.make_move(2, 1, Side::Bottom);
        let (val, best_move) = eval(&mut pos);
        let best_move = best_move.unwrap();
        assert_eq!(-3, val);
        assert!(pos.moves_equivalent(best_move, Move{x: 0, y: 0, side: Side::Bottom}));

        pos.make_move(0, 0, Side::Bottom);
        let (val, _) = eval(&mut pos);
        assert_eq!(3, val);

        pos.undo_move(0, 0, Side::Bottom);
        pos.make_move(0, 2, Side::Left);
        let (val, _) = eval(&mut pos);
        assert_eq!(5, val);
    }

    #[test]
    fn eval_ex3p12() {
        let mut pos = ex3p12();
        let (val, best_move) = eval(&mut pos);
        let best_move = best_move.unwrap();
        let expected_val = 9;
        assert_eq!(expected_val, val);
        assert!(pos.moves_equivalent(best_move, Move{x: 4, y: 0, side: Side::Bottom}));

        pos.make_move(4, 0, Side::Bottom);
        let (val, _) = eval(&mut pos);
        assert_eq!(-expected_val, val);
    }

    // For use in generative tests
    fn make_random_pos(r: &mut StdRng) -> Position {
        let width: usize = r.gen_range(1, 3);
        let height: usize = r.gen_range(1, 3);
        let mut pos = Position::new_game(width, height);
        let mut moves = pos.legal_moves();
        r.shuffle(moves.as_mut_slice());
        let move_count = r.gen_range(0, moves.len() + 1);
        for i in 0..move_count {
            let m = moves[i];
            pos.make_move(m.x, m.y, m.side);
        }
        pos
    }

    // Dumb evaluation algorithm to compare to optimised one
    fn naive_minimax(pos: &mut Position) -> isize {
        let moves = pos.legal_moves();
        if moves.is_empty() {
            return 0;
        }
        let mut result = isize::MIN;
        for m in &moves {
            let outcome = pos.make_move(m.x, m.y, m.side);
            let captures = outcome.coins_captured as isize;
            let m_val = if captures > 0 {
                captures + naive_minimax(pos)
            } else {
                -naive_minimax(pos)
            };
            pos.undo_move(m.x, m.y, m.side);
            result = cmp::max(result, m_val);
        }
        result
    }

    #[test]
    fn matches_naive_minimax() {
        let test_time_s = 10 as f64;
        let seed: &[_] = &[1234];
        let mut r: StdRng = SeedableRng::from_seed(seed);
        let mut i = 0;
        let start_time = time::precise_time_s();
        loop {
            let mut pos = make_random_pos(&mut r);
            let expected_val = naive_minimax(&mut pos);
            let (val, best_move) = eval(&mut pos);
            assert_eq!(expected_val, val, "Position {} value matches naive minimax", i);

            if !pos.is_end_of_game() {
                let best_move = best_move.unwrap();
                let outcome = pos.make_move(best_move.x, best_move.y, best_move.side);
                let captures = outcome.coins_captured as isize;
                let (next_val, _) = eval(&mut pos);
                let expected_next_val = if captures > 0 {
                    expected_val - captures
                } else {
                    -expected_val
                };
                assert_eq!(expected_next_val, next_val);
            }

            let elapsed = time::precise_time_s() - start_time;
            if elapsed >= test_time_s {
                break;
            }
            i += 1;
        }
    }

    // TODO: Test that rotations and reflections do not affect the evaluation

//    #[test]
//    fn eval_p50() {
//        let mut pos = p50();
//        let (val, best_move) = eval(&mut pos);
//        let best_move = best_move.unwrap();
//        assert_eq!(4, val);
//        assert!(pos.moves_equivalent(best_move, Move{x: 0, y: 3, side: Side::Right})
//                || pos.moves_equivalent(best_move, Move{x: 0, y: 3, side: Side::Bottom})
//                || pos.moves_equivalent(best_move, Move{x: 0, y: 3, side: Side::Left}));
//    }
}
<|endoftext|>


<commit_before>use std::convert::AsRef;
use std::fs::{read_dir, metadata};
use std::path::{Path, PathBuf};
use std::collections::BTreeMap;
use std::str::FromStr;

use cronparse::{CrontabFile, CrontabFileError, CrontabFileErrorKind};
use cronparse::crontab::{EnvVarEntry, CrontabEntry};

use generate::generate_systemd_units;

pub fn process_crontab_dir<T: FromStr, D: AsRef<Path>>(srcdir: &str, dstdir: D) where CrontabEntry: From<T>, CrontabFileError: From<<T as FromStr>::Err> {
    let files = read_dir(srcdir).and_then(|fs| fs.map(|r| r.map(|p| p.path()))
                                       .filter(|r| r.as_ref().map(|p| metadata(p).map(|m| m.is_file()).unwrap_or(true)).unwrap_or(true))
                                       .collect::<Result<Vec<PathBuf>, _>>());
    match files {
        Err(err) => warn!("error processing directory {}: {}", srcdir, err),
        Ok(files) => for file in files {
            process_crontab_file::<T, _, _>(file, dstdir.as_ref());
        }
    }
}

pub fn process_crontab_file<T: FromStr, P: AsRef<Path>, D: AsRef<Path>>(path: P, dstdir: D) where CrontabEntry: From<T>, CrontabFileError: From<<T as FromStr>::Err> {
    CrontabFile::<T>::new(path.as_ref()).map(|crontab| {
        let mut env = BTreeMap::new();
        for entry in crontab {
            match entry {
                Ok(CrontabEntry::EnvVar(EnvVarEntry(name, value))) => { env.insert(name, value); },
                Ok(data) => match generate_systemd_units(data, &env, path.as_ref(), dstdir.as_ref()) {
                    Ok(_) => (),
                    Err(err) => warn!("error generating unit from {}: {}", path.as_ref().display(), err)
                },
                Err(err @ CrontabFileError { kind: CrontabFileErrorKind::Io(_), .. }) => warn!("error accessing file {}: {}", path.as_ref().display(), err),
                Err(err @ CrontabFileError { kind: CrontabFileErrorKind::Parse(_), .. }) => warn!("skipping file {} due to parsing error: {}", path.as_ref().display(), err),
            }
        }
    }).unwrap_or_else(|err| {
        warn!("error parsing file {}: {}", path.as_ref().display(), err);
    });
}

<commit_msg>fix #33: skip temporary files (with starting dots)<commit_after>use std::convert::AsRef;
use std::fs::{read_dir, metadata};
use std::path::{Path, PathBuf};
use std::collections::BTreeMap;
use std::str::FromStr;

use cronparse::{CrontabFile, CrontabFileError, CrontabFileErrorKind};
use cronparse::crontab::{EnvVarEntry, CrontabEntry};

use generate::generate_systemd_units;

pub fn process_crontab_dir<T: FromStr, D: AsRef<Path>>(srcdir: &str, dstdir: D) where CrontabEntry: From<T>, CrontabFileError: From<<T as FromStr>::Err> {
    let files = read_dir(srcdir).and_then(|fs| fs.map(|r| r.map(|p| p.path()))
                                       .filter(|r| r.as_ref().map(|p| !p.file_name().and_then(|n| n.to_str().map(|n| n.starts_with("."))).unwrap_or(true)
                                                                  && metadata(p).map(|m| m.is_file()).unwrap_or(true)).unwrap_or(true))
                                       .collect::<Result<Vec<PathBuf>, _>>());
    match files {
        Err(err) => warn!("error processing directory {}: {}", srcdir, err),
        Ok(files) => for file in files {
            process_crontab_file::<T, _, _>(file, dstdir.as_ref());
        }
    }
}

pub fn process_crontab_file<T: FromStr, P: AsRef<Path>, D: AsRef<Path>>(path: P, dstdir: D) where CrontabEntry: From<T>, CrontabFileError: From<<T as FromStr>::Err> {
    CrontabFile::<T>::new(path.as_ref()).map(|crontab| {
        let mut env = BTreeMap::new();
        for entry in crontab {
            match entry {
                Ok(CrontabEntry::EnvVar(EnvVarEntry(name, value))) => { env.insert(name, value); },
                Ok(data) => match generate_systemd_units(data, &env, path.as_ref(), dstdir.as_ref()) {
                    Ok(_) => (),
                    Err(err) => warn!("error generating unit from {}: {}", path.as_ref().display(), err)
                },
                Err(err @ CrontabFileError { kind: CrontabFileErrorKind::Io(_), .. }) => warn!("error accessing file {}: {}", path.as_ref().display(), err),
                Err(err @ CrontabFileError { kind: CrontabFileErrorKind::Parse(_), .. }) => warn!("skipping file {} due to parsing error: {}", path.as_ref().display(), err),
            }
        }
    }).unwrap_or_else(|err| {
        warn!("error parsing file {}: {}", path.as_ref().display(), err);
    });
}

<|endoftext|>