Want to contribute? Fork me on Codeberg.org!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

114 lines
3.3 KiB

// ---------------
// Module overview
// ---------------
//
// RoomSettings: Stores database settings for room.
// In future, could store passphrase, etc.
//
// Room: Game state abstracted away from any networking.
// Any events that aren't game-related are handled by Server.
use crate::database::{Database, DatabaseCreationError, DatabaseSettings};
use crate::dictionary::lookup;
use crate::response::MessageResponseData;
use crate::utils::{get_final_mora, get_starting_mora};
use crate::word::Word;
use wana_kana::{ConvertJapanese, IsJapaneseStr};
pub struct RoomSettings {
pub name: String,
pub database_settings: DatabaseSettings,
}
pub struct Room {
name: String,
database: Database,
next_mora: Option<String>,
last_client_id: Option<u64>,
}
impl Room {
pub fn new(settings: RoomSettings) -> Result<Self, DatabaseCreationError> {
Ok(Self {
name: settings.name,
database: Database::new(settings.database_settings)?,
next_mora: None,
last_client_id: None,
})
}
pub fn name(&self) -> &str {
&self.name
}
pub fn next_mora(&self) -> &Option<String> {
&self.next_mora
}
pub fn get_history(&self) -> rusqlite::Result<Vec<Word>> {
self.database
.load_words_before(self.database.last_word_id + 1)
}
// Err(&str) will be converted to MessageResponseData::Error
pub fn handle_query(
&mut self,
query: &str,
client_id: u64,
) -> Result<MessageResponseData, &str> {
// Ensure query isn't from last player
if Some(client_id) == self.last_client_id {
return Err("It's not your turn!");
};
// Ensure query is in Japanese
let query = query.to_string();
let query = if query.is_japanese() {
query
} else {
let kana = query.to_kana();
if kana.is_japanese() {
kana
} else {
return Err("Not Japanese!");
}
};
// Look up word in dictionary
let dictionary_result = lookup(&query);
// Send result
match dictionary_result {
Some(entry) => {
if entry
.reading
.chars()
.last()
.unwrap()
.to_string()
.to_hiragana()
== "ん"
{
Err("Can't end with ん!")
} else if self.next_mora.is_none()
|| get_starting_mora(&entry.reading).eq(self.next_mora.as_deref().unwrap())
{
let word: Word = entry.into();
self.next_mora = Some(get_final_mora(&word.reading));
self.database.add_word(&word).unwrap(); // TODO: replace .unwrap() with ?
self.last_client_id = Some(client_id);
Ok(MessageResponseData::Word {
author: client_id,
word,
next_mora: self.next_mora.as_deref().unwrap().to_owned(),
})
} else {
Err("Wrong starting mora!")
}
}
None => Err("Not in dictionary!"),
}
}
}