Initialize skirmish board and refactor states

- Create `GameStates` from a `&Cli` and initialize the skirmish board in
  `App::new`.
- Move map dimensions to `SkirmishState` and add a `board_cells` vector
  populated by `CellWidget`s.
- Refactor `SettingsState` to store only user‑specific settings (fields
  are cloned).
- Update `BoardWidget` to hold a reference to the cell vector and use
  the new dimensions.
- Adjust CLI defaults: map width to 50 and map height to 25.
This commit is contained in:
2026-03-27 19:25:20 +01:00
parent a0186ea0cb
commit 9300eef906
7 changed files with 62 additions and 31 deletions
+4 -1
View File
@@ -25,10 +25,13 @@ pub struct App {
impl App { impl App {
pub fn new(args: Cli) -> Self { pub fn new(args: Cli) -> Self {
let mut states: GameStates = GameStates::new(&args);
states.skirmish.init_board();
Self { Self {
exit: false, exit: false,
view: args.view, view: args.view,
states: GameStates::new(args), states,
} }
} }
+12 -11
View File
@@ -15,7 +15,7 @@ pub struct GameStates {
} }
impl GameStates { impl GameStates {
pub fn new(args: Cli) -> Self { pub fn new(args: &Cli) -> Self {
Self { Self {
main_menu: MainMenuState { main_menu: MainMenuState {
id: 0, id: 0,
@@ -27,6 +27,9 @@ impl GameStates {
name: "Skirmish", name: "Skirmish",
vertical_offset: Offset::new(), vertical_offset: Offset::new(),
horizontal_offset: Offset::new(), horizontal_offset: Offset::new(),
map_width: args.map_width as usize,
map_height: args.map_height as usize,
board_cells: Vec::new(),
}, },
perk_decks: PerkDecksState { perk_decks: PerkDecksState {
id: 2, id: 2,
@@ -39,16 +42,14 @@ impl GameStates {
selected_skill: 0, selected_skill: 0,
}, },
settings: SettingsState { settings: SettingsState {
username: args.username, username: args.username.clone(),
game_mode: args.game_mode, game_mode: args.game_mode.clone(),
map_width: args.map_width, perk_deck: args.perk_deck.clone(),
map_height: args.map_height, starting_wood: args.starting_wood.clone(),
perk_deck: args.perk_deck, starting_iron: args.starting_iron.clone(),
starting_wood: args.starting_wood, supply_limit: args.supply_limit.clone(),
starting_iron: args.starting_iron, xp_modifier: args.xp_modifier.clone(),
supply_limit: args.supply_limit, skill_points_limit: args.skill_points_limit.clone(),
xp_modifier: args.xp_modifier,
skill_points_limit: args.skill_points_limit,
}, },
} }
} }
-2
View File
@@ -4,8 +4,6 @@ use crate::app::states::{GameMode, PerkDecks};
pub struct SettingsState { pub struct SettingsState {
pub username: String, pub username: String,
pub game_mode: GameMode, pub game_mode: GameMode,
pub map_width: u8,
pub map_height: u8,
pub perk_deck: PerkDecks, pub perk_deck: PerkDecks,
pub starting_wood: u16, pub starting_wood: u16,
pub starting_iron: u16, pub starting_iron: u16,
+23 -1
View File
@@ -1,3 +1,4 @@
use crate::app::widgets::CellWidget;
use clap::ValueEnum; use clap::ValueEnum;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -16,6 +17,10 @@ impl Offset {
} }
pub fn set_max(&mut self, max: usize) { pub fn set_max(&mut self, max: usize) {
if self.max != 0 {
return;
}
self.max = max; self.max = max;
} }
@@ -28,12 +33,29 @@ impl Offset {
} }
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct SkirmishState { pub struct SkirmishState {
pub id: usize, pub id: usize,
pub name: &'static str, pub name: &'static str,
pub map_width: usize,
pub map_height: usize,
pub vertical_offset: Offset, pub vertical_offset: Offset,
pub horizontal_offset: Offset, pub horizontal_offset: Offset,
pub board_cells: Vec<CellWidget>,
}
impl SkirmishState {
pub fn init_board(&mut self) {
if !self.board_cells.is_empty() {
return;
}
for row in 0..self.map_height {
for col in 0..self.map_width {
self.board_cells.push(CellWidget::new(row, col));
}
}
}
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, ValueEnum)]
+19 -13
View File
@@ -6,31 +6,33 @@ use ratatui::{
}; };
use std::rc::Rc; use std::rc::Rc;
pub struct BoardWidget { pub struct BoardWidget<'a> {
map_width: usize,
cell_width: u16, cell_width: u16,
cell_height: u16, cell_height: u16,
cols: u16, cols: u16,
rows: u16, rows: u16,
h_offset: usize, h_offset: usize,
v_offset: usize, v_offset: usize,
cells: &'a Vec<CellWidget>,
} }
impl BoardWidget { impl<'a> BoardWidget<'a> {
pub fn new(app: &mut App, area_width: u16, area_height: u16) -> Self { pub fn new(app: &'a mut App, area_width: u16, area_height: u16) -> Self {
const CELL_HIGHT: u16 = 8; // 4 const CELL_HIGHT: u16 = 5; // 4
const CELL_WIDTH: u16 = 14; // 7 const CELL_WIDTH: u16 = 9; // 7
let rows: u16 = area_height / CELL_HIGHT; let rows: u16 = area_height / CELL_HIGHT;
let cols: u16 = area_width / CELL_WIDTH; let cols: u16 = area_width / CELL_WIDTH;
let v_max_offset: usize = if app.states.settings.map_height as u16 > rows { let v_max_offset: usize = if app.states.skirmish.map_height as u16 > rows {
app.states.settings.map_height as u16 - rows app.states.skirmish.map_height as u16 - rows
} else { } else {
0 0
} as usize; } as usize;
let h_max_offset: usize = if app.states.settings.map_width as u16 > cols { let h_max_offset: usize = if app.states.skirmish.map_width as u16 > cols {
app.states.settings.map_width as u16 - cols app.states.skirmish.map_width as u16 - cols
} else { } else {
0 0
} as usize; } as usize;
@@ -39,17 +41,19 @@ impl BoardWidget {
app.states.skirmish.vertical_offset.set_max(v_max_offset); app.states.skirmish.vertical_offset.set_max(v_max_offset);
Self { Self {
map_width: app.states.skirmish.map_width as usize,
cell_width: CELL_WIDTH, cell_width: CELL_WIDTH,
cell_height: CELL_HIGHT, cell_height: CELL_HIGHT,
cols, cols,
rows, rows,
h_offset: app.states.skirmish.horizontal_offset.get_value(), h_offset: app.states.skirmish.horizontal_offset.get_value(),
v_offset: app.states.skirmish.vertical_offset.get_value(), v_offset: app.states.skirmish.vertical_offset.get_value(),
cells: &app.states.skirmish.board_cells,
} }
} }
} }
impl Widget for BoardWidget { impl Widget for BoardWidget<'_> {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let horizontal: Rc<[Rect]> = Layout::horizontal(vec![ let horizontal: Rc<[Rect]> = Layout::horizontal(vec![
Constraint::Length(self.cell_width); Constraint::Length(self.cell_width);
@@ -65,11 +69,13 @@ impl Widget for BoardWidget {
.split(*col_area); .split(*col_area);
for (row_idx, cell_area) in vertical.iter().enumerate() { for (row_idx, cell_area) in vertical.iter().enumerate() {
let cell: CellWidget = if let Some(cell) = self
CellWidget::new(row_idx + self.v_offset, col_idx + self.h_offset); .cells
.get((row_idx + self.v_offset) * self.map_width + (col_idx + self.h_offset))
{
cell.render(*cell_area, buf); cell.render(*cell_area, buf);
} }
} }
} }
}
} }
+1
View File
@@ -13,6 +13,7 @@ use ratatui::{
// Base, // Base,
// } // }
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CellWidget { pub struct CellWidget {
pub row: usize, pub row: usize,
pub col: usize, pub col: usize,
+2 -2
View File
@@ -37,7 +37,7 @@ pub struct Cli {
long, long,
help = "Map width", help = "Map width",
value_name = "Positive integer [20; 100]", value_name = "Positive integer [20; 100]",
default_value = "27" default_value = "50"
)] )]
pub map_width: u8, pub map_width: u8,
@@ -45,7 +45,7 @@ pub struct Cli {
long, long,
help = "Map height", help = "Map height",
value_name = "Positive integer [11; 50]", value_name = "Positive integer [11; 50]",
default_value = "11" default_value = "25"
)] )]
pub map_height: u8, pub map_height: u8,