|
|
@ -30,7 +30,7 @@ enum MessageResponseData {
|
|
|
|
Word {
|
|
|
|
Word {
|
|
|
|
author: u64,
|
|
|
|
author: u64,
|
|
|
|
word: Word,
|
|
|
|
word: Word,
|
|
|
|
next_char: char,
|
|
|
|
next_mora: String,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
History {
|
|
|
|
History {
|
|
|
|
words: Vec<Word>,
|
|
|
|
words: Vec<Word>,
|
|
|
@ -70,7 +70,7 @@ pub struct Server {
|
|
|
|
event_hub: EventHub,
|
|
|
|
event_hub: EventHub,
|
|
|
|
database: Database,
|
|
|
|
database: Database,
|
|
|
|
clients: HashMap<u64, Responder>,
|
|
|
|
clients: HashMap<u64, Responder>,
|
|
|
|
next_char: Option<char>,
|
|
|
|
next_mora: Option<String>,
|
|
|
|
last_client_id: Option<u64>,
|
|
|
|
last_client_id: Option<u64>,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -85,13 +85,59 @@ pub enum ServerError {
|
|
|
|
DatabaseError(rusqlite::Error),
|
|
|
|
DatabaseError(rusqlite::Error),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_starting_mora(word: &str) -> String {
|
|
|
|
|
|
|
|
if word.is_empty() {
|
|
|
|
|
|
|
|
return String::from("");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let word = word.to_hiragana();
|
|
|
|
|
|
|
|
let mut iter = word.chars();
|
|
|
|
|
|
|
|
let starting_char = iter.next().unwrap();
|
|
|
|
|
|
|
|
let second_char = iter.next().unwrap();
|
|
|
|
|
|
|
|
match second_char {
|
|
|
|
|
|
|
|
'ゃ' | 'ゅ' | 'ょ' => format!("{starting_char}{second_char}"),
|
|
|
|
|
|
|
|
_ => starting_char.to_string(),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Trim off lengtheners and non-kana that are irrelevant to shiritori
|
|
|
|
|
|
|
|
// TODO: Use slices
|
|
|
|
|
|
|
|
fn trim_irrelevant_chars(word: &str) -> String {
|
|
|
|
|
|
|
|
let mut iter = word.chars().rev().peekable();
|
|
|
|
|
|
|
|
while let Some(c) = iter.peek() {
|
|
|
|
|
|
|
|
if *c == 'ー' || !c.to_string().is_kana() {
|
|
|
|
|
|
|
|
iter.next();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
iter.rev().collect()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get final mora, which could be multiple chars e.g. しゃ
|
|
|
|
|
|
|
|
// TODO: Use slices
|
|
|
|
|
|
|
|
fn get_final_mora(word: &str) -> String {
|
|
|
|
|
|
|
|
let word = trim_irrelevant_chars(word).to_hiragana();
|
|
|
|
|
|
|
|
if word.is_empty() {
|
|
|
|
|
|
|
|
return String::from("");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut iter = word.chars().rev();
|
|
|
|
|
|
|
|
let final_char = iter.next().unwrap();
|
|
|
|
|
|
|
|
match final_char {
|
|
|
|
|
|
|
|
'ゃ' | 'ゅ' | 'ょ' => format!("{}{final_char}", match iter.next() {
|
|
|
|
|
|
|
|
Some(c) => c.to_string(),
|
|
|
|
|
|
|
|
None => String::from(""),
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
_ => final_char.to_string(),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
impl Server {
|
|
|
|
impl Server {
|
|
|
|
pub fn new(port: u16, testing: bool) -> Result<Self, ServerCreationError> {
|
|
|
|
pub fn new(port: u16, testing: bool) -> Result<Self, ServerCreationError> {
|
|
|
|
Ok(Server {
|
|
|
|
Ok(Server {
|
|
|
|
event_hub: simple_websockets::launch(port)?,
|
|
|
|
event_hub: simple_websockets::launch(port)?,
|
|
|
|
database: Database::new(testing)?,
|
|
|
|
database: Database::new(testing)?,
|
|
|
|
clients: HashMap::new(),
|
|
|
|
clients: HashMap::new(),
|
|
|
|
next_char: None,
|
|
|
|
next_mora: None,
|
|
|
|
last_client_id: None,
|
|
|
|
last_client_id: None,
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -153,32 +199,23 @@ impl Server {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
match lookup(&message) {
|
|
|
|
match lookup(&message) {
|
|
|
|
Some(entry) => {
|
|
|
|
Some(entry) => {
|
|
|
|
|
|
|
|
println!("{}, {:?}", get_starting_mora(&entry.reading), self.next_mora);
|
|
|
|
if entry.reading.chars().last().unwrap().to_string().to_hiragana() == "ん" {
|
|
|
|
if entry.reading.chars().last().unwrap().to_string().to_hiragana() == "ん" {
|
|
|
|
MessageResponseData::Error {
|
|
|
|
MessageResponseData::Error {
|
|
|
|
message: String::from("Can't end with ん!"),
|
|
|
|
message: String::from("Can't end with ん!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if self.next_char.is_none() || entry.reading.chars().next().unwrap().to_string().to_hiragana().chars().next().unwrap() == self.next_char.unwrap() {
|
|
|
|
} else if self.next_mora.is_none() || get_starting_mora(&entry.reading).eq(self.next_mora.as_deref().unwrap()) {
|
|
|
|
self.next_char = {
|
|
|
|
|
|
|
|
// If final character is lengthener or not kana
|
|
|
|
|
|
|
|
// Use semifinal
|
|
|
|
|
|
|
|
let mut final_chars = entry.reading.chars().rev();
|
|
|
|
|
|
|
|
let final_char = final_chars.next().unwrap();
|
|
|
|
|
|
|
|
Some(if final_char == 'ー' || !final_char.to_string().is_kana() {
|
|
|
|
|
|
|
|
final_chars.next().unwrap()
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
final_char
|
|
|
|
|
|
|
|
}.to_string().to_hiragana().chars().next().unwrap())
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
let word: Word = entry.clone().into();
|
|
|
|
let word: Word = entry.clone().into();
|
|
|
|
|
|
|
|
self.next_mora = Some(get_final_mora(&word.reading));
|
|
|
|
self.database.add_word(&word)?;
|
|
|
|
self.database.add_word(&word)?;
|
|
|
|
MessageResponseData::Word {
|
|
|
|
MessageResponseData::Word {
|
|
|
|
author: client_id,
|
|
|
|
author: client_id,
|
|
|
|
word,
|
|
|
|
word,
|
|
|
|
next_char: self.next_char.unwrap(),
|
|
|
|
next_mora: self.next_mora.as_deref().unwrap().to_owned(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
MessageResponseData::Error {
|
|
|
|
MessageResponseData::Error {
|
|
|
|
message: String::from("Wrong starting kana!"),
|
|
|
|
message: String::from("Wrong starting mora!"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|