WIP
This commit is contained in:
		
							parent
							
								
									c7b9544004
								
							
						
					
					
						commit
						90ee3e416f
					
				
					 7 changed files with 344 additions and 2 deletions
				
			
		
							
								
								
									
										6
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								Cargo.lock
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -72,6 +72,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
				
			||||||
name = "chessfriend"
 | 
					name = "chessfriend"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
dependencies = [
 | 
					dependencies = [
 | 
				
			||||||
 | 
					 "chessfriend_core",
 | 
				
			||||||
 | 
					 "chessfriend_moves",
 | 
				
			||||||
 | 
					 "chessfriend_position",
 | 
				
			||||||
 | 
					 "clap",
 | 
				
			||||||
 | 
					 "shlex",
 | 
				
			||||||
 | 
					 "thiserror",
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[package]]
 | 
					[[package]]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,3 +3,10 @@ name = "chessfriend"
 | 
				
			||||||
version = "0.1.0"
 | 
					version = "0.1.0"
 | 
				
			||||||
edition = "2024"
 | 
					edition = "2024"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					chessfriend_core = { path = "../core" }
 | 
				
			||||||
 | 
					chessfriend_moves = { path = "../moves" }
 | 
				
			||||||
 | 
					chessfriend_position = { path = "../position" }
 | 
				
			||||||
 | 
					clap = { version = "4.4.12", features = ["derive"] }
 | 
				
			||||||
 | 
					shlex = "1.2.0"
 | 
				
			||||||
 | 
					thiserror = "2"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										87
									
								
								chessfriend/src/chessfriend.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								chessfriend/src/chessfriend.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					// Eryn Wells <eryn@erynwells.me>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    core::{Piece, Square},
 | 
				
			||||||
 | 
					    position::{MakeMoveError, Move, ValidateMove},
 | 
				
			||||||
 | 
					    threadpool::ThreadPool,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use chessfriend_core::random::RandomNumberGenerator;
 | 
				
			||||||
 | 
					use chessfriend_position::{
 | 
				
			||||||
 | 
					    PlacePieceError, PlacePieceStrategy, Position, ZobristState, fen::FromFenStr,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use std::{num::NonZero, sync::Arc};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct ChessFriend {
 | 
				
			||||||
 | 
					    /// A pool of worker threads over which tasks may be distributed.
 | 
				
			||||||
 | 
					    thread_pool: ThreadPool,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    zobrist_state: Arc<ZobristState>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// A global Position for the engine.
 | 
				
			||||||
 | 
					    position: Position,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ChessFriend {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn new(options: Options) -> Self {
 | 
				
			||||||
 | 
					        let mut rng = RandomNumberGenerator::default();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let zobrist_state = Arc::new(ZobristState::new(&mut rng));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let position = match options.initial_position {
 | 
				
			||||||
 | 
					            InitialPosition::Empty => Position::empty(Some(zobrist_state.clone())),
 | 
				
			||||||
 | 
					            InitialPosition::Starting => Position::starting(Some(zobrist_state.clone())),
 | 
				
			||||||
 | 
					            InitialPosition::Fen(fen) => {
 | 
				
			||||||
 | 
					                let mut position = Position::from_fen_str(fen).unwrap_or_default();
 | 
				
			||||||
 | 
					                position.set_zobrist_state(zobrist_state.clone());
 | 
				
			||||||
 | 
					                position
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let thread_pool = ThreadPool::new(options.threading.0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            thread_pool,
 | 
				
			||||||
 | 
					            zobrist_state,
 | 
				
			||||||
 | 
					            position,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ChessFriend {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Default, Eq, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Options<'a> {
 | 
				
			||||||
 | 
					    initial_position: InitialPosition<'a>,
 | 
				
			||||||
 | 
					    threading: Threading,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Default, Eq, PartialEq)]
 | 
				
			||||||
 | 
					pub enum InitialPosition<'a> {
 | 
				
			||||||
 | 
					    Empty,
 | 
				
			||||||
 | 
					    #[default]
 | 
				
			||||||
 | 
					    Starting,
 | 
				
			||||||
 | 
					    Fen(&'a str),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Eq, PartialEq)]
 | 
				
			||||||
 | 
					pub struct Threading(NonZero<usize>);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Threading {
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn new(n: NonZero<usize>) -> Self {
 | 
				
			||||||
 | 
					        Self(n)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[must_use]
 | 
				
			||||||
 | 
					    pub fn new_with_available_parallelism() -> Self {
 | 
				
			||||||
 | 
					        const ONE: NonZero<usize> = NonZero::new(1).unwrap();
 | 
				
			||||||
 | 
					        Self(std::thread::available_parallelism().unwrap_or(ONE))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for Threading {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self::new_with_available_parallelism()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,2 +1,19 @@
 | 
				
			||||||
// Eryn Wells <eryn@erynwells.me>
 | 
					// Eryn Wells <eryn@erynwells.me>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod chessfriend;
 | 
				
			||||||
 | 
					mod threadpool;
 | 
				
			||||||
 | 
					mod uci;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub use crate::chessfriend::ChessFriend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod options {
 | 
				
			||||||
 | 
					    pub use crate::chessfriend::{InitialPosition, Options, Threading};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod core {
 | 
				
			||||||
 | 
					    pub use chessfriend_core::{Color, Piece, Shape, Square};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub mod position {
 | 
				
			||||||
 | 
					    pub use chessfriend_moves::{MakeMoveError, Move, ValidateMove};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										77
									
								
								chessfriend/src/threadpool.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								chessfriend/src/threadpool.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,77 @@
 | 
				
			||||||
 | 
					// Eryn Wells <eryn@erynwells.me>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    num::NonZero,
 | 
				
			||||||
 | 
					    panic,
 | 
				
			||||||
 | 
					    sync::{Arc, Mutex, mpsc},
 | 
				
			||||||
 | 
					    thread,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) trait Job: FnOnce() + Send + 'static {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) struct ThreadPool {
 | 
				
			||||||
 | 
					    workers: Vec<Worker>,
 | 
				
			||||||
 | 
					    sender: Option<mpsc::Sender<Box<dyn Job>>>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl ThreadPool {
 | 
				
			||||||
 | 
					    pub fn new(threads_count: NonZero<usize>) -> Self {
 | 
				
			||||||
 | 
					        let (sender, receiver) = mpsc::channel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let receiver = Arc::new(Mutex::new(receiver));
 | 
				
			||||||
 | 
					        let workers: Vec<_> = (0..threads_count.into())
 | 
				
			||||||
 | 
					            .map(|i| Worker::new(i, receiver.clone()))
 | 
				
			||||||
 | 
					            .collect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            workers,
 | 
				
			||||||
 | 
					            sender: Some(sender),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Drop for ThreadPool {
 | 
				
			||||||
 | 
					    fn drop(&mut self) {
 | 
				
			||||||
 | 
					        drop(self.sender.take());
 | 
				
			||||||
 | 
					        self.workers.drain(..).for_each(Worker::join);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Worker {
 | 
				
			||||||
 | 
					    id: usize,
 | 
				
			||||||
 | 
					    handle: thread::JoinHandle<()>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Worker {
 | 
				
			||||||
 | 
					    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Box<dyn Job>>>>) -> Self {
 | 
				
			||||||
 | 
					        // TODO: A note from the Rust Programming Language
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					        // Note: If the operating system can’t create a thread because there
 | 
				
			||||||
 | 
					        // aren’t enough system resources, thread::spawn will panic. That will
 | 
				
			||||||
 | 
					        // cause our whole server to panic, even though the creation of some
 | 
				
			||||||
 | 
					        // threads might succeed. For simplicity’s sake, this behavior is fine,
 | 
				
			||||||
 | 
					        // but in a production thread pool implementation, you’d likely want to
 | 
				
			||||||
 | 
					        // use std::thread::Builder and its spawn method that returns Result
 | 
				
			||||||
 | 
					        // instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let handle = thread::spawn(move || {
 | 
				
			||||||
 | 
					            loop {
 | 
				
			||||||
 | 
					                let job = {
 | 
				
			||||||
 | 
					                    let receiver = receiver.lock().unwrap();
 | 
				
			||||||
 | 
					                    receiver.recv().unwrap()
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                job();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Self { id, handle }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn join(self) {
 | 
				
			||||||
 | 
					        match self.handle.join() {
 | 
				
			||||||
 | 
					            Ok(()) => {}
 | 
				
			||||||
 | 
					            Err(error) => panic::resume_unwind(error),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										148
									
								
								chessfriend/src/uci.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								chessfriend/src/uci.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,148 @@
 | 
				
			||||||
 | 
					// Eryn Wells <eryn@erynwells.me>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use clap::{Error as ClapError, Parser, Subcommand, ValueEnum};
 | 
				
			||||||
 | 
					use std::{
 | 
				
			||||||
 | 
					    fmt::Display,
 | 
				
			||||||
 | 
					    io::{BufRead, Write},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Parser, Debug)]
 | 
				
			||||||
 | 
					#[command(multicall = true)]
 | 
				
			||||||
 | 
					pub struct Uci {
 | 
				
			||||||
 | 
					    #[command(subcommand)]
 | 
				
			||||||
 | 
					    command: Command,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Subcommand)]
 | 
				
			||||||
 | 
					enum Command {
 | 
				
			||||||
 | 
					    /// Establish UCI (Universal Chess Interface) as the channel's exchange protocol.
 | 
				
			||||||
 | 
					    Uci,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Toggle debug state on or off.
 | 
				
			||||||
 | 
					    Debug { state: DebugState },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Synchronize the engine with the client. Can also be used as a 'ping'.
 | 
				
			||||||
 | 
					    IsReady,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Stop calculating as soon as possible.
 | 
				
			||||||
 | 
					    Stop,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Stop all processing and quit the program.
 | 
				
			||||||
 | 
					    Quit,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy, Debug, Eq, PartialEq, ValueEnum)]
 | 
				
			||||||
 | 
					enum DebugState {
 | 
				
			||||||
 | 
					    On,
 | 
				
			||||||
 | 
					    Off,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum Response<'a> {
 | 
				
			||||||
 | 
					    /// Declares one aspect of the engine's identity.
 | 
				
			||||||
 | 
					    Id(IdValue<'a>),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Declares that communicating in UCI is acceptable.
 | 
				
			||||||
 | 
					    UciOk,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Declares that the engine is ready to receive commands from the client.
 | 
				
			||||||
 | 
					    ReadyOk,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for Response<'_> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Response::Id(value) => write!(f, "id {value}"),
 | 
				
			||||||
 | 
					            Response::UciOk => write!(f, "uciok"),
 | 
				
			||||||
 | 
					            Response::ReadyOk => write!(f, "readyok"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum IdValue<'a> {
 | 
				
			||||||
 | 
					    Name(&'a str),
 | 
				
			||||||
 | 
					    Author(&'a str),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Display for IdValue<'_> {
 | 
				
			||||||
 | 
					    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            IdValue::Name(name) => write!(f, "name {name}"),
 | 
				
			||||||
 | 
					            IdValue::Author(author) => write!(f, "author {author}"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub enum Error {
 | 
				
			||||||
 | 
					    #[error("unable to parse command")]
 | 
				
			||||||
 | 
					    LexError,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[error("{0}")]
 | 
				
			||||||
 | 
					    ClapError(#[from] ClapError),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Uci {
 | 
				
			||||||
 | 
					    /// Respond to a command.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// ## Errors
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Returns an error if parsing the command string fails, otherwise returns an array of
 | 
				
			||||||
 | 
					    /// responses.
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    pub fn respond(line: &str) -> Result<Vec<Response>, Error> {
 | 
				
			||||||
 | 
					        let arguments = shlex::split(line).ok_or(Error::LexError)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let interface = Self::try_parse_from(arguments)?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        match interface.command {
 | 
				
			||||||
 | 
					            Command::Uci => {
 | 
				
			||||||
 | 
					                const IDENTITIES: [Response; 2] = [
 | 
				
			||||||
 | 
					                    Response::Id(IdValue::Name("ChessFriend")),
 | 
				
			||||||
 | 
					                    Response::Id(IdValue::Author("Eryn Wells")),
 | 
				
			||||||
 | 
					                ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                let options: Vec<Response> = vec![];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                Ok(IDENTITIES.into_iter().chain(options).collect())
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Command::Debug { state: _ } => Ok(vec![]),
 | 
				
			||||||
 | 
					            Command::IsReady => Ok(vec![Response::ReadyOk]),
 | 
				
			||||||
 | 
					            Command::Stop => Ok(vec![]),
 | 
				
			||||||
 | 
					            Command::Quit => Ok(vec![]),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct UciInterface {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl UciInterface {
 | 
				
			||||||
 | 
					    pub fn read_until_quit(
 | 
				
			||||||
 | 
					        &self,
 | 
				
			||||||
 | 
					        input: impl BufRead,
 | 
				
			||||||
 | 
					        output: &mut impl Write,
 | 
				
			||||||
 | 
					    ) -> Result<(), UciInterfaceError> {
 | 
				
			||||||
 | 
					        for line in input.lines() {
 | 
				
			||||||
 | 
					            let line = line?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let responses = Uci::respond(line.as_str())?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // TODO: Dispatch command to background processing thread.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for r in responses {
 | 
				
			||||||
 | 
					                write!(output, "{r}")?;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Ok(())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Error)]
 | 
				
			||||||
 | 
					pub enum UciInterfaceError {
 | 
				
			||||||
 | 
					    #[error("io error: {0}")]
 | 
				
			||||||
 | 
					    IoError(#[from] std::io::Error),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[error("uci error: {0}")]
 | 
				
			||||||
 | 
					    UciError(#[from] Error),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -5,8 +5,8 @@ mod position;
 | 
				
			||||||
#[macro_use]
 | 
					#[macro_use]
 | 
				
			||||||
mod macros;
 | 
					mod macros;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub use chessfriend_board::{fen, PlacePieceError, PlacePieceStrategy};
 | 
					pub use chessfriend_board::{fen, PlacePieceError, PlacePieceStrategy, ZobristState};
 | 
				
			||||||
pub use chessfriend_moves::{GeneratedMove, ValidateMove};
 | 
					pub use chessfriend_moves::{GeneratedMove, Move, ValidateMove};
 | 
				
			||||||
pub use position::Position;
 | 
					pub use position::Position;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub mod perft;
 | 
					pub mod perft;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue