Can select bot type
This commit is contained in:
parent
46ab1fec9a
commit
c9f643e224
@ -14,16 +14,11 @@ use tui::Terminal;
|
|||||||
|
|
||||||
use cli_player::server::start_server_if_missing;
|
use cli_player::server::start_server_if_missing;
|
||||||
use cli_player::ui_screens::*;
|
use cli_player::ui_screens::*;
|
||||||
use sea_battle_backend::data::{GameRules, PlayConfiguration};
|
|
||||||
|
|
||||||
async fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> Result<(), Box<dyn Error>> {
|
async fn run_app<B: Backend>(terminal: &mut Terminal<B>) -> Result<(), Box<dyn Error>> {
|
||||||
// Temporary code
|
// Temporary code
|
||||||
let res = configure_game_rules::configure_play_rules(
|
let res = select_bot_type::select_bot_type(terminal)?;
|
||||||
GameRules::default(),
|
Err(io::Error::new(
|
||||||
PlayConfiguration::default(),
|
|
||||||
terminal,
|
|
||||||
)?;
|
|
||||||
Err(std::io::Error::new(
|
|
||||||
ErrorKind::Other,
|
ErrorKind::Other,
|
||||||
format!("configured rules: {:?}", res),
|
format!("configured rules: {:?}", res),
|
||||||
))?;
|
))?;
|
||||||
|
@ -12,20 +12,15 @@ use tui::style::{Color, Style};
|
|||||||
use tui::widgets::*;
|
use tui::widgets::*;
|
||||||
use tui::{Frame, Terminal};
|
use tui::{Frame, Terminal};
|
||||||
|
|
||||||
use sea_battle_backend::data::{GameRules, PlayConfiguration};
|
use sea_battle_backend::data::GameRules;
|
||||||
|
|
||||||
use crate::constants::TICK_RATE;
|
use crate::constants::TICK_RATE;
|
||||||
use crate::ui_screens::utils::centered_rect_size;
|
use crate::ui_screens::utils::centered_rect_size;
|
||||||
|
use crate::ui_screens::ScreenResult;
|
||||||
use crate::ui_widgets::button_widget::ButtonWidget;
|
use crate::ui_widgets::button_widget::ButtonWidget;
|
||||||
use crate::ui_widgets::checkbox_widget::CheckboxWidget;
|
use crate::ui_widgets::checkbox_widget::CheckboxWidget;
|
||||||
use crate::ui_widgets::text_editor_widget::TextEditorWidget;
|
use crate::ui_widgets::text_editor_widget::TextEditorWidget;
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ConfigureGameRulesResult {
|
|
||||||
Ok(GameRules),
|
|
||||||
Canceled,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Eq, PartialEq)]
|
#[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Eq, PartialEq)]
|
||||||
enum EditingField {
|
enum EditingField {
|
||||||
MapWidth = 0,
|
MapWidth = 0,
|
||||||
@ -38,18 +33,15 @@ enum EditingField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct GameRulesConfigurationScreen {
|
struct GameRulesConfigurationScreen {
|
||||||
config: PlayConfiguration,
|
|
||||||
rules: GameRules,
|
rules: GameRules,
|
||||||
curr_field: EditingField,
|
curr_field: EditingField,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn configure_play_rules<B: Backend>(
|
pub fn configure_play_rules<B: Backend>(
|
||||||
rules: GameRules,
|
rules: GameRules,
|
||||||
config: PlayConfiguration,
|
|
||||||
terminal: &mut Terminal<B>,
|
terminal: &mut Terminal<B>,
|
||||||
) -> io::Result<ConfigureGameRulesResult> {
|
) -> io::Result<ScreenResult<GameRules>> {
|
||||||
let mut model = GameRulesConfigurationScreen {
|
let mut model = GameRulesConfigurationScreen {
|
||||||
config,
|
|
||||||
rules,
|
rules,
|
||||||
curr_field: EditingField::OK,
|
curr_field: EditingField::OK,
|
||||||
};
|
};
|
||||||
@ -68,7 +60,7 @@ pub fn configure_play_rules<B: Backend>(
|
|||||||
if let Event::Key(key) = event::read()? {
|
if let Event::Key(key) = event::read()? {
|
||||||
match key.code {
|
match key.code {
|
||||||
// Quit app
|
// Quit app
|
||||||
KeyCode::Char('q') => return Ok(ConfigureGameRulesResult::Canceled),
|
KeyCode::Char('q') => return Ok(ScreenResult::Canceled),
|
||||||
|
|
||||||
// Navigate between fields
|
// Navigate between fields
|
||||||
KeyCode::Up | KeyCode::Left => cursor_pos -= 1,
|
KeyCode::Up | KeyCode::Left => cursor_pos -= 1,
|
||||||
@ -77,11 +69,11 @@ pub fn configure_play_rules<B: Backend>(
|
|||||||
// Submit results
|
// Submit results
|
||||||
KeyCode::Enter => {
|
KeyCode::Enter => {
|
||||||
if model.curr_field == EditingField::Cancel {
|
if model.curr_field == EditingField::Cancel {
|
||||||
return Ok(ConfigureGameRulesResult::Canceled);
|
return Ok(ScreenResult::Canceled);
|
||||||
}
|
}
|
||||||
|
|
||||||
if model.curr_field == EditingField::OK && model.rules.is_valid() {
|
if model.curr_field == EditingField::OK && model.rules.is_valid() {
|
||||||
return Ok(ConfigureGameRulesResult::Ok(model.rules));
|
return Ok(ScreenResult::Ok(model.rules));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
pub mod configure_game_rules;
|
pub mod configure_game_rules;
|
||||||
|
pub mod select_bot_type;
|
||||||
pub mod select_play_mode;
|
pub mod select_play_mode;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ScreenResult<E> {
|
||||||
|
Ok(E),
|
||||||
|
Canceled,
|
||||||
|
}
|
||||||
|
95
rust/cli_player/src/ui_screens/select_bot_type.rs
Normal file
95
rust/cli_player/src/ui_screens/select_bot_type.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use crossterm::event;
|
||||||
|
use crossterm::event::{Event, KeyCode};
|
||||||
|
use tui::backend::Backend;
|
||||||
|
use tui::style::{Color, Modifier, Style};
|
||||||
|
use tui::text::*;
|
||||||
|
use tui::widgets::*;
|
||||||
|
use tui::{Frame, Terminal};
|
||||||
|
|
||||||
|
use sea_battle_backend::data::{BotDescription, BotType, PlayConfiguration};
|
||||||
|
|
||||||
|
use crate::constants::TICK_RATE;
|
||||||
|
use crate::ui_screens::utils::centered_rect_size;
|
||||||
|
use crate::ui_screens::ScreenResult;
|
||||||
|
|
||||||
|
struct SelectPlayModeScreen {
|
||||||
|
state: ListState,
|
||||||
|
curr_selection: usize,
|
||||||
|
types: Vec<BotDescription>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn select_bot_type<B: Backend>(
|
||||||
|
terminal: &mut Terminal<B>,
|
||||||
|
) -> io::Result<ScreenResult<BotType>> {
|
||||||
|
let types = PlayConfiguration::default().bot_types;
|
||||||
|
let mut model = SelectPlayModeScreen {
|
||||||
|
state: Default::default(),
|
||||||
|
curr_selection: types.len() - 1,
|
||||||
|
types,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut last_tick = Instant::now();
|
||||||
|
loop {
|
||||||
|
model.state.select(Some(model.curr_selection));
|
||||||
|
terminal.draw(|f| ui(f, &mut model))?;
|
||||||
|
|
||||||
|
let timeout = TICK_RATE
|
||||||
|
.checked_sub(last_tick.elapsed())
|
||||||
|
.unwrap_or_else(|| Duration::from_secs(0));
|
||||||
|
|
||||||
|
if event::poll(timeout)? {
|
||||||
|
if let Event::Key(key) = event::read()? {
|
||||||
|
match key.code {
|
||||||
|
KeyCode::Char('q') => return Ok(ScreenResult::Canceled),
|
||||||
|
KeyCode::Enter => {
|
||||||
|
return Ok(ScreenResult::Ok(model.types[model.curr_selection].r#type));
|
||||||
|
}
|
||||||
|
KeyCode::Down => model.curr_selection += 1,
|
||||||
|
KeyCode::Up => model.curr_selection += model.types.len() - 1,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
model.curr_selection %= model.types.len();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if last_tick.elapsed() >= TICK_RATE {
|
||||||
|
last_tick = Instant::now();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ui<B: Backend>(f: &mut Frame<B>, model: &mut SelectPlayModeScreen) {
|
||||||
|
let area = centered_rect_size(60, model.types.len() as u16 * 2 + 2, f.size());
|
||||||
|
|
||||||
|
// Create a List from all list items and highlight the currently selected one
|
||||||
|
let items = model
|
||||||
|
.types
|
||||||
|
.iter()
|
||||||
|
.map(|bot| {
|
||||||
|
ListItem::new(vec![
|
||||||
|
Spans::from(bot.name),
|
||||||
|
Spans::from(Span::styled(
|
||||||
|
bot.description,
|
||||||
|
Style::default().add_modifier(Modifier::ITALIC),
|
||||||
|
)),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let items = List::new(items)
|
||||||
|
.block(
|
||||||
|
Block::default()
|
||||||
|
.title("Select bot type")
|
||||||
|
.borders(Borders::ALL),
|
||||||
|
)
|
||||||
|
.highlight_style(
|
||||||
|
Style::default()
|
||||||
|
.fg(Color::Green)
|
||||||
|
.add_modifier(Modifier::BOLD),
|
||||||
|
)
|
||||||
|
.highlight_symbol(">> ");
|
||||||
|
|
||||||
|
f.render_stateful_widget(items, area, &mut model.state);
|
||||||
|
}
|
@ -11,9 +11,9 @@ pub enum BotType {
|
|||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
pub struct BotDescription {
|
pub struct BotDescription {
|
||||||
r#type: BotType,
|
pub r#type: BotType,
|
||||||
name: &'static str,
|
pub name: &'static str,
|
||||||
description: &'static str,
|
pub description: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
|
Loading…
Reference in New Issue
Block a user