use std::{thread,time};
use std::time::Instant;
use std::sync::{atomic, mpsc, Mutex};
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use std::collections::BTreeMap;
use std::fmt;
use std::error::Error;
use std::convert::TryFrom;
use std::sync::mpsc::{Receiver, Sender};
use command::*;
use error::*;
use event::*;
use shogi::*;
use protocol::*;
use rule::*;
use output::*;
use Logger;
use OnErrorHandler;
use crossbeam_channel::{unbounded, after};
pub trait USIPlayer<E>: fmt::Debug where E: PlayerError {
const ID: &'static str;
const AUTHOR: &'static str;
fn get_option_kinds(&mut self) -> Result<BTreeMap<String,SysEventOptionKind>,E>;
fn get_options(&mut self) -> Result<BTreeMap<String,UsiOptType>,E>;
fn take_ready<W,L>(&mut self, on_keep_alive:OnKeepAlive<W,L>)
-> Result<(),E> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static;
fn set_option(&mut self,name:String,value:SysEventOption) -> Result<(),E>;
fn newgame(&mut self) -> Result<(),E>;
fn set_position(&mut self,teban:Teban,ban:Banmen,ms:Mochigoma,mg:Mochigoma,n:u32,m:Vec<Move>)
-> Result<(),E>;
fn think<L,S,P>(&mut self,think_start_time:Instant,limit:&UsiGoTimeLimit,event_queue:Arc<Mutex<UserEventQueue>>,
info_sender:S,periodically_info:P,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
-> Result<BestMove,E> where L: Logger + Send + 'static,
S: InfoSender,
P: PeriodicallyInfo,;
fn think_ponder<L,S,P>(&mut self,limit:&UsiGoTimeLimit,event_queue:Arc<Mutex<UserEventQueue>>,
info_sender:S,periodically_info:P,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
-> Result<BestMove,E> where L: Logger + Send + 'static,
S: InfoSender + Send + 'static,
P: PeriodicallyInfo;
fn think_mate<L,S,P>(&mut self,limit:&UsiGoMateTimeLimit,event_queue:Arc<Mutex<UserEventQueue>>,
info_sender:S,periodically_info:P,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
-> Result<CheckMate,E> where L: Logger + Send + 'static,
S: InfoSender,
P: PeriodicallyInfo;
fn on_stop(&mut self,e:&UserEvent) -> Result<(), E> where E: PlayerError;
fn on_ponderhit(&mut self,e:&UserEvent) -> Result<(), E> where E: PlayerError;
fn gameover<L>(&mut self,s:&GameEndState,
event_queue:Arc<Mutex<UserEventQueue>>,
on_error_handler:Arc<Mutex<OnErrorHandler<L>>>) -> Result<(),E> where L: Logger, Arc<Mutex<OnErrorHandler<L>>>: Send + 'static;
fn on_quit(&mut self,e:&UserEvent) -> Result<(), E> where E: PlayerError;
fn quit(&mut self) -> Result<(),E>;
fn handle_events<'a,L>(&mut self,event_queue:&'a Mutex<UserEventQueue>,
on_error_handler:&Mutex<OnErrorHandler<L>>) -> Result<bool,E>
where L: Logger, E: Error + fmt::Debug,
Arc<Mutex<OnErrorHandler<L>>>: Send + 'static,
EventHandlerError<UserEventKind,E>: From<E> {
Ok(match self.dispatch_events(event_queue,&on_error_handler) {
Ok(_)=> true,
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
false
}
})
}
fn dispatch_events<'a,L>(&mut self, event_queue:&'a Mutex<UserEventQueue>,
on_error_handler:&Mutex<OnErrorHandler<L>>) ->
Result<(), EventDispatchError<'a,UserEventQueue,UserEvent,E>>
where L: Logger, E: Error + fmt::Debug,
Arc<Mutex<OnErrorHandler<L>>>: Send + 'static,
EventHandlerError<UserEventKind,E>: From<E> {
let events = {
event_queue.lock()?.drain_events()
};
let mut has_error = false;
for e in &events {
match e {
&UserEvent::Stop => {
match self.on_stop(e) {
Ok(_) => (),
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
has_error = true;
}
};
},
&UserEvent::PonderHit(_) => {
match self.on_ponderhit(e) {
Ok(_) => (),
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
has_error = true;
}
};
},
&UserEvent::Quit => {
match self.on_quit(e) {
Ok(_) => (),
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
has_error = true;
}
};
}
};
}
match has_error {
true => Err(EventDispatchError::ContainError),
false => Ok(()),
}
}
fn apply_moves<T,F>(&self,mut state:State,
mut teban:Teban,
mut mc:MochigomaCollections,
m:&Vec<AppliedMove>,mut r:T,mut f:F)
-> (Teban,State,MochigomaCollections,T)
where F: FnMut(&Self,Teban,&Banmen,
&MochigomaCollections,&Option<AppliedMove>,
&Option<MochigomaKind>,T) -> T {
for m in m {
match Rule::apply_move_none_check(&state,teban,&mc,*m) {
(next,nmc,o) => {
r = f(self,teban,&state.get_banmen(),&mc,&Some(*m),&o,r);
state = next;
mc = nmc;
teban = teban.opposite();
}
}
}
r = f(self,teban,&state.get_banmen(),&mc,&None,&None,r);
(teban,state,mc,r)
}
}
#[derive(Clone, Debug)]
pub enum UsiInfoMessage {
Commands(Vec<UsiInfoSubCommand>),
Flush,
Quit,
}
pub trait InfoSender: Clone + Send + 'static {
fn send(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError>;
fn send_immediate(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError>;
fn flush(&mut self) -> Result<(), InfoSendError> {
Ok(())
}
}
pub struct USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
worker:InfoSendWorker<W>
}
impl<W> USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
pub fn new(worker:InfoSendWorker<W>) -> USIInfoSender<W> {
USIInfoSender {
worker:worker
}
}
}
impl<W> InfoSender for USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
fn send(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
if let Err(_) = self.worker.sender.send(UsiInfoMessage::Commands(commands)) {
Err(InfoSendError::Fail(String::from(
"info command send failed.")))
} else {
Ok(())
}
}
fn send_immediate(&mut self, commands: Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
self.send(commands)?;
Ok(self.flush()?)
}
fn flush(&mut self) -> Result<(), InfoSendError> {
if let Err(_) = self.worker.sender.send(UsiInfoMessage::Flush) {
Err(InfoSendError::Fail(String::from(
"info sender buffer flush failed.")))
} else {
Ok(())
}
}
}
impl<W> Clone for USIInfoSender<W> where W: USIOutputWriter + Send + 'static {
fn clone(&self) -> USIInfoSender<W> {
USIInfoSender::new(self.worker.clone())
}
}
pub struct InfoSendWorker<W> where W: USIOutputWriter {
sender:Sender<UsiInfoMessage>,
writer:Arc<Mutex<W>>,
quited:Arc<AtomicBool>
}
const INFO_SEND_BUFFER_SIZE:usize = 100;
impl<W> InfoSendWorker<W> where W: USIOutputWriter {
pub fn new<L>(writer:Arc<Mutex<W>>,
notifier:Sender<()>,
on_error_handler:Arc<Mutex<OnErrorHandler<L>>>)
-> InfoSendWorker<W> where L: Logger,
Arc<Mutex<W>>: Send + 'static,
Arc<Mutex<OnErrorHandler<L>>>: Send + 'static {
let mut buffer = Vec::with_capacity(INFO_SEND_BUFFER_SIZE);
let (sender,receiver) = mpsc::channel();
{
let writer = writer.clone();
thread::spawn(move || {
loop {
match receiver.recv() {
Ok(UsiInfoMessage::Commands(commands)) => {
let command = match UsiInfoCommand(commands).to_usi_command() {
Ok(command) => command,
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
break;
}
};
buffer.push(command);
if buffer.len() >= INFO_SEND_BUFFER_SIZE {
match writer.lock() {
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
break;
},
Ok(ref writer) => {
if let Err(ref e) = writer.write(&buffer) {
let _ = on_error_handler.lock().map(|h| h.call(e));
break;
}
buffer.clear();
}
}
}
},
Ok(UsiInfoMessage::Flush) => {
if buffer.len() > 0 {
match writer.lock() {
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
},
Ok(ref writer) => {
if let Err(ref e) = writer.write(&buffer) {
let _ = on_error_handler.lock().map(|h| h.call(e));
}
}
}
}
},
Ok(UsiInfoMessage::Quit) => {
if buffer.len() > 0 {
match writer.lock() {
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
},
Ok(ref writer) => {
if let Err(ref e) = writer.write(&buffer) {
let _ = on_error_handler.lock().map(|h| h.call(e));
}
}
}
}
break;
},
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
break;
}
}
}
if let Err(ref e) = notifier.send(()) {
let _ = on_error_handler.lock().map(|h| h.call(e));
}
});
}
InfoSendWorker {
sender:sender,
writer:writer,
quited:Arc::new(AtomicBool::new(false))
}
}
pub fn quit(&self,receiver:Receiver<()>) -> Result<(), InfoSendWorkerError> {
if !self.quited.swap(true,atomic::Ordering::Release) {
self.sender.send(UsiInfoMessage::Quit)?;
receiver.recv()?;
}
Ok(())
}
}
impl<W> Clone for InfoSendWorker<W> where W: USIOutputWriter {
fn clone(&self) -> Self {
InfoSendWorker {
sender:self.sender.clone(),
writer:self.writer.clone(),
quited:self.quited.clone()
}
}
}
pub struct ConsoleInfoSender {
writer:USIStdOutputWriter,
silent:bool,
}
impl ConsoleInfoSender {
pub fn new(silent:bool) -> ConsoleInfoSender {
ConsoleInfoSender {
writer:USIStdOutputWriter::new(),
silent:silent
}
}
}
impl InfoSender for ConsoleInfoSender {
fn send(&mut self,commands:Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
if !self.silent {
let lines = vec![commands.to_usi_command()?];
if let Err(_) = self.writer.write(&lines) {
return Err(InfoSendError::Fail(String::from(
"info command send failed.")))
}
}
Ok(())
}
fn send_immediate(&mut self, commands: Vec<UsiInfoSubCommand>) -> Result<(), InfoSendError> {
self.send(commands)
}
}
impl Clone for ConsoleInfoSender {
fn clone(&self) -> ConsoleInfoSender {
ConsoleInfoSender::new(self.silent)
}
}
pub trait KeepAliveSender {
fn send(&self);
#[must_use]
fn auto(&self,sec:u64) -> AutoKeepAlive;
}
pub struct OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
writer:Arc<Mutex<W>>,
on_error_handler:Arc<Mutex<OnErrorHandler<L>>>
}
impl<W,L> OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
pub fn new(writer:Arc<Mutex<W>>,on_error_handler:Arc<Mutex<OnErrorHandler<L>>>) -> OnKeepAlive<W,L> {
OnKeepAlive {
writer:writer,
on_error_handler:on_error_handler
}
}
}
impl<W,L> KeepAliveSender for OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
fn send(&self) {
match self.writer.lock() {
Err(ref e) => {
let _ = self.on_error_handler.lock().map(|h| h.call(e));
},
Ok(ref writer) => {
if let Err(ref e) = writer.write(&vec![String::from("")]) {
let _ = self.on_error_handler.lock().map(|h| h.call(e));
}
}
};
}
#[must_use]
fn auto(&self,sec:u64) -> AutoKeepAlive {
AutoKeepAlive::new(sec,self.clone())
}
}
impl<W,L> Clone for OnKeepAlive<W,L> where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
fn clone(&self) -> OnKeepAlive<W,L> {
OnKeepAlive {
writer:self.writer.clone(),
on_error_handler:self.on_error_handler.clone()
}
}
}
pub struct AutoKeepAlive {
stop_sender:crossbeam_channel::Sender<()>
}
impl AutoKeepAlive {
fn new<W,L>(sec:u64,on_keep_alive: OnKeepAlive<W,L>)
-> AutoKeepAlive where W: USIOutputWriter + Send + 'static, L: Logger + Send + 'static {
let(s,r) = unbounded();
std::thread::spawn(move || {
let mut timeout = after(time::Duration::from_secs(sec));
loop {
select! {
recv(r) -> _ => {
return;
},
recv(timeout) -> _ => {
on_keep_alive.send();
timeout = after(time::Duration::from_secs(sec));
}
}
}
});
AutoKeepAlive {
stop_sender:s
}
}
}
impl Drop for AutoKeepAlive {
fn drop(&mut self) {
let _ = self.stop_sender.send(());
}
}
pub struct PeriodicallyInfoSender {
stop_sender:crossbeam_channel::Sender<()>,
}
impl PeriodicallyInfoSender {
pub fn new(stop_sender:crossbeam_channel::Sender<()>) -> PeriodicallyInfoSender {
PeriodicallyInfoSender {
stop_sender:stop_sender
}
}
}
impl Drop for PeriodicallyInfoSender {
fn drop(&mut self) {
let _ = self.stop_sender.send(());
}
}
pub trait PeriodicallyInfo: Send + 'static {
#[must_use]
fn start<F,L>(self,interval:u64,info_generator:F,on_error_handler:&Arc<Mutex<OnErrorHandler<L>>>)
-> PeriodicallyInfoSender where F: FnMut() -> Vec<UsiInfoSubCommand> + Sized + Send + 'static,
L: Logger + Send + 'static;
}
pub struct USIPeriodicallyInfo<W> where W: USIOutputWriter + Send + 'static {
writer:Arc<Mutex<W>>,
silent:bool
}
impl<W> USIPeriodicallyInfo<W>
where W: USIOutputWriter + Send + 'static {
pub fn new(writer:Arc<Mutex<W>>,silent:bool) -> USIPeriodicallyInfo<W> {
USIPeriodicallyInfo {
writer:writer,
silent:silent
}
}
}
impl<W> PeriodicallyInfo for USIPeriodicallyInfo<W>
where W: USIOutputWriter + Send + 'static {
#[must_use]
fn start<F,L>(self,interval:u64,info_generator:F,on_error_handler:&Arc<Mutex<OnErrorHandler<L>>>)
-> PeriodicallyInfoSender where F: FnMut() -> Vec<UsiInfoSubCommand> + Send + 'static,
L: Logger + Send + 'static {
let (s,r) = unbounded();
let writer = self.writer.clone();
let mut info_generator = info_generator;
let silent = self.silent;
let on_error_handler = on_error_handler.clone();
std::thread::spawn(move || {
let mut timeout = after(time::Duration::from_millis(interval));
loop {
select! {
recv(r) -> _ => {
return;
},
recv(timeout) -> _ => {
match UsiOutput::try_from(&UsiCommand::UsiInfo(info_generator())) {
Ok(UsiOutput::Command(ref s)) => {
match writer.lock() {
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
break;
},
Ok(ref writer) => {
if !silent {
let _ = writer.write(s).map_err(|e| on_error_handler.lock().map(|h| h.call(&e)));
}
}
};
},
Err(ref e) => {
let _ = on_error_handler.lock().map(|h| h.call(e));
break;
}
}
timeout = after(time::Duration::from_millis(interval));
}
}
}
});
PeriodicallyInfoSender::new(s)
}
}
impl<W> Clone for USIPeriodicallyInfo<W> where W: USIOutputWriter + Send + 'static {
fn clone(&self) -> USIPeriodicallyInfo<W> {
USIPeriodicallyInfo {
writer:self.writer.clone(),
silent:self.silent
}
}
}
pub struct ConsolePeriodicallyInfo {
inner:USIPeriodicallyInfo<USIStdOutputWriter>
}
impl ConsolePeriodicallyInfo {
pub fn new(silent:bool) -> ConsolePeriodicallyInfo {
ConsolePeriodicallyInfo {
inner:USIPeriodicallyInfo::new(
Arc::new(Mutex::new(USIStdOutputWriter::new())),
silent
)
}
}
}
impl PeriodicallyInfo for ConsolePeriodicallyInfo {
#[must_use]
fn start<F,L>(self,interval:u64,info_generator:F,on_error_handler:&Arc<Mutex<OnErrorHandler<L>>>)
-> PeriodicallyInfoSender where F: FnMut() -> Vec<UsiInfoSubCommand> + Send + 'static,
L: Logger + Send + 'static {
self.inner.start(interval,info_generator,on_error_handler)
}
}
impl Clone for ConsolePeriodicallyInfo {
fn clone(&self) -> ConsolePeriodicallyInfo {
ConsolePeriodicallyInfo {
inner:self.inner.clone()
}
}
}