use std::str::FromStr;
use anyhow::Context;
use crate::{
play::{Plae, Vertex},
role::Role,
time,
};
#[allow(clippy::doc_markdown)]
#[derive(Debug, Clone)]
pub enum Message {
BoardSize(usize),
Empty,
FinalStatus,
GenerateMove,
KnownCommand(String),
ListCommands,
Name,
Play(Plae),
PlayFrom,
PlayTo((Role, Vertex)),
ProtocolVersion,
Quit,
ShowBoard,
TimeSettings(time::TimeSettings),
Version,
}
pub static COMMANDS: [&str; 14] = [
"board_size",
"final_status",
"generate_move",
"known_command",
"list_commands",
"name",
"play",
"play_from",
"play_to",
"protocol_version",
"quit",
"show_board",
"time_settings",
"version",
];
impl FromStr for Message {
type Err = anyhow::Error;
fn from_str(message: &str) -> anyhow::Result<Self> {
let args: Vec<&str> = message.split_whitespace().collect();
let Some(first) = args.first() else {
return Ok(Self::Empty);
};
match *first {
"board_size" => Ok(Self::BoardSize(
(*args
.get(1)
.context("expected: board_size 11 or board_size 13")?)
.parse()?,
)),
"final_status" => Ok(Self::FinalStatus),
"generate_move" => Ok(Self::GenerateMove),
"known_command" => Ok(Self::KnownCommand(
(*args.get(1).context("expected: known_command COMMAND")?).to_string(),
)),
"list_commands" => Ok(Self::ListCommands),
"name" => Ok(Self::Name),
"play" => {
let play = Plae::try_from(args)?;
Ok(Self::Play(play))
}
"play_from" => Ok(Self::PlayFrom),
"play_to" => {
if let (Some(role), Some(vertex)) = (args.get(1), args.get(2)) {
let role = Role::from_str(role)?;
let vertex = Vertex::from_str(vertex)?;
Ok(Self::PlayTo((role, vertex)))
} else {
Err(anyhow::Error::msg("expected: play_to role vertex"))
}
}
"protocol_version" => Ok(Self::ProtocolVersion),
"quit" => Ok(Self::Quit),
"show_board" => Ok(Self::ShowBoard),
"time_settings" => {
let time_settings = time::TimeSettings::try_from(args)?;
Ok(Self::TimeSettings(time_settings))
}
"version" => Ok(Self::Version),
text => {
if text.trim().is_empty() {
Ok(Self::Empty)
} else {
Err(anyhow::Error::msg(format!("unrecognized command: {text}")))
}
}
}
}
}