engine.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. use search::apply_move;
  2. use bitboard::Bitboard;
  3. use game::Game;
  4. use search::*;
  5. use movegen::*;
  6. use evaluate::PosValue;
  7. use log::{info};
  8. use std::time::{Duration, Instant};
  9. use std::collections::{VecDeque, HashMap};
  10. use zobrist::ZobristTable;
  11. use hash::Cache;
  12. use std::thread::sleep_ms;
  13. use std::sync::mpsc::{Receiver, Sender};
  14. pub enum EngineMsg {
  15. SetBoard(Game),
  16. SetPiece(Bitboard),
  17. Search(SearchInfo),
  18. Ping,
  19. Stop,
  20. NewGame,
  21. GetState,
  22. GetInfo,
  23. }
  24. pub enum SearchInfo {
  25. Depth(isize),
  26. Movetime(isize),
  27. Time {
  28. wtime: isize,
  29. btime: isize,
  30. winc: isize,
  31. binc: isize,
  32. movestogo: isize
  33. },
  34. Infinite,
  35. }
  36. pub enum InterfaceMsg {
  37. }
  38. pub struct Engine {
  39. game: Game,
  40. messages: VecDeque<EngineMsg>,
  41. r: Receiver<EngineMsg>,
  42. s: Sender<InterfaceMsg>,
  43. hash: Cache,
  44. zobrist_table: ZobristTable
  45. }
  46. impl Engine {
  47. pub fn new(r: Receiver<EngineMsg>, s: Sender<InterfaceMsg>) -> Self {
  48. let mut eng = Engine {
  49. game: Game::default(),
  50. messages: VecDeque::new(),
  51. r, s,
  52. hash: Cache::new(),
  53. zobrist_table: ZobristTable::new()
  54. };
  55. eng.game.zobrist = Some(eng.game.calculate_zobrist(&eng.zobrist_table));
  56. eng
  57. }
  58. pub fn run(&mut self) {
  59. while let Some(msg) = self.dequeue_message() {
  60. match msg {
  61. EngineMsg::SetBoard(g) => {
  62. self.game = g;
  63. },
  64. EngineMsg::Search(ref info) => {
  65. self.start_search(info);
  66. }
  67. _ => {}
  68. }
  69. }
  70. }
  71. /**
  72. * blocks until a message is available
  73. */
  74. fn dequeue_message(&mut self) -> Option<EngineMsg> {
  75. if self.messages.is_empty() {
  76. self.r.recv().ok()
  77. }
  78. else {
  79. self.messages.pop_front()
  80. }
  81. }
  82. fn start_search(&mut self, si: &SearchInfo) {
  83. match si {
  84. SearchInfo::Depth(depth) => {
  85. let receiver = &mut self.r;
  86. let messages = &mut self.messages;
  87. let mut check_fn = || -> bool {
  88. if let Ok(msg) = receiver.try_recv() {
  89. if let EngineMsg::Stop = msg {
  90. return true;
  91. }
  92. else {
  93. messages.push_back(msg);
  94. }
  95. }
  96. return false;
  97. };
  98. let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
  99. let before = Instant::now();
  100. let search_result = search(&self.game, &mut sc, &mut self.hash, *depth as i32);
  101. if let SearchResult::Finished(best_move, best_val) = search_result {
  102. let time = before.elapsed();
  103. let nps = (sc.nodes as f64 / time.as_millis() as f64 * 1000.0) as i64;
  104. info!("bestmove {}", best_move.to_string());
  105. 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);
  106. println!("info nps {}", nps.to_string());
  107. println!("bestmove {}", best_move.to_string());
  108. }
  109. },
  110. SearchInfo::Movetime(millis) => {
  111. let before = Instant::now();
  112. let mut depth = 1;
  113. let receiver = &mut self.r;
  114. let messages = &mut self.messages;
  115. let mut check_fn = || -> bool {
  116. if let Ok(msg) = receiver.try_recv() {
  117. if let EngineMsg::Stop = msg {
  118. return true;
  119. }
  120. else {
  121. messages.push_back(msg);
  122. }
  123. }
  124. if before.elapsed() > Duration::from_millis(*millis as _) {
  125. return true;
  126. }
  127. return false;
  128. };
  129. let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
  130. let mut best_move = Move::default();
  131. let mut best_val: PosValue = i32::max_value() as _;
  132. loop {
  133. let search_result = search(&mut self.game, &mut sc, &mut self.hash, depth as i32);
  134. if let SearchResult::Finished(bm, bv) = search_result {
  135. info!("depth: {} bm: {}, bv: {}", depth, bm.to_string(), bv);
  136. best_move = bm;
  137. best_val = bv;
  138. let elapsed = before.elapsed();
  139. let nodes = sc.nodes;
  140. let nps = (nodes as f64 / elapsed.as_nanos() as f64 * 1000000000.0) as i64;
  141. let cp = best_val as i64;
  142. println!("info depth {} score cp {} time {} nodes {} nps {} pv {}", depth, cp, elapsed.as_millis(), nodes, nps, best_move.to_string());
  143. info!("info depth {} score cp {} time {} nodes {} nps {} pv {}", depth, cp, elapsed.as_millis(), nodes, nps, best_move.to_string());
  144. depth += 1;
  145. }
  146. else if let SearchResult::Mate(bm, in_turns) = search_result {
  147. best_move = bm;
  148. let elapsed = before.elapsed();
  149. let nodes = sc.nodes;
  150. let nps = (nodes as f64 / elapsed.as_nanos() as f64 * 1000000000.0) as i64;
  151. let pv = best_val as i64;
  152. println!("info depth {} score mate {} time {} nodes {} nps {} pv {}", depth, in_turns, elapsed.as_millis(), nodes, nps, bm.to_string());
  153. info!("info depth {} score mate {} time {} nodes {} nps {} pv {}", depth, pv, elapsed.as_millis(), nodes, nps, bm.to_string());
  154. break;
  155. }
  156. else {
  157. break;
  158. }
  159. }
  160. info!("bestmove {}", best_move.to_string());
  161. println!("bestmove {}", best_move.to_string());
  162. },
  163. _ => {}
  164. }
  165. }
  166. }
  167. /*
  168. fn dequeue_message(queue: &mut VecDeque<EngineMsg>, r: &Receiver<EngineMsg>) -> Option<EngineMsg> {
  169. if queue.is_empty() {
  170. r.recv().ok()
  171. }
  172. else {
  173. queue.pop_front()
  174. }
  175. }
  176. pub fn run_engine(r: Receiver<EngineMsg>, _s: Sender<InterfaceMsg>) {
  177. let mut game = Game::default();
  178. let mut messages: VecDeque<EngineMsg> = VecDeque::new();
  179. loop {
  180. let msg = dequeue_message(&mut messages, &r).unwrap();
  181. match msg {
  182. EngineMsg::SetBoard(g) => {
  183. game = g;
  184. },
  185. EngineMsg::SetPiece(_) => { println!("SetPiece") },
  186. EngineMsg::Search(info) => {
  187. match info {
  188. SearchInfo::Depth(depth) => {
  189. let mut check_fn = || -> bool {
  190. if let Ok(msg) = r.try_recv() {
  191. if let EngineMsg::Stop = msg {
  192. return true;
  193. }
  194. else {
  195. messages.push_back(msg);
  196. }
  197. }
  198. return false;
  199. };
  200. let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
  201. let before = Instant::now();
  202. let best_move = search(&game, &mut sc, depth as i32);
  203. let time = before.elapsed();
  204. let nps = (sc.nodes as f64 / time.as_millis() as f64 * 1000.0) as i64;
  205. info!("bestmove {}", best_move.to_string());
  206. 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);
  207. println!("info nps {}", nps.to_string());
  208. println!("bestmove {}", best_move.to_string());
  209. },
  210. SearchInfo::Movetime(millis) => {
  211. let before = Instant::now();
  212. let mut depth = 1;
  213. let mut check_fn = || -> bool {
  214. if let Ok(msg) = r.try_recv() {
  215. if let EngineMsg::Stop = msg {
  216. return true;
  217. }
  218. else {
  219. messages.push_back(msg);
  220. }
  221. }
  222. if before.elapsed() > Duration::from_millis(millis as _) {
  223. return true;
  224. }
  225. return false;
  226. };
  227. let mut sc = SearchControl{ nodes: 0, check: &mut check_fn };
  228. let mut best_move = Move::default();
  229. loop {
  230. let bm = search(&game, &mut sc, depth as i32);
  231. if bm != Move::default() {
  232. best_move = bm;
  233. }
  234. else {
  235. break;
  236. }
  237. depth += 1;
  238. }
  239. println!("bestmove {}", best_move.to_string());
  240. },
  241. _ => {}
  242. }
  243. },
  244. EngineMsg::Ping => { println!("Ping") },
  245. EngineMsg::Stop => { println!("Stop") },
  246. EngineMsg::NewGame => {
  247. //println!("NewGame")
  248. },
  249. EngineMsg::GetState => { println!("GetState") },
  250. EngineMsg::GetInfo => { println!("GetInfo") },
  251. }
  252. //println!("{}", game.beautiful_print());
  253. //let moves = generate_moves(&game, WHITE);
  254. }
  255. }
  256. */