use crate::{ types::{AppState, Config, DatabasePath, GameState, Player, Rank}, ui::{home, playing_field, HomeView, PlayingFieldView}, }; use serde::{Deserialize, Serialize}; use std::sync::{Arc, RwLock}; use typeshare::typeshare; #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[typeshare] #[serde(tag = "type", content = "content")] pub enum CoreRequest { CreateGame(CreateGameRequest), Home, PlayingField, PlayStone(PlayStoneRequest), StartGame, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[typeshare] pub struct PlayStoneRequest { pub column: u8, pub row: u8, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[typeshare] pub struct CreateGameRequest { pub black_player: PlayerInfoRequest, pub white_player: PlayerInfoRequest, } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[typeshare] pub enum PlayerInfoRequest { Hotseat(HotseatPlayerRequest), } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[typeshare] pub struct HotseatPlayerRequest { pub name: String, pub rank: Option, } impl From for Player { fn from(p: HotseatPlayerRequest) -> Self { Self { name: p.name, rank: p.rank.and_then(|r| Rank::try_from(r.as_ref()).ok()), } } } #[derive(Clone, Debug, Serialize, Deserialize)] #[typeshare] #[serde(tag = "type", content = "content")] pub enum CoreResponse { HomeView(HomeView), PlayingFieldView(PlayingFieldView), } #[derive(Clone, Debug)] pub struct CoreApp { config: Config, state: Arc>, } impl CoreApp { pub fn new(config_path: std::path::PathBuf) -> Self { println!("config_path: {:?}", config_path); let config = Config::from_path(config_path).expect("configuration to open"); let db_path: DatabasePath = config.get().unwrap(); let state = Arc::new(RwLock::new(AppState::new(db_path))); println!("config: {:?}", config); println!("games database: {:?}", state.read().unwrap().database.len()); Self { config, state } } pub async fn dispatch(&self, request: CoreRequest) -> CoreResponse { match request { /* CoreRequest::LaunchScreen => { let app_state = self.state.read().unwrap(); At launch, I want to either show a list of games in progress, the current game, or the game creation screen. - if a live game is in progress, immmediately go to that game. Such a game will be classified at game creation, so it should be persisted to the state. - if no live games are in progress, but there are slow games in progress, show a list of the slow games and let the player choose which one to jump into. - if no games are in progress, show only the game creation screen - game creation menu should be present both when there are only slow games and when there are no games - the UI returned here will always be available in other places, such as when the user is viewing a game and wants to return to this page For the initial version, I want only to show the game creation screen. Then I will backtrack record application state so that the only decisions can be made. } */ CoreRequest::CreateGame(create_request) => { let mut app_state = self.state.write().unwrap(); let white_player = { match create_request.white_player { PlayerInfoRequest::Hotseat(request) => Player::from(request), } }; let black_player = { match create_request.black_player { PlayerInfoRequest::Hotseat(request) => Player::from(request), } }; app_state.game = Some(GameState { white_player, black_player, ..GameState::new() }); let game_state = app_state.game.as_ref().unwrap(); CoreResponse::PlayingFieldView(playing_field(game_state)) } CoreRequest::Home => { CoreResponse::HomeView(home(self.state.read().unwrap().database.all_games())) } CoreRequest::PlayingField => { let app_state = self.state.read().unwrap(); let game = app_state.game.as_ref().unwrap(); CoreResponse::PlayingFieldView(playing_field(game)) } CoreRequest::PlayStone(request) => { let mut app_state = self.state.write().unwrap(); app_state.place_stone(request); let game = app_state.game.as_ref().unwrap(); CoreResponse::PlayingFieldView(playing_field(game)) } CoreRequest::StartGame => { unimplemented!() } } } pub async fn run(&self) {} }