|
@@ -7,14 +7,13 @@ use log::{info};
|
|
|
use std::time::{Duration, Instant};
|
|
|
use std::collections::VecDeque;
|
|
|
|
|
|
-
|
|
|
-
|
|
|
+use std::thread::sleep_ms;
|
|
|
use std::sync::mpsc::{Receiver, Sender};
|
|
|
|
|
|
pub enum EngineMsg {
|
|
|
SetBoard(Game),
|
|
|
SetPiece(Bitboard),
|
|
|
- Search(i32),
|
|
|
+ Search(SearchInfo),
|
|
|
Ping,
|
|
|
Stop,
|
|
|
NewGame,
|
|
@@ -22,19 +21,136 @@ pub enum EngineMsg {
|
|
|
GetInfo,
|
|
|
}
|
|
|
|
|
|
+pub enum SearchInfo {
|
|
|
+ Depth(isize),
|
|
|
+ Movetime(isize),
|
|
|
+ Time {
|
|
|
+ wtime: isize,
|
|
|
+ btime: isize,
|
|
|
+ winc: isize,
|
|
|
+ binc: isize,
|
|
|
+ movestogo: isize
|
|
|
+ },
|
|
|
+ Infinite,
|
|
|
|
|
|
-pub enum EngineState {
|
|
|
- Idle,
|
|
|
- Searching
|
|
|
}
|
|
|
|
|
|
-
|
|
|
pub enum InterfaceMsg {
|
|
|
- BestMove(Move),
|
|
|
- State(EngineState)
|
|
|
}
|
|
|
|
|
|
|
|
|
+pub struct Engine {
|
|
|
+ game: Game,
|
|
|
+ messages: VecDeque<EngineMsg>,
|
|
|
+ r: Receiver<EngineMsg>,
|
|
|
+ s: Sender<InterfaceMsg>
|
|
|
+}
|
|
|
+
|
|
|
+impl Engine {
|
|
|
+ pub fn new(r: Receiver<EngineMsg>, s: Sender<InterfaceMsg>) -> Self {
|
|
|
+ Engine {
|
|
|
+ game: Game::default(),
|
|
|
+ messages: VecDeque::new(),
|
|
|
+ r, s
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pub fn run(&mut self) {
|
|
|
+ while let Some(msg) = self.dequeue_message() {
|
|
|
+ match msg {
|
|
|
+ EngineMsg::SetBoard(g) => {
|
|
|
+ self.game = g;
|
|
|
+ },
|
|
|
+ EngineMsg::Search(ref info) => {
|
|
|
+ self.start_search(info);
|
|
|
+ }
|
|
|
+ _ => {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * blocks until a message is available
|
|
|
+ */
|
|
|
+ fn dequeue_message(&mut self) -> Option<EngineMsg> {
|
|
|
+ if self.messages.is_empty() {
|
|
|
+ self.r.recv().ok()
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ self.messages.pop_front()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ fn start_search(&mut self, si: &SearchInfo) {
|
|
|
+ match si {
|
|
|
+ SearchInfo::Depth(depth) => {
|
|
|
+ let receiver = &mut self.r;
|
|
|
+ let messages = &mut self.messages;
|
|
|
+ let mut check_fn = || -> bool {
|
|
|
+ if let Ok(msg) = receiver.try_recv() {
|
|
|
+ if let EngineMsg::Stop = msg {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ messages.push_back(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+ let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
|
|
|
+ let before = Instant::now();
|
|
|
+ let best_move = search(&self.game, &mut sc, *depth as i32);
|
|
|
+
|
|
|
+ let time = before.elapsed();
|
|
|
+ let nps = (sc.nodes as f64 / time.as_millis() as f64 * 1000.0) as i64;
|
|
|
+ info!("bestmove {}", best_move.to_string());
|
|
|
+ info!("searched {} nodes in {} ms ({} nodes/s)", sc.nodes, time.as_millis(), (sc.nodes as f64 / time.as_millis() as f64 * 1000.0) as i64);
|
|
|
+
|
|
|
+ println!("info nps {}", nps.to_string());
|
|
|
+ println!("bestmove {}", best_move.to_string());
|
|
|
+ },
|
|
|
+ SearchInfo::Movetime(millis) => {
|
|
|
+ let before = Instant::now();
|
|
|
+ let mut depth = 1;
|
|
|
+ let receiver = &mut self.r;
|
|
|
+ let messages = &mut self.messages;
|
|
|
+ let mut check_fn = || -> bool {
|
|
|
+ if let Ok(msg) = receiver.try_recv() {
|
|
|
+ if let EngineMsg::Stop = msg {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ messages.push_back(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if before.elapsed() > Duration::from_millis(*millis as _) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+
|
|
|
+ let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
|
|
|
+ let mut best_move = Move::default();
|
|
|
+ loop {
|
|
|
+ let bm = search(&mut self.game, &mut sc, depth as i32);
|
|
|
+ if bm != Move::default() {
|
|
|
+ best_move = bm;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ depth += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ println!("bestmove {}", best_move.to_string());
|
|
|
+ },
|
|
|
+ _ => {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+
|
|
|
fn dequeue_message(queue: &mut VecDeque<EngineMsg>, r: &Receiver<EngineMsg>) -> Option<EngineMsg> {
|
|
|
if queue.is_empty() {
|
|
|
r.recv().ok()
|
|
@@ -44,7 +160,7 @@ fn dequeue_message(queue: &mut VecDeque<EngineMsg>, r: &Receiver<EngineMsg>) ->
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-pub fn run_engine(r: Receiver<EngineMsg>, s: Sender<InterfaceMsg>) {
|
|
|
+pub fn run_engine(r: Receiver<EngineMsg>, _s: Sender<InterfaceMsg>) {
|
|
|
let mut game = Game::default();
|
|
|
let mut messages: VecDeque<EngineMsg> = VecDeque::new();
|
|
|
loop {
|
|
@@ -52,34 +168,71 @@ pub fn run_engine(r: Receiver<EngineMsg>, s: Sender<InterfaceMsg>) {
|
|
|
|
|
|
match msg {
|
|
|
EngineMsg::SetBoard(g) => {
|
|
|
- //println!("SetBoard");
|
|
|
game = g;
|
|
|
},
|
|
|
EngineMsg::SetPiece(_) => { println!("SetPiece") },
|
|
|
- EngineMsg::Search(depth) => {
|
|
|
- //info!("searching in pos\n {}", game.beautiful_print());
|
|
|
- //println!("Search {}", depth);
|
|
|
-
|
|
|
- let mut check_fn = || -> bool {
|
|
|
- if let Ok(msg) = r.try_recv() {
|
|
|
- if let EngineMsg::Stop = msg {
|
|
|
- return true;
|
|
|
+ EngineMsg::Search(info) => {
|
|
|
+
|
|
|
+ match info {
|
|
|
+ SearchInfo::Depth(depth) => {
|
|
|
+ let mut check_fn = || -> bool {
|
|
|
+ if let Ok(msg) = r.try_recv() {
|
|
|
+ if let EngineMsg::Stop = msg {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ messages.push_back(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+ let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
|
|
|
+ let before = Instant::now();
|
|
|
+ let best_move = search(&game, &mut sc, depth as i32);
|
|
|
+
|
|
|
+ let time = before.elapsed();
|
|
|
+ let nps = (sc.nodes as f64 / time.as_millis() as f64 * 1000.0) as i64;
|
|
|
+ info!("bestmove {}", best_move.to_string());
|
|
|
+ info!("searched {} nodes in {} ms ({} nodes/s)", sc.nodes, time.as_millis(), (sc.nodes as f64 / time.as_millis() as f64 * 1000.0) as i64);
|
|
|
+
|
|
|
+ println!("info nps {}", nps.to_string());
|
|
|
+ println!("bestmove {}", best_move.to_string());
|
|
|
+ },
|
|
|
+ SearchInfo::Movetime(millis) => {
|
|
|
+ let before = Instant::now();
|
|
|
+ let mut depth = 1;
|
|
|
+ let mut check_fn = || -> bool {
|
|
|
+ if let Ok(msg) = r.try_recv() {
|
|
|
+ if let EngineMsg::Stop = msg {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ messages.push_back(msg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if before.elapsed() > Duration::from_millis(millis as _) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+
|
|
|
+ let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
|
|
|
+ let mut best_move = Move::default();
|
|
|
+ loop {
|
|
|
+ let bm = search(&game, &mut sc, depth as i32);
|
|
|
+ if bm != Move::default() {
|
|
|
+ best_move = bm;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ depth += 1;
|
|
|
}
|
|
|
- else {
|
|
|
- messages.push_back(msg);
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- };
|
|
|
|
|
|
- let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
|
|
|
-
|
|
|
- let before = Instant::now();
|
|
|
- let best_move = search(&game, &mut sc, depth);
|
|
|
- let time = before.elapsed();
|
|
|
- println!("bestmove {}", best_move.to_string());
|
|
|
- info!("bestmove {}", best_move.to_string());
|
|
|
- info!("searched {} nodes in {} ms ({} nodes/s)", sc.nodes, time.as_millis(), (sc.nodes as f64 / time.as_millis() as f64 * 1000.0) as i64);
|
|
|
+ println!("bestmove {}", best_move.to_string());
|
|
|
+ },
|
|
|
+ _ => {}
|
|
|
+ }
|
|
|
},
|
|
|
EngineMsg::Ping => { println!("Ping") },
|
|
|
EngineMsg::Stop => { println!("Stop") },
|
|
@@ -96,3 +249,4 @@ pub fn run_engine(r: Receiver<EngineMsg>, s: Sender<InterfaceMsg>) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+*/
|