WIP: Add support for removing AIs
This commit is contained in:
parent
5f125dfb75
commit
12ce134047
5 changed files with 58 additions and 68 deletions
|
@ -66,7 +66,7 @@ enum RoomEvent {
|
|||
PlayerJoined(Player),
|
||||
PlayerLeft(Player),
|
||||
AIJoined(Difficulty),
|
||||
//AILeft(Difficulty),
|
||||
AILeft { index: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
|
@ -74,6 +74,7 @@ enum RoomEvent {
|
|||
enum ServerToClientMessage {
|
||||
RoomChange { event: RoomEvent, info: PartyInfo },
|
||||
GameEvent { state: ApiState },
|
||||
Invalid { reason: String },
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
|
@ -84,6 +85,7 @@ enum ClientToServerMessage {
|
|||
StartGame,
|
||||
GameMove,
|
||||
AddAI { difficulty: Difficulty },
|
||||
RemoveAI { index: usize },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -99,6 +101,7 @@ async fn incoming_message_handler<E: std::fmt::Display>(
|
|||
sender: &Sender<InnerRoomMessage>,
|
||||
player: &Player,
|
||||
room: &Arc<RwLock<Room>>,
|
||||
stream: &mut DuplexStream,
|
||||
) -> bool {
|
||||
match message {
|
||||
None => {
|
||||
|
@ -184,6 +187,23 @@ async fn incoming_message_handler<E: std::fmt::Display>(
|
|||
};
|
||||
sender.send(InnerRoomMessage::PassThrough(event)).unwrap();
|
||||
}
|
||||
ClientToServerMessage::RemoveAI { index } => {
|
||||
let mut room = room.write().await;
|
||||
if index < room.party_info.ais.len() {
|
||||
room.party_info.ais.remove(index);
|
||||
let event = ServerToClientMessage::RoomChange {
|
||||
event: RoomEvent::AILeft { index },
|
||||
info: room.party_info.clone(),
|
||||
};
|
||||
sender.send(InnerRoomMessage::PassThrough(event)).unwrap();
|
||||
} else {
|
||||
let event = ServerToClientMessage::Invalid {
|
||||
reason: format!("{index} is out of bounds"),
|
||||
};
|
||||
let event = serde_json::to_string(&event).unwrap();
|
||||
let _ = stream.send(event.into()).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
|
@ -204,6 +224,7 @@ async fn outgoing_message_handler<E: std::fmt::Debug>(
|
|||
stream: &mut DuplexStream,
|
||||
) -> bool {
|
||||
let message = message.unwrap();
|
||||
println!("Inner room message - {:#?}", message);
|
||||
let message = match message {
|
||||
InnerRoomMessage::PassThrough(event) => serde_json::to_string(&event).unwrap(),
|
||||
InnerRoomMessage::GameEvent => {
|
||||
|
@ -290,7 +311,7 @@ async fn chat(
|
|||
// Rust formatter can't reach into this macro, hence we broke out the logic
|
||||
// into sub-functions
|
||||
message = incoming_message => {
|
||||
if incoming_message_handler(message, &sender, &player, &room).await {
|
||||
if incoming_message_handler(message, &sender, &player, &room, &mut stream).await {
|
||||
return Ok(())
|
||||
}
|
||||
},
|
||||
|
@ -304,56 +325,6 @@ async fn chat(
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
//
|
||||
// ws.channel(move |mut stream| Box::pin(async move {
|
||||
// let mut interval = interval(Duration::from_secs(10));
|
||||
// while !stream.is_terminated(){ // always seems to return true?
|
||||
// let ws_incoming = stream.next();
|
||||
// let other_incoming = receiver.recv();
|
||||
// let ping_tick = interval.tick();
|
||||
//
|
||||
// // pin_mut!(ws_incoming, other_incoming); // no clue what this does
|
||||
//
|
||||
// select! {
|
||||
// message = ws_incoming => {
|
||||
// if message.is_none() {
|
||||
// println!("Websocket closed");
|
||||
// return Ok(())
|
||||
// }
|
||||
//
|
||||
// println!("websocket received a websocket message");
|
||||
// let message = message.unwrap()?;
|
||||
//
|
||||
// if let ws::Message::Close(close_frame) = &message {
|
||||
// println!("Received close message");
|
||||
// println!("{close_frame:?}")
|
||||
// } else if let ws::Message::Text(text) = &message {
|
||||
// println!("Received text {text:?}");
|
||||
// sender.send(text.to_string()).unwrap();
|
||||
// } else {
|
||||
// println!("Received non-text message: {message:?}")
|
||||
// }
|
||||
// },
|
||||
// message = other_incoming => {
|
||||
// let message = message.unwrap();
|
||||
// println!("Sending message \"{message}\" via websocket");
|
||||
//
|
||||
//
|
||||
//
|
||||
// let _ = stream.send(message.into()).await; // always seems to return Ok(()), even after a disconnection
|
||||
// //println!("Message sent: {blat:?}");
|
||||
// }
|
||||
// _ = ping_tick => {
|
||||
// println!("ping_tick");
|
||||
// let message = Message::Ping(Vec::new());
|
||||
// let _ = stream.send(message.into()).await;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// Ok(())
|
||||
//
|
||||
// }))
|
||||
}
|
||||
|
||||
#[launch]
|
||||
|
|
|
@ -18,6 +18,16 @@ interface PartyInfo {
|
|||
players: Player[]
|
||||
}
|
||||
|
||||
const LOGBASE = 10000;
|
||||
function unprocessAIRandomness(processedAIRandomness: number): string {
|
||||
const x = 100*(LOGBASE**processedAIRandomness -1) / (LOGBASE-1)
|
||||
return x.toFixed(0)
|
||||
}
|
||||
|
||||
function unprocessedAIProportion(processedProportion: number): string {
|
||||
return (100 * (1-processedProportion)).toFixed(0);
|
||||
}
|
||||
|
||||
export function Menu(): React.JSX.Element {
|
||||
|
||||
const [roomName, setRoomName] = useState<string>("");
|
||||
|
@ -31,8 +41,7 @@ export function Menu(): React.JSX.Element {
|
|||
|
||||
// Can change log scale to control shape of curve using following equation:
|
||||
// aiRandomness = log(1 + x*(n-1))/log(n) when x, the user input, ranges between 0 and 1
|
||||
const logBase: number = 10000;
|
||||
const processedAIRandomness = Math.log(1 + (logBase - 1)*aiRandomness/100) / Math.log(logBase);
|
||||
const processedAIRandomness = Math.log(1 + (LOGBASE - 1)*aiRandomness/100) / Math.log(LOGBASE);
|
||||
const processedProportionDictionary = 1.0 - proportionDictionary / 100;
|
||||
|
||||
if(socket != null && partyInfo == null) {
|
||||
|
@ -42,8 +51,19 @@ export function Menu(): React.JSX.Element {
|
|||
return <li key={x.id}>{x.name}</li>;
|
||||
});
|
||||
const ais = partyInfo.ais.map((x, i) => {
|
||||
return <li key={i}>Proportion: {x.proportion} / Randomness: {x.randomness}</li>
|
||||
})
|
||||
return <li key={i}>
|
||||
<span>Proportion: {unprocessedAIProportion(x.proportion)} / Randomness: {unprocessAIRandomness(x.randomness)}</span>
|
||||
<button onClick={() => {
|
||||
const event = {
|
||||
type: "RemoveAI",
|
||||
index: i
|
||||
};
|
||||
socket.send(JSON.stringify(event));
|
||||
}
|
||||
}>X
|
||||
</button>
|
||||
</li>
|
||||
});
|
||||
|
||||
return <div>
|
||||
<p>Connected to {roomName}</p>
|
||||
|
|
|
@ -26,19 +26,19 @@ impl WasmAPI {
|
|||
pub fn exchange(&mut self, selection: JsValue) -> JsValue {
|
||||
let selection: Vec<bool> = serde_wasm_bindgen::from_value(selection).unwrap();
|
||||
|
||||
let result = self.0.exchange("Player".to_string(), selection);
|
||||
let result = self.0.exchange("Player", selection);
|
||||
|
||||
serde_wasm_bindgen::to_value(&result).unwrap()
|
||||
}
|
||||
|
||||
pub fn pass(&mut self) -> JsValue {
|
||||
let result = self.0.pass("Player".to_string());
|
||||
let result = self.0.pass("Player");
|
||||
|
||||
serde_wasm_bindgen::to_value(&result).unwrap()
|
||||
}
|
||||
|
||||
pub fn load(&mut self) -> JsValue {
|
||||
let result = self.0.load("Player".to_string());
|
||||
let result = self.0.load("Player");
|
||||
serde_wasm_bindgen::to_value(&result).unwrap()
|
||||
}
|
||||
|
||||
|
|
|
@ -128,13 +128,13 @@ impl APIGame {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn exchange(&mut self, player: String, tray_tiles: Vec<bool>) -> Result<ApiState, Error> {
|
||||
self.player_exists_and_turn(&player)?;
|
||||
pub fn exchange(&mut self, player: &str, tray_tiles: Vec<bool>) -> Result<ApiState, Error> {
|
||||
self.player_exists_and_turn(player)?;
|
||||
|
||||
let (tray, turn_action, game_state) = self.0.exchange_tiles(tray_tiles)?;
|
||||
let update = Update {
|
||||
r#type: turn_action,
|
||||
player,
|
||||
player: player.to_string(),
|
||||
};
|
||||
|
||||
self.1.push(update.clone());
|
||||
|
@ -142,14 +142,14 @@ impl APIGame {
|
|||
Ok(self.build_result(tray, Some(game_state), Some(update)))
|
||||
}
|
||||
|
||||
pub fn pass(&mut self, player: String) -> Result<ApiState, Error> {
|
||||
self.player_exists_and_turn(&player)?;
|
||||
pub fn pass(&mut self, player: &str) -> Result<ApiState, Error> {
|
||||
self.player_exists_and_turn(player)?;
|
||||
|
||||
let game_state = self.0.pass()?;
|
||||
let tray = self.0.player_states.get_tray(&player).unwrap().clone();
|
||||
let tray = self.0.player_states.get_tray(player).unwrap().clone();
|
||||
let update = Update {
|
||||
r#type: TurnAction::Pass,
|
||||
player,
|
||||
player: player.to_string(),
|
||||
};
|
||||
self.1.push(update.clone());
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ use crate::player_interaction::ai::{Difficulty, AI};
|
|||
use crate::player_interaction::Tray;
|
||||
use rand::prelude::SliceRandom;
|
||||
use rand::rngs::SmallRng;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand::SeedableRng;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
|
||||
pub enum Player {
|
||||
|
@ -204,7 +204,6 @@ pub struct Game {
|
|||
}
|
||||
|
||||
impl Game {
|
||||
|
||||
pub fn new_specific(
|
||||
mut rng: SmallRng,
|
||||
dictionary: DictionaryImpl,
|
||||
|
|
Loading…
Reference in a new issue