1use chrono::prelude::*;
3
4use std::fmt;
5use std::{thread};
6use std::sync::Mutex;
7use std::sync::Arc;
8use std::sync::atomic::AtomicBool;
9use std::sync::atomic::Ordering;
10use std::thread::JoinHandle;
11use std::marker::Send;
12use std::marker::PhantomData;
13use std::time::{Instant,Duration};
14use std::io::Write;
15use std::io::BufWriter;
16use std::fs;
17use std::fs::OpenOptions;
18use std::convert::TryFrom;
19
20use crossbeam_channel::unbounded;
21use crossbeam_channel::Sender;
22use crossbeam_channel::Receiver;
23use crossbeam_channel::SendError;
24use crossbeam_channel::after;
25use crossbeam_channel::never;
26
27use command::*;
28use event::*;
29use error::*;
30use input::*;
31use output::*;
32use player::*;
33use shogi::*;
34use hash::*;
35use Logger;
36use logger::FileLogger;
37use OnErrorHandler;
38use SandBox;
39use rule::*;
40use protocol::*;
41
42pub trait SelfMatchKifuWriter {
44 fn write(&mut self,initial_sfen:&String,m:&Vec<Move>) -> Result<(),KifuWriteError>;
50 fn to_sfen(&self,initial_sfen:&String,m:&Vec<Move>)
56 -> Result<String, SfenStringConvertError> {
57
58 let sfen = initial_sfen.split(" ").collect::<Vec<&str>>();
59
60 if sfen.len() >= 5 {
61 match (sfen[0],sfen[1],sfen[2],sfen[3],sfen[4]) {
62 ("sfen",p1,p2,p3,p4) if m.len() > 0 => {
63 Ok(format!("sfen {} {} {} {} moves {}",p1,p2,p3,p4,m.to_sfen()?))
64 },
65 ("sfen",p1,p2,p3,p4) => {
66 Ok(format!("sfen {} {} {} {}",p1,p2,p3,p4))
67 },
68 ("startpos",_,_,_,_) if m.len() > 0 => {
69 Ok(format!("startpos moves {}",m.to_sfen()?))
70 },
71 ("startpos",_,_,_,_)=> {
72 Ok(format!("startpos"))
73 },
74 _ => {
75 Err(SfenStringConvertError::InvalidFormat(initial_sfen.clone()))
76 }
77 }
78 } else if sfen.len() >= 1 && sfen[0] == "startpos" {
79 if m.len() > 0 {
80 Ok(format!("startpos moves {}",m.to_sfen()?))
81 } else {
82 Ok(format!("startpos"))
83 }
84 } else {
85 Err(SfenStringConvertError::InvalidFormat(initial_sfen.clone()))
86 }
87 }
88}
89#[derive(Debug)]
91pub struct FileSfenKifuWriter {
92 writer:BufWriter<fs::File>,
93}
94impl FileSfenKifuWriter {
95 pub fn new(file:String) -> Result<FileSfenKifuWriter,KifuWriteError> {
100 Ok(FileSfenKifuWriter {
101 writer:BufWriter::new(OpenOptions::new().append(true).create(true).open(file)?),
102 })
103 }
104}
105impl SelfMatchKifuWriter for FileSfenKifuWriter {
106 fn write(&mut self,initial_sfen:&String,m:&Vec<Move>) -> Result<(),KifuWriteError> {
112 let sfen = self.to_sfen(initial_sfen,m)?;
113
114 let _ = self.writer.write(format!("{}\n",sfen).as_bytes())?;
115 Ok(())
116 }
117}
118#[derive(Debug)]
120enum TimeoutKind {
121 Never,
123 Turn,
125 Uptime,
127}
128#[derive(Debug)]
130pub enum SelfMatchMessage {
131 Ready,
133 GameStart,
135 StartThink(Teban,Banmen,MochigomaCollections,u32,Vec<AppliedMove>,Instant),
137 StartPonderThink(Teban,Banmen,MochigomaCollections,u32,Vec<AppliedMove>),
139 NotifyMove(BestMove),
141 PonderHit,
143 PonderNG,
145 GameEnd(GameEndState),
147 Abort,
149 Quit,
151 Error(usize),
153}
154#[derive(Debug)]
156pub struct SelfMatchResult {
157 pub game_count:u32,
159 pub elapsed:Duration,
161 pub start_dt:DateTime<Local>,
163 pub end_dt:DateTime<Local>,
165}
166#[derive(Debug)]
168pub struct SelfMatchEngine<E>
169 where E: PlayerError {
170 player_error_type:PhantomData<E>,
171 pub system_event_queue:Arc<Mutex<SystemEventQueue>>,
173}
174impl<E> SelfMatchEngine<E>
175 where E: PlayerError {
176 pub fn new() -> SelfMatchEngine<E> where E: PlayerError {
178 SelfMatchEngine {
179 player_error_type:PhantomData::<E>,
180 system_event_queue:Arc::new(Mutex::new(EventQueue::new())),
181 }
182 }
183
184 pub fn start_default<T,S,P,I,F,RH,EH>(&mut self, on_init_event_dispatcher:I,
203 flip_players:F,
204 initial_position_creator:Option<Box<dyn FnMut() -> String + Send + 'static>>,
205 kifu_writer:Option<Box<dyn FnMut(&String,&Vec<Move>) -> Result<(),KifuWriteError> +Send + 'static>>,
206 input_handler:RH,
207 player1:T,
208 player2:T,
209 player1_options:Vec<(String,SysEventOption)>,
210 player2_options:Vec<(String,SysEventOption)>,
211 info_sender:S,
212 pinfo_sender:P,
213 game_time_limit:UsiGoTimeLimit,
214 uptime:Option<Duration>,
215 number_of_games:Option<u32>,
216 on_error:EH) -> Result<SelfMatchResult,SelfMatchRunningError<E>>
217 where T: USIPlayer<E> + fmt::Debug + Send + 'static,
218 F: FnMut() -> bool + Send + 'static,
219 RH: FnMut(String) -> Result<bool,SelfMatchRunningError<E>> + Send + 'static,
220 I: FnMut(&mut SelfMatchEventDispatcher<E,FileLogger>),
221 S: InfoSender,
222 P: PeriodicallyInfo + Clone + Send + 'static,
223 Arc<Mutex<FileLogger>>: Send + 'static,
224 EH: FnMut(Option<Arc<Mutex<OnErrorHandler<FileLogger>>>>,
225 &SelfMatchRunningError<E>) {
226 self.start_with_log_path(String::from("logs/log.txt"),
227 on_init_event_dispatcher,
228 flip_players,
229 initial_position_creator,
230 kifu_writer, input_handler,
231 player1,player2,
232 player1_options, player2_options,
233 info_sender,
234 pinfo_sender,
235 game_time_limit,
236 uptime,
237 number_of_games,
238 on_error)
239 }
240
241 pub fn start_with_log_path<T,S,P,I,F,RH,EH>(&mut self,path:String,
261 on_init_event_dispatcher:I,
262 flip_players:F,
263 initial_position_creator:Option<Box<dyn FnMut() -> String + Send + 'static>>,
264 kifu_writer:Option<Box<dyn FnMut(&String,&Vec<Move>) -> Result<(),KifuWriteError> +Send + 'static>>,
265 input_handler:RH,
266 player1:T,
267 player2:T,
268 player1_options:Vec<(String,SysEventOption)>,
269 player2_options:Vec<(String,SysEventOption)>,
270 info_sender:S,
271 pinfo_sender:P,
272 game_time_limit:UsiGoTimeLimit,
273 uptime:Option<Duration>,
274 number_of_games:Option<u32>,
275 mut on_error:EH) -> Result<SelfMatchResult,SelfMatchRunningError<E>>
276 where T: USIPlayer<E> + fmt::Debug + Send + 'static,
277 F: FnMut() -> bool + Send + 'static,
278 RH: FnMut(String) -> Result<bool,SelfMatchRunningError<E>> + Send + 'static,
279 I: FnMut(&mut SelfMatchEventDispatcher<E,FileLogger>),
280 S: InfoSender,
281 P: PeriodicallyInfo + Clone + Send + 'static,
282 Arc<Mutex<FileLogger>>: Send + 'static,
283 EH: FnMut(Option<Arc<Mutex<OnErrorHandler<FileLogger>>>>,
284 &SelfMatchRunningError<E>) {
285 let logger = match FileLogger::new(path) {
286 Err(e) => {
287 let e = SelfMatchRunningError::IOError(e);
288 on_error(None,&e);
289 return Err(e);
290 },
291 Ok(logger) => logger,
292 };
293
294 let input_reader = USIStdInputReader::new();
295
296 self.start(on_init_event_dispatcher,
297 flip_players,
298 initial_position_creator,
299 kifu_writer, input_reader, input_handler,
300 player1,player2,
301 player1_options, player2_options,
302 info_sender,
303 pinfo_sender,
304 game_time_limit,
305 uptime,
306 number_of_games,
307 logger, on_error)
308 }
309
310 pub fn start<T,S,P,I,F,R,RH,L,EH>(&mut self, on_init_event_dispatcher:I,
331 flip_players:F,
332 initial_position_creator:Option<Box<dyn FnMut() -> String + Send + 'static>>,
333 kifu_writer:Option<Box<dyn FnMut(&String,&Vec<Move>) -> Result<(),KifuWriteError> +Send + 'static>>,
334 input_reader:R,
335 input_handler:RH,
336 player1:T,
337 player2:T,
338 player1_options:Vec<(String,SysEventOption)>,
339 player2_options:Vec<(String,SysEventOption)>,
340 info_sender:S,
341 pinfo_sender:P,
342 game_time_limit:UsiGoTimeLimit,
343 uptime:Option<Duration>,
344 number_of_games:Option<u32>,
345 logger:L, mut on_error:EH) -> Result<SelfMatchResult,SelfMatchRunningError<E>>
346 where T: USIPlayer<E> + fmt::Debug + Send + 'static,
347 F: FnMut() -> bool + Send + 'static,
348 R: USIInputReader + Send + 'static,
349 RH: FnMut(String) -> Result<bool,SelfMatchRunningError<E>> + Send + 'static,
350 I: FnMut(&mut SelfMatchEventDispatcher<E,L>),
351 S: InfoSender,
352 P: PeriodicallyInfo + Clone + Send + 'static,
353 L: Logger + fmt::Debug + Send + 'static,
354 Arc<Mutex<L>>: Send + 'static,
355 EH: FnMut(Option<Arc<Mutex<OnErrorHandler<L>>>>,
356 &SelfMatchRunningError<E>) {
357 let logger_arc = Arc::new(Mutex::new(logger));
358 let on_error_handler_arc = Arc::new(Mutex::new(OnErrorHandler::new(logger_arc.clone())));
359 let on_error_handler = on_error_handler_arc.clone();
360
361 let r = self.run(on_init_event_dispatcher,
362 flip_players,
363 initial_position_creator,
364 kifu_writer, input_reader, input_handler,
365 player1,player2,
366 player1_options, player2_options,
367 info_sender,
368 pinfo_sender,
369 game_time_limit,
370 uptime,
371 number_of_games,
372 logger_arc, on_error_handler_arc);
373
374 if let Err(ref e) = r {
375 on_error(Some(on_error_handler),e);
376 }
377
378 r
379 }
380
381 fn run<T,S,P,I,F,R,RH,L>(&mut self, mut on_init_event_dispatcher:I,
382 mut flip_players:F,
383 initial_position_creator:Option<Box<dyn FnMut() -> String + Send + 'static>>,
384 kifu_writer:Option<Box<dyn FnMut(&String,&Vec<Move>) -> Result<(),KifuWriteError> + Send + 'static>>,
385 mut input_reader:R,
386 mut input_handler:RH,
387 mut player1:T,
388 mut player2:T,
389 player1_options:Vec<(String,SysEventOption)>,
390 player2_options:Vec<(String,SysEventOption)>,
391 info_sender:S,
392 pinfo_sender:P,
393 game_time_limit:UsiGoTimeLimit,
394 uptime:Option<Duration>,
395 number_of_games:Option<u32>,
396 logger_arc:Arc<Mutex<L>>,
397 on_error_handler_arc:Arc<Mutex<OnErrorHandler<L>>>) -> Result<SelfMatchResult,SelfMatchRunningError<E>>
398 where T: USIPlayer<E> + fmt::Debug + Send + 'static,
399 F: FnMut() -> bool + Send + 'static,
400 R: USIInputReader + Send + 'static,
401 RH: FnMut(String) -> Result<bool,SelfMatchRunningError<E>> + Send + 'static,
402 I: FnMut(&mut SelfMatchEventDispatcher<E,L>),
403 S: InfoSender,
404 P: PeriodicallyInfo + Clone + Send + 'static,
405 L: Logger + fmt::Debug + Send + 'static,
406 Arc<Mutex<L>>: Send + 'static {
407 let start_time = Instant::now();
408 let start_dt = Local::now();
409
410 let mut self_match_event_dispatcher:SelfMatchEventDispatcher<E,L> = USIEventDispatcher::new(&on_error_handler_arc);
411
412 on_init_event_dispatcher(&mut self_match_event_dispatcher);
413
414 let mut system_event_dispatcher:SystemEventDispatcher<SelfMatchEngine<E>,E,L> = USIEventDispatcher::new(&on_error_handler_arc);
415
416 let user_event_queue_arc:[Arc<Mutex<UserEventQueue>>; 2] = [Arc::new(Mutex::new(EventQueue::new())),Arc::new(Mutex::new(EventQueue::new()))];
417
418 let user_event_queue = [user_event_queue_arc[0].clone(),user_event_queue_arc[1].clone()];
419
420 let mut initial_position_creator:Box<dyn FnMut() -> String + Send + 'static> =
421 initial_position_creator.map_or(Box::new(|| String::from("startpos")), |f| {
422 f
423 });
424
425 let on_error_handler = on_error_handler_arc.clone();
426
427 let mut kifu_writer = kifu_writer;
428 let mut kifu_writer = move |sfen:&String,m:&Vec<Move>| {
429 let _ = kifu_writer.as_mut().map(|w| {
430 let _= w(sfen,m).map_err(|e| on_error_handler.lock().map(|h| h.call(&e)));
431 });
432 };
433
434 let quit_ready_arc = Arc::new(AtomicBool::new(false));
435 let on_error_handler = on_error_handler_arc.clone();
436
437 let self_match_event_queue:SelfMatchEventQueue = EventQueue::new();
438 let self_match_event_queue_arc = Arc::new(Mutex::new(self_match_event_queue));
439
440 let (ss,sr) = unbounded();
441 let (cs1,cr1) = unbounded();
442 let (cs2,cr2) = unbounded();
443 let mut cr = vec![cr1,cr2];
444
445 {
446 let ss = ss.clone();
447 let quit_ready = quit_ready_arc.clone();
448
449 let on_error_handler = on_error_handler_arc.clone();
450
451 system_event_dispatcher.add_handler(SystemEventKind::Quit, move |_,e| {
452 match e {
453 &SystemEvent::Quit => {
454 for i in 0..2 {
455 match user_event_queue[i].lock() {
456 Ok(mut user_event_queue) => {
457 user_event_queue.push(UserEvent::Quit);
458 },
459 Err(ref e) => {
460 let _ = on_error_handler.lock().map(|h| h.call(e));
461 }
462 };
463 };
464
465 if !quit_ready.load(Ordering::Acquire) {
466 if let Err(ref e) = ss.send(SelfMatchMessage::Quit) {
467 let _ = on_error_handler.lock().map(|h| h.call(e));
468 }
469 }
470
471 Ok(())
472 },
473 e => Err(EventHandlerError::InvalidState(e.event_kind())),
474 }
475 });
476 }
477
478 for (k,v) in player1_options {
479 match player1.set_option(k,v) {
480 Ok(()) => (),
481 Err(ref e) => {
482 let _ = on_error_handler.lock().map(|h| h.call(e));
483 return Err(SelfMatchRunningError::Fail(String::from(
484 "An error occurred while executing a self match. Please see the log for details ..."
485 )));
486 }
487 }
488 }
489
490 for (k,v) in player2_options {
491 match player2.set_option(k,v) {
492 Ok(()) => (),
493 Err(ref e) => {
494 let _ = on_error_handler.lock().map(|h| h.call(e));
495 return Err(SelfMatchRunningError::Fail(String::from(
496 "An error occurred while executing a self match. Please see the log for details ..."
497 )));
498 }
499 }
500 }
501
502 let position_parser = PositionParser::new();
503
504 let self_match_event_queue = self_match_event_queue_arc.clone();
505 let quit_ready = quit_ready_arc.clone();
506
507 let on_error_handler = on_error_handler_arc.clone();
508
509 let user_event_queue = user_event_queue_arc.clone();
510
511 let bridge_h = thread::spawn(move || SandBox::immediate(|| {
512 let cs = [cs1.clone(),cs2.clone()];
513 let mut prev_move:Option<AppliedMove> = None;
514 let mut ponders:[Option<AppliedMove>; 2] = [None,None];
515
516 let quit_ready_inner = quit_ready.clone();
517
518 let quit_notification = move || {
519 quit_ready_inner.store(true,Ordering::Release);
520 };
521
522 let self_match_event_queue_inner = self_match_event_queue.clone();
523 let on_error_handler_inner = on_error_handler.clone();
524
525 let quit_ready_inner = quit_ready.clone();
526
527 let on_gameend = move |win_cs:Sender<SelfMatchMessage>,
528 lose_cs:Sender<SelfMatchMessage>,
529 _:[Sender<SelfMatchMessage>; 2],
530 sr:&Receiver<SelfMatchMessage>,
531 s:SelfMatchGameEndState| {
532 let mut message_state = GameEndState::Win;
533
534 let quit_notification = || {
535 quit_ready_inner.store(true,Ordering::Release);
536 };
537
538 match self_match_event_queue_inner.lock() {
539 Ok(mut self_match_event_queue) => {
540 self_match_event_queue.push(SelfMatchEvent::GameEnd(s));
541 },
542 Err(ref e) => {
543 let _ = on_error_handler_inner.lock().map(|h| h.call(e));
544 return Err(SelfMatchRunningError::InvalidState(String::from(
545 "Exclusive lock on self_match_event_queue failed."
546 )));
547 }
548 }
549
550 for current_cs in &[win_cs.clone(),lose_cs.clone()] {
551 current_cs.send(SelfMatchMessage::GameEnd(message_state))?;
552 match sr.recv()? {
553 SelfMatchMessage::Ready => (),
554 SelfMatchMessage::Error(n) => {
555 return Err(SelfMatchRunningError::PlayerThreadError(n));
556 },
557 SelfMatchMessage::Quit => {
558 quit_notification();
559
560 return Ok(());
561 },
562 _ => {
563 return Err(SelfMatchRunningError::InvalidState(String::from(
564 "An invalid message was sent to the self-match management thread."
565 )));
566 }
567 }
568 message_state = GameEndState::Lose;
569 }
570 Ok(())
571 };
572
573 let mut game_count = 0;
574
575 'gameloop: while !quit_ready.load(Ordering::Acquire) &&
576 number_of_games.map_or(true, |n| game_count < n) &&
577 uptime.map_or(true, |t| Instant::now() - start_time < t) {
578
579 cs[0].send(SelfMatchMessage::GameStart)?;
580 cs[1].send(SelfMatchMessage::GameStart)?;
581
582 game_count += 1;
583
584 let mut cs_index = if flip_players() {
585 1
586 } else {
587 0
588 };
589
590 let sfen = initial_position_creator();
591 let (teban, banmen, mc, n, mvs) = match position_parser.parse(&sfen.split(" ").collect::<Vec<&str>>()) {
592 Ok(position) => {
593 position.extract()
594 },
595 Err(ref e) => {
596 let _ = on_error_handler.lock().map(|h| h.call(e));
597 return Err(SelfMatchRunningError::InvalidState(String::from(
598 "An error occurred parsing the sfen string."
599 )));
600 }
601 };
602
603 if teban == Teban::Gote {
604 cs_index = (cs_index + 1) % 2;
605 }
606
607 let banmen_at_start = banmen.clone();
608 let mc_at_start = mc.clone();
609 let teban_at_start = teban.clone();
610
611 let mut current_game_time_limit = [game_time_limit,game_time_limit];
612 let mut current_time_limit = current_game_time_limit[cs_index].to_instant(teban,Instant::now());
613
614 let kyokumen_map:KyokumenMap<u64,u32> = KyokumenMap::new();
615 let oute_kyokumen_map:KyokumenMap<u64,u32> = KyokumenMap::new();
616
617 let hasher = KyokumenHash::new();
618
619 let (ms,mg) = match mc {
620 MochigomaCollections::Pair(ref ms, ref mg) => {
621 match teban {
622 Teban::Sente => (ms.clone(),mg.clone()),
623 Teban::Gote => (mg.clone(),ms.clone()),
624 }
625 },
626 MochigomaCollections::Empty => {
627 (Mochigoma::new(),Mochigoma::new())
628 },
629 };
630
631 let (mhash, shash) = hasher.calc_initial_hash(&banmen,&ms,&mg);
632
633 let mut mvs = mvs.into_iter().map(|m| m.to_applied_move()).collect::<Vec<AppliedMove>>();
634
635 let (mut teban,
636 mut state,
637 mut mc,
638 mut mhash,
639 mut shash,
640 mut kyokumen_map,
641 mut oute_kyokumen_map) = Rule::apply_moves(State::new(banmen),
642 teban,mc,&mvs,
643 mhash,shash,
644 kyokumen_map,
645 oute_kyokumen_map,&hasher);
646
647 if teban != teban_at_start {
648 cs_index = (cs_index + 1) % 2;
649 }
650
651 match self_match_event_queue.lock() {
652 Ok(mut self_match_event_queue) => {
653 self_match_event_queue.push(
654 SelfMatchEvent::GameStart(if cs_index == 1 {
655 2
656 } else {
657 1
658 }, teban, sfen.clone()));
659 },
660 Err(ref e) => {
661 let _ = on_error_handler.lock().map(|h| h.call(e));
662 return Err(SelfMatchRunningError::InvalidState(String::from(
663 "Exclusive lock on self_match_event_queue failed."
664 )));
665 }
666 }
667
668 while uptime.map_or(true, |t| Instant::now() - start_time < t) {
669 match user_event_queue[cs_index].lock() {
670 Ok(mut user_event_queue) => {
671 user_event_queue.clear();
672 },
673 Err(ref e) => {
674 let _ = on_error_handler.lock().map(|h| h.call(e));
675 }
676 }
677
678 match ponders[cs_index] {
679 None => {
680 let _ = cs[cs_index].send(SelfMatchMessage::StartThink(
681 teban_at_start.clone(),banmen_at_start.clone(),mc_at_start.clone(),n,mvs.clone(),Instant::now()));
682 },
683 pm @ Some(_) if pm == prev_move => {
684 match user_event_queue[cs_index].lock() {
685 Ok(mut user_event_queue) => {
686 user_event_queue.push(UserEvent::PonderHit(Instant::now()));
687 },
688 Err(ref e) => {
689 let _ = on_error_handler.lock().map(|h| h.call(e));
690 }
691 }
692 let _ = cs[cs_index].send(SelfMatchMessage::PonderHit);
693 },
694 _ => {
695 match user_event_queue[cs_index].lock() {
696 Ok(mut user_event_queue) => {
697 user_event_queue.push(UserEvent::Stop);
698 },
699 Err(ref e) => {
700 let _ = on_error_handler.lock().map(|h| h.call(e));
701 }
702 }
703 let _ = cs[cs_index].send(SelfMatchMessage::PonderNG);
704 let _ = cs[cs_index].send(SelfMatchMessage::StartThink(
705 teban_at_start.clone(),banmen_at_start.clone(),mc_at_start.clone(),n,mvs.clone(),Instant::now()));
706 }
707 }
708
709 let think_start_time = Instant::now();
710
711 let timeout = current_time_limit.map(|cl| uptime.map(|u| {
712 if start_time + u < cl {
713 start_time + u - Instant::now()
714 } else {
715 cl - Instant::now()
716 }
717 }).unwrap_or(cl - Instant::now()))
718 .map(|d| after(d))
719 .unwrap_or_else(|| uptime.map(|u| after(start_time + u - Instant::now()))
720 .unwrap_or(never()));
721
722 let timeout_kind = current_time_limit.map(|cl| uptime.map(|u| {
723 if start_time + u < cl {
724 TimeoutKind::Uptime
725 } else {
726 TimeoutKind::Turn
727 }
728 }).unwrap_or(TimeoutKind::Turn))
729 .unwrap_or_else(|| uptime.map(|_| TimeoutKind::Uptime).unwrap_or(TimeoutKind::Never));
730
731 select! {
732 recv(sr) -> message => {
733 match message? {
734 SelfMatchMessage::NotifyMove(BestMove::Move(m,pm)) => {
735 match self_match_event_queue.lock() {
736 Ok(mut self_match_event_queue) => {
737 self_match_event_queue.push(SelfMatchEvent::Moved(teban,Moved::try_from((state.get_banmen(),&m))?));
738 },
739 Err(ref e) => {
740 let _ = on_error_handler.lock().map(|h| h.call(e));
741 return Err(SelfMatchRunningError::InvalidState(String::from(
742 "Exclusive lock on self_match_event_queue failed."
743 )));
744 }
745 }
746
747 current_game_time_limit[cs_index] = Rule::update_time_limit(
748 ¤t_game_time_limit[cs_index],
749 teban,think_start_time.elapsed()
750 );
751 current_time_limit = current_game_time_limit[cs_index].to_instant(teban,Instant::now());
752
753 let m = m.to_applied_move();
754
755 match Rule::apply_valid_move(&state,teban,&mc,m) {
756 Ok((next,nmc,o)) => {
757
758 let is_win = Rule::is_win(&state,teban,m);
759
760 if is_win {
761 mvs.push(m);
762
763 kifu_writer(&sfen,&mvs.into_iter()
764 .map(|m| m.to_move())
765 .collect::<Vec<Move>>());
766 on_gameend(
767 cs[cs_index].clone(),
768 cs[(cs_index+1) % 2].clone(),
769 [cs[0].clone(),cs[1].clone()],
770 &sr,
771 SelfMatchGameEndState::Win(teban)
772 )?;
773 break;
774 }
775
776 if Rule::in_check(teban.opposite(),&state) {
777 if Rule::in_check(teban.opposite(),&next) {
778 mvs.push(m);
779 kifu_writer(&sfen,&mvs.into_iter()
780 .map(|m| m.to_move())
781 .collect::<Vec<Move>>());
782 on_gameend(
783 cs[(cs_index+1) % 2].clone(),
784 cs[cs_index].clone(),
785 [cs[0].clone(),cs[1].clone()],
786 &sr,
787 SelfMatchGameEndState::Foul(teban,FoulKind::NotRespondedOute)
788 )?;
789 break;
790 }
791 } else {
792 if Rule::in_check(teban.opposite(),&next) {
793 mvs.push(m);
794 kifu_writer(&sfen,&mvs.into_iter()
795 .map(|m| m.to_move())
796 .collect::<Vec<Move>>());
797 on_gameend(
798 cs[(cs_index+1) % 2].clone(),
799 cs[cs_index].clone(),
800 [cs[0].clone(),cs[1].clone()],
801 &sr,
802 SelfMatchGameEndState::Foul(teban,FoulKind::Suicide)
803 )?;
804 break;
805 }
806 }
807
808 mvs.push(m);
809
810 mhash = hasher.calc_main_hash(mhash,teban,&state.get_banmen(),&mc,m,&o);
811 shash = hasher.calc_sub_hash(shash,teban,&state.get_banmen(),&mc,m,&o);
812
813 mc = nmc;
814 state = next;
815
816 if Rule::is_put_fu_and_mate(&state,teban,&mc,m) {
817 kifu_writer(&sfen,&mvs.into_iter()
818 .map(|m| m.to_move())
819 .collect::<Vec<Move>>());
820 on_gameend(
821 cs[(cs_index+1) % 2].clone(),
822 cs[cs_index].clone(),
823 [cs[0].clone(),cs[1].clone()],
824 &sr,
825 SelfMatchGameEndState::Foul(teban,FoulKind::PutFuAndMate)
826 )?;
827 break;
828 }
829
830 if Rule::is_sennichite_by_oute(
831 &state,
832 teban,mhash,shash,
833 &oute_kyokumen_map
834 ) {
835 kifu_writer(&sfen,&mvs.into_iter()
836 .map(|m| m.to_move())
837 .collect::<Vec<Move>>());
838 on_gameend(
839 cs[(cs_index+1) % 2].clone(),
840 cs[cs_index].clone(),
841 [cs[0].clone(),cs[1].clone()],
842 &sr,
843 SelfMatchGameEndState::Foul(teban,FoulKind::SennichiteOu)
844 )?;
845 break;
846 }
847
848 Rule::update_sennichite_by_oute_map(
849 &state,
850 teban,mhash,shash,
851 &mut oute_kyokumen_map
852 );
853
854 if Rule::is_sennichite(
855 &state,teban,mhash,shash,&kyokumen_map
856 ) {
857 kifu_writer(&sfen,&mvs.into_iter()
858 .map(|m| m.to_move())
859 .collect::<Vec<Move>>());
860 on_gameend(
861 cs[(cs_index+1) % 2].clone(),
862 cs[cs_index].clone(),
863 [cs[0].clone(),cs[1].clone()],
864 &sr,
865 SelfMatchGameEndState::Foul(teban,FoulKind::Sennichite)
866 )?;
867 break;
868 }
869
870 Rule::update_sennichite_map(
871 &state,teban,mhash,shash,&mut kyokumen_map
872 );
873
874 teban = teban.opposite();
875
876 ponders[cs_index] = pm.map(|pm| pm.to_applied_move());
877
878 match pm {
879 Some(pm) => {
880 match mvs.clone() {
881 mut mvs => {
882 mvs.push(pm.to_applied_move());
883 cs[cs_index].send(
884 SelfMatchMessage::StartPonderThink(
885 teban_at_start.clone(),banmen_at_start.clone(),
886 mc_at_start.clone(),n,mvs))?;
887 }
888 }
889 },
890 None => (),
891 }
892
893 cs_index = (cs_index + 1) % 2;
894 },
895 Err(_) => {
896 mvs.push(m);
897 kifu_writer(&sfen,&mvs.into_iter()
898 .map(|m| m.to_move())
899 .collect::<Vec<Move>>());
900 on_gameend(
901 cs[(cs_index+1) % 2].clone(),
902 cs[cs_index].clone(),
903 [cs[0].clone(),cs[1].clone()],
904 &sr,
905 SelfMatchGameEndState::Foul(teban,FoulKind::InvalidMove)
906 )?;
907 break;
908 }
909 }
910 prev_move = Some(m)
911 },
912 SelfMatchMessage::NotifyMove(BestMove::Resign) => {
913 kifu_writer(&sfen,&mvs.into_iter()
914 .map(|m| m.to_move())
915 .collect::<Vec<Move>>());
916 on_gameend(
917 cs[(cs_index+1) % 2].clone(),
918 cs[cs_index].clone(),
919 [cs[0].clone(),cs[1].clone()],
920 &sr,
921 SelfMatchGameEndState::Resign(teban)
922 )?;
923 break;
924 },
925 SelfMatchMessage::NotifyMove(BestMove::Abort) => {
926 match self_match_event_queue.lock() {
927 Ok(mut self_match_event_queue) => {
928 self_match_event_queue.push(SelfMatchEvent::Abort);
929 cs[0].send(SelfMatchMessage::Abort)?;
930 cs[1].send(SelfMatchMessage::Abort)?;
931 },
932 Err(ref e) => {
933 let _ = on_error_handler.lock().map(|h| h.call(e));
934 return Err(SelfMatchRunningError::InvalidState(String::from(
935 "Exclusive lock on self_match_event_queue failed."
936 )));
937 }
938 }
939 break;
940 },
941 SelfMatchMessage::NotifyMove(BestMove::Win) if Rule::is_nyugyoku_win(&state,teban,&mc,¤t_time_limit)=> {
942 kifu_writer(&sfen,&mvs.into_iter()
943 .map(|m| m.to_move())
944 .collect::<Vec<Move>>());
945 on_gameend(
946 cs[cs_index].clone(),
947 cs[(cs_index+1) % 2].clone(),
948 [cs[0].clone(),cs[1].clone()],
949 &sr,
950 SelfMatchGameEndState::NyuGyokuWin(teban)
951 )?;
952 break;
953 },
954 SelfMatchMessage::NotifyMove(BestMove::Win) => {
955 kifu_writer(&sfen,&mvs.into_iter()
956 .map(|m| m.to_move())
957 .collect::<Vec<Move>>());
958 on_gameend(
959 cs[(cs_index+1) % 2].clone(),
960 cs[cs_index].clone(),
961 [cs[0].clone(),cs[1].clone()],
962 &sr,
963 SelfMatchGameEndState::NyuGyokuLose(teban)
964 )?;
965 break;
966 },
967 SelfMatchMessage::Error(n) => {
968 return Err(SelfMatchRunningError::PlayerThreadError(n));
969 },
970 SelfMatchMessage::Quit => {
971 quit_notification();
972
973 cs[0].send(SelfMatchMessage::Quit)?;
974 cs[1].send(SelfMatchMessage::Quit)?;
975
976 return Ok(SelfMatchResult {
977 game_count: game_count,
978 elapsed: start_time.elapsed(),
979 start_dt:start_dt,
980 end_dt:Local::now(),
981 });
982 },
983 _ => {
984 return Err(SelfMatchRunningError::InvalidState(String::from(
985 "An invalid message was sent to the self-match management thread."
986 )));
987 }
988 }
989 },
990 recv(timeout) -> message => {
991 match message? {
992 _ => {
993 match user_event_queue[cs_index].lock() {
994 Ok(mut user_event_queue) => {
995 user_event_queue.push(UserEvent::Stop);
996 },
997 Err(ref e) => {
998 let _ = on_error_handler.lock().map(|h| h.call(e));
999 }
1000 }
1001
1002 match timeout_kind {
1003 TimeoutKind::Turn => {
1004 kifu_writer(&sfen,&mvs.into_iter().map(|m| m.to_move()).collect::<Vec<Move>>());
1005 match sr.recv()? {
1006 SelfMatchMessage::NotifyMove(_) => {
1007 on_gameend(
1008 cs[(cs_index+1) % 2].clone(),
1009 cs[cs_index].clone(),
1010 [cs[0].clone(),cs[1].clone()],
1011 &sr,
1012 SelfMatchGameEndState::Timeover(teban))?;
1013
1014 },
1015 _ => {
1016 return Err(SelfMatchRunningError::InvalidState(String::from(
1017 "An invalid message was sent to the self-match management thread."
1018 )));
1019 }
1020 }
1021
1022 break;
1023 },
1024 TimeoutKind::Uptime => {
1025 match sr.recv()? {
1026 SelfMatchMessage::NotifyMove(_) => {
1027 break 'gameloop;
1028 },
1029 _ => {
1030 return Err(SelfMatchRunningError::InvalidState(String::from(
1031 "An invalid message was sent to the self-match management thread."
1032 )));
1033 }
1034 }
1035 },
1036 _ => {
1037 return Err(SelfMatchRunningError::InvalidState(String::from(
1038 "Timeout kind is invalid."
1039 )));
1040 }
1041 }
1042 }
1043 }
1044 }
1045 }
1046 }
1047 }
1048 quit_notification();
1049
1050 cs[0].send(SelfMatchMessage::Quit)?;
1051 cs[1].send(SelfMatchMessage::Quit)?;
1052
1053 Ok(SelfMatchResult {
1054 game_count: game_count,
1055 elapsed: start_time.elapsed(),
1056 start_dt:start_dt,
1057 end_dt:Local::now()
1058 })
1059 }, on_error_handler.clone()).map_err(|e| {
1060 match e {
1061 SelfMatchRunningError::SendError(SendError(SelfMatchMessage::Error(n))) => {
1062 let r = if n == 0 {
1063 cs2.send(SelfMatchMessage::Error(0))
1064 } else {
1065 cs1.send(SelfMatchMessage::Error(1))
1066 };
1067 if let Err(ref e) = r {
1068 let _ = on_error_handler.lock().map(|h| h.call(e));
1069 }
1070 },
1071 SelfMatchRunningError::PlayerThreadError(0) => {
1072 if let Err(ref e) = cs2.send(SelfMatchMessage::Error(0)) {
1073 let _ = on_error_handler.lock().map(|h| h.call(e));
1074 }
1075 },
1076 SelfMatchRunningError::PlayerThreadError(1) => {
1077 if let Err(ref e) = cs1.send(SelfMatchMessage::Error(1)) {
1078 let _ = on_error_handler.lock().map(|h| h.call(e));
1079 }
1080 },
1081 _ => {
1082 if let Err(ref e) = cs1.send(SelfMatchMessage::Error(0)) {
1083 let _ = on_error_handler.lock().map(|h| h.call(e));
1084 }
1085 if let Err(ref e) = cs2.send(SelfMatchMessage::Error(1)) {
1086 let _ = on_error_handler.lock().map(|h| h.call(e));
1087 }
1088 }
1089 }
1090 quit_ready.store(true,Ordering::Release);
1091 e
1092 }));
1093
1094 let mut players = vec![player1,player2];
1095 let mut handlers:Vec<JoinHandle<Result<(),SelfMatchRunningError<E>>>> = Vec::with_capacity(2);
1096
1097 for i in 0..2 {
1098 let cr = cr.remove(0);
1099 let mut player = players.remove(0);
1100 let on_error_handler = on_error_handler_arc.clone();
1101 let logger = logger_arc.clone();
1102 let user_event_queue = [user_event_queue_arc[0].clone(),user_event_queue_arc[1].clone()];
1103 let quit_ready = quit_ready_arc.clone();
1104 let info_sender = info_sender.clone();
1105 let pinfo_sender = pinfo_sender.clone();
1106 let limit = game_time_limit;
1107
1108 let ss = ss.clone();
1109
1110 let player_i = i;
1111
1112 handlers.push(thread::spawn(move || SandBox::immediate(|| {
1113 loop {
1114 match cr.recv()? {
1115 SelfMatchMessage::GameStart => {
1116 let writer = Arc::new(Mutex::new(VoidOutPutWriter));
1117
1118 player.take_ready(OnKeepAlive::new(writer,on_error_handler.clone()))?;
1119 player.newgame()?;
1120
1121 loop {
1122 match cr.recv()? {
1123 SelfMatchMessage::StartThink(t,b,mc,n,m,s) => {
1124 let (ms, mg) = match mc {
1125 MochigomaCollections::Pair(ref ms, ref mg) => {
1126 (ms.clone(),mg.clone())
1127 },
1128 MochigomaCollections::Empty => {
1129 (Mochigoma::new(),Mochigoma::new())
1130 }
1131 };
1132
1133 player.set_position(t, b, ms, mg, n, m.into_iter().map(|m| {
1134 m.to_move()
1135 }).collect::<Vec<Move>>())?;
1136
1137 let m = player.think(s,&limit,
1138 user_event_queue[player_i].clone(),
1139 info_sender.clone(),
1140 pinfo_sender.clone(),
1141 on_error_handler.clone())?;
1142
1143 if !quit_ready.load(Ordering::Acquire) {
1144 ss.send(SelfMatchMessage::NotifyMove(m))?;
1145 }
1146 },
1147 SelfMatchMessage::StartPonderThink(t,b,mc,n,m) => {
1148 let (ms, mg) = match mc {
1149 MochigomaCollections::Pair(ref ms, ref mg) => {
1150 (ms.clone(),mg.clone())
1151 },
1152 MochigomaCollections::Empty => {
1153 (Mochigoma::new(),Mochigoma::new())
1154 }
1155 };
1156
1157 player.set_position(t, b, ms, mg, n, m.into_iter().map(|m| {
1158 m.to_move()
1159 }).collect::<Vec<Move>>())?;
1160
1161 let m = player.think_ponder(&limit,
1162 user_event_queue[player_i].clone(),
1163 info_sender.clone(),
1164 pinfo_sender.clone(),
1165 on_error_handler.clone())?;
1166
1167 match cr.recv()? {
1168 SelfMatchMessage::PonderHit => {
1169 if !quit_ready.load(Ordering::Acquire) {
1170 ss.send(SelfMatchMessage::NotifyMove(m))?;
1171 }
1172 },
1173 SelfMatchMessage::PonderNG => (),
1174 SelfMatchMessage::Quit => {
1175 player.quit()?;
1176
1177 return Ok(());
1178 },
1179 SelfMatchMessage::Abort => {
1180 break;
1181 },
1182 SelfMatchMessage::Error(_) => {
1183 return Ok(());
1184 }
1185 _ => {
1186 let _ = logger.lock().map(|mut logger| {
1187 logger.logging(&format!("Invalid message."))
1188 }).map_err(|_| {
1189 USIStdErrorWriter::write("Logger's exclusive lock could not be secured").unwrap();
1190 false
1191 });
1192
1193 if !quit_ready.load(Ordering::Acquire) {
1194 if !quit_ready.load(Ordering::Acquire) {
1195 ss.send(SelfMatchMessage::Error(player_i))?;
1196 }
1197 }
1198 break;
1199 }
1200 }
1201 },
1202 SelfMatchMessage::GameEnd(s) => {
1203 player.gameover(&s,user_event_queue[player_i].clone(),
1204 on_error_handler.clone())?;
1205
1206 if !quit_ready.load(Ordering::Acquire) {
1207 ss.send(SelfMatchMessage::Ready)?;
1208 }
1209
1210 break;
1211 },
1212 SelfMatchMessage::Abort => {
1213 break;
1214 },
1215 SelfMatchMessage::Quit => {
1216 player.quit()?;
1217
1218 return Ok(());
1219 },
1220 SelfMatchMessage::Error(_) => {
1221 return Ok(());
1222 },
1223 _ => {
1224 let _ = logger.lock().map(|mut logger| {
1225 logger.logging(&format!("Invalid message."))
1226 }).map_err(|_| {
1227 USIStdErrorWriter::write("Logger's exclusive lock could not be secured").unwrap();
1228 false
1229 });
1230
1231 if !quit_ready.load(Ordering::Acquire) {
1232 ss.send(SelfMatchMessage::Error(player_i))?;
1233 }
1234
1235 break;
1236 }
1237 }
1238 }
1239 },
1240 SelfMatchMessage::Quit => {
1241 player.quit()?;
1242
1243 return Ok(());
1244 },
1245 SelfMatchMessage::Error(_) => {
1246 return Ok(());
1247 },
1248 _ => {
1249 let _ = logger.lock().map(|mut logger| {
1250 logger.logging(&format!("Invalid message."))
1251 }).map_err(|_| {
1252 USIStdErrorWriter::write("Logger's exclusive lock could not be secured").unwrap();
1253 false
1254 });
1255
1256 if !quit_ready.load(Ordering::Acquire) {
1257 ss.send(SelfMatchMessage::Error(player_i))?;
1258 }
1259 }
1260 }
1261 }
1262 }, on_error_handler.clone()).map_err(|e| {
1263 match e {
1264 SelfMatchRunningError::SendError(SendError(_)) |
1265 SelfMatchRunningError::RecvError(_) => (),
1266 _ if !quit_ready.load(Ordering::Acquire) => {
1267 if let Err(ref e) = ss.send(SelfMatchMessage::Error(player_i)) {
1268 let _ = on_error_handler.lock().map(|h| h.call(e));
1269 }
1270 },
1271 _ => (),
1272 }
1273 e
1274 })));
1275 }
1276
1277 let delay = Duration::from_millis(50);
1278 let on_error_handler = on_error_handler_arc.clone();
1279 let self_match_event_queue = self_match_event_queue_arc.clone();
1280 let logger = logger_arc.clone();
1281 let quit_ready = quit_ready_arc.clone();
1282
1283 thread::spawn(move || {
1284 while !quit_ready.load(Ordering::Acquire) {
1285 match input_reader.read() {
1286 Ok(Some(line)) => {
1287 match input_handler(line) {
1288 Ok(false) => {
1289 return;
1290 },
1291 Err(ref e) => {
1292 let _ = on_error_handler.lock().map(|h| h.call(e));
1293 return;
1294 },
1295 _ => (),
1296 }
1297 },
1298 Err(ref e) if !quit_ready.load(Ordering::Acquire) => {
1299 let _ = on_error_handler.lock().map(|h| h.call(e));
1300 return;
1301 },
1302 _ => (),
1303 }
1304 }
1305 });
1306
1307 let on_error_handler = on_error_handler_arc.clone();
1308
1309 let quit_ready = quit_ready_arc.clone();
1310
1311 while !quit_ready.load(Ordering::Acquire) || (match self.system_event_queue.lock() {
1312 Ok(system_event_queue) => system_event_queue.has_event(),
1313 Err(ref e) => {
1314 let _ = on_error_handler.lock().map(|h| h.call(e));
1315 false
1316 }
1317 }) || (match self_match_event_queue.lock() {
1318 Ok(self_match_event_queue) => self_match_event_queue.has_event(),
1319 Err(ref e) => {
1320 let _ = on_error_handler.lock().map(|h| h.call(e));
1321 false
1322 }
1323 }) {
1324 match system_event_dispatcher.dispatch_events(self, &*self.system_event_queue) {
1325 Ok(_) => true,
1326 Err(ref e) => {
1327 on_error_handler.lock().map(|h| h.call(e)).is_err()
1328 }
1329 };
1330 match self_match_event_dispatcher.dispatch_events(self, &*self_match_event_queue) {
1331 Ok(_) => true,
1332 Err(ref e) => {
1333 on_error_handler.lock().map(|h| h.call(e)).is_err()
1334 }
1335 };
1336 thread::sleep(delay);
1337 }
1338
1339 let mut has_error = false;
1340
1341 let result = bridge_h.join().map_err(|_| {
1342 has_error = true;
1343 let _ = logger.lock().map(|mut logger| {
1344 logger.logging(&format!("Main thread join failed."))
1345 }).map_err(|_| {
1346 USIStdErrorWriter::write("Logger's exclusive lock could not be secured").unwrap();
1347 false
1348 });
1349 }).unwrap_or(Err(SelfMatchRunningError::ThreadJoinFailed(String::from(
1350 "Main thread join failed."
1351 )))).map_err(|e| {
1352 has_error = true;
1353 e
1354 });
1355
1356 for h in handlers {
1357 let _ = h.join().map_err(|_| {
1358 has_error = true;
1359 let _ = logger.lock().map(|mut logger| {
1360 logger.logging(&format!("Sub thread join failed."))
1361 }).map_err(|_| {
1362 USIStdErrorWriter::write("Logger's exclusive lock could not be secured").unwrap();
1363 false
1364 });
1365 }).map(|r| {
1366 r.map_err(|e| {
1367 has_error = true;
1368 e
1369 }).is_err()
1370 });
1371 }
1372
1373 if has_error {
1374 Err(SelfMatchRunningError::Fail(String::from(
1375 "An error occurred while executing a self match. Please see the log for details ..."
1376 )))
1377 } else {
1378 result
1379 }
1380 }
1381}