From 428da563ddc22dd649c83af715485153af105d02 Mon Sep 17 00:00:00 2001 From: Taylor Bockman Date: Sun, 17 Dec 2017 14:11:30 -0800 Subject: [PATCH] SOme issue with backslash escaping --- README.md | 22 +++++++++++++++++++--- src/lib.rs | 9 +++------ src/options.rs | 4 +++- tests/lib.rs | 49 ++++++++++++++++++++++++++++++++++++------------- 4 files changed, 61 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 6175c62..d690619 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,18 @@ Next, you'll need to create a copy of `Engine` by calling `Engine::new`. Once th `Engine::identify` to send identification information to the GUI. Once identification is done, you need to send your configuration options. This is dependent on your engine. Refer to -the UCI standard for the available options: - -```EXAMPLE OF CONFIGURATION OF OPTIONS``` +the UCI standard for the available options. Here is an example of an option configuration: + +```rust + let o1 = EngineOption { + name: constants::HASH, + option_type: EngineOptionType::Spin, + option_data: [(EngineOptionDataType::DefaultVal, EngineOptionData::Int(1)), + (EngineOptionDataType::Min, EngineOptionData::Int(1)), + (EngineOptionDataType::Max, EngineOptionData::Int(128)) + ].iter().cloned().collect(); + }; +``` As nice as it would be to have fully typechecked options you will need to be careful a little here. The available options your engine uses must be passed to `Engine::new` as an array of `Options::EngineOption` @@ -115,3 +124,10 @@ an `isready` command which you will be responsible for replying to by using `Eng ** TODO: Put an example engine under `/examples` that does nothing but talks to the GUI and receives commands. ** Document it here and mention it can be used for guidance. + + +### Other Libraries in the works + +In the future more libraries will be available to help chess engine developers get started. I will be writing +a library to give some standard implementations of [Zobrist Hashing](https://en.wikipedia.org/wiki/Zobrist_hashing), +among other useful tools that are commonly re-implemented a thousand times for every engine. diff --git a/src/lib.rs b/src/lib.rs index d65a971..eedebb4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -69,12 +69,9 @@ where /// Sends all available options in the options configuration and a final UCIOK meaning we are reading to go. pub fn send_available_options(&mut self) { - // NOTE: Options can be represented as an array of EngineOption in the options.rs - // file and values are the associated options. - // This function will construct the proper string from the objects. - // Construct the strings using the `option_string` function of each engine option. Let it tell you - // what it is. - // TODO: This needs to be tested majorly + for eo in &self.engine_options { + write!(&mut self.writer, "{}", eo.to_string()).expect(&format!("failed to send `{}`", eo.to_string())); + } // Again this command must complete before we can say the engine is connected, so panicking at this stage is ok write!(&mut self.writer, "{}", commands::UCIOK).expect("failed to send `uciok` command"); diff --git a/src/options.rs b/src/options.rs index e712afe..483b872 100644 --- a/src/options.rs +++ b/src/options.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; use commands; +/// These constants can be used for naming options easily. Option name is fairly flexible. pub mod constants { /// Represents the hash option @@ -98,7 +99,8 @@ impl EngineOption { } } - pub fn option_string(&self) -> String { + /// Turns the EngineOption into a string that can be sent to the GUI + pub fn to_string(&self) -> String { let mut option_data_string: String = String::new(); // NOTE: The user is left to understand what option takes which of these data type values. There's some diff --git a/tests/lib.rs b/tests/lib.rs index ca7169f..6af9d78 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -25,10 +25,6 @@ fn send_identification_data() { let mut e = Engine::new("test_name", "test", &input[..], &mut output, vec!()); e.identify(); } - - // NOTE: This looks weird bceause you'd think it would store each insertion into the output buffer - // as a separate element of that buffer, but it really just appends the two strings since in reality - // the buffer would be flushed after reading. assert_eq!(str::from_utf8(&output).unwrap_or("Unwrapping output failed in send_identification_data"), "id name test_name\nid author test\n"); } @@ -86,19 +82,46 @@ fn engine_option_string() { (EngineOptionDataType::Max, EngineOptionData::Int(128)) ].iter().cloned().collect(); - let o = EngineOption { - name: name, - option_type: option_type, - option_data: option_data, - }; + let o = EngineOption { name, option_type, option_data, }; let expected = "option name Hash type spin default 1 min 1 max 128\n"; - assert_eq!(o.option_string(), expected); + assert_eq!(o.to_string(), expected); } #[test] fn send_available_engine_options() { - // This should send two to three options and check the string in the - // buffer to make sure it's correct. - assert_eq!(true, false); + let input = b"UNUSED"; + let mut output = Vec::new(); + + let o1 = EngineOption { + name: constants::HASH, + option_type: EngineOptionType::Spin, + option_data: [(EngineOptionDataType::DefaultVal, EngineOptionData::Int(1)), + (EngineOptionDataType::Min, EngineOptionData::Int(1)), + (EngineOptionDataType::Max, EngineOptionData::Int(128)) + ].iter().cloned().collect(), + }; + + let o2 = EngineOption { + name: constants::NALIMOVPATH, + option_type: EngineOptionType::TypeString, + option_data: [(EngineOptionDataType::DefaultVal, EngineOptionData::Text(String::from(r"c:\"))), + ].iter().cloned().collect(), + }; + + let o3 = EngineOption { + name: "Clear Hash", + option_type: EngineOptionType::Button, + option_data: [].iter().cloned().collect(), + }; + + { + let mut e = Engine::new("test_name", "test", &input[..], &mut output, vec!(o1, o2, o3)); + e.send_available_options(); + } + assert_eq!(str::from_utf8(&output).unwrap_or("Unwrapping output failed in send_identification_data"), + "option name Hash type spin default 1 min 1 max 128\n\ + option name NalimovPath type string default c:\n\ + option name Clear Hash type button\n\ + uciok\n"); }