diff --git a/flake.lock b/flake.lock index 5cc0eb6..75b82ac 100644 --- a/flake.lock +++ b/flake.lock @@ -8,11 +8,11 @@ "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1775462255, - "narHash": "sha256-YRzdvh6nvMebcgO2nDpr8dqVwKHpp1BBRUHeMxX9UAY=", + "lastModified": 1779612045, + "narHash": "sha256-+7lfNVnmXJDkiRYHd5NoNwYoyUcc0LcXPaIJqjO7VWM=", "owner": "nix-community", "repo": "fenix", - "rev": "f90343f1ed330243d4bbdbce51acbd93b776a797", + "rev": "d7be747f0a65af378de515fc3cee131bf99a008f", "type": "github" }, "original": { @@ -31,11 +31,11 @@ ] }, "locked": { - "lastModified": 1769799857, - "narHash": "sha256-88IFXZ7Sa1vxbz5pty0Io5qEaMQMMUPMonLa3Ls/ss4=", + "lastModified": 1778151388, + "narHash": "sha256-lldMJPUeouEjO8/7aLuwhcsIw29vVihm2ZALzjiqfec=", "owner": "nix-community", "repo": "naersk", - "rev": "9d4ed44d8b8cecdceb1d6fd76e74123d90ae6339", + "rev": "efdddff9ff4d8e7d0056d57ec67dac50f75ab8f6", "type": "github" }, "original": { @@ -46,11 +46,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1775036866, - "narHash": "sha256-ZojAnPuCdy657PbTq5V0Y+AHKhZAIwSIT2cb8UgAz/U=", + "lastModified": 1779508470, + "narHash": "sha256-Ap9KJX+5xHIn3bPIpfNgT6MEXdAECECwo4/rmlQD74M=", "owner": "nixos", "repo": "nixpkgs", - "rev": "6201e203d09599479a3b3450ed24fa81537ebc4e", + "rev": "29916453413845e54a65b8a1cf996842300cd299", "type": "github" }, "original": { @@ -70,11 +70,11 @@ "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1775429583, - "narHash": "sha256-bFC/p7Ywyd9QIr9DbU3Q75c7AcaCm9wVmEvcI3702cY=", + "lastModified": 1779569060, + "narHash": "sha256-NSnk5D+3KEfRdbgPijs33N2RAKSG6A74SwfnynLcouo=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "38fb8f92ac15853d7fa9fb47fc2d81fdd5cd6c7e", + "rev": "987ea33645ab1c709b1df6823038abcb2fe8973e", "type": "github" }, "original": { diff --git a/src/app/states/skirmish.rs b/src/app/states/skirmish.rs index ff63a09..4e89fc0 100644 --- a/src/app/states/skirmish.rs +++ b/src/app/states/skirmish.rs @@ -11,7 +11,7 @@ pub struct SkirmishState { impl SkirmishState { pub fn tick_update(&mut self) { - self.board.advance_turn(); + // self.board.advance_turn(); // if self.board.is_victory() {} diff --git a/src/app/states/skirmish_states/board.rs b/src/app/states/skirmish_states/board.rs index 68f7509..7f36d9a 100644 --- a/src/app/states/skirmish_states/board.rs +++ b/src/app/states/skirmish_states/board.rs @@ -4,8 +4,8 @@ use crate::app::{ FocusedCell, Offset, skirmish_states::{ CellSizes, MarkedCells, MoveFocusedCell, Players, ZoomLevel, - structures::{BaseBuilding, Ore, Stone, Structures}, - tasks::{DiggingTask, Tasks}, + structures::{BaseBuilding, Ore, Stone, Structures, Tunnel}, + tasks::{DiggingTask, Task, Tasks}, units::{MinerUnit, Unit, Units}, }, }, @@ -219,7 +219,14 @@ impl BoardState { let (row, col) = self.marked_cells.selected_unit.get_coords(); if self.marked_cells.marked_cells.len() > 1 && !del { - let path: VecDeque<(usize, usize)> = self.marked_cells.marked_cells.clone(); + let path: VecDeque<(usize, usize)> = self + .marked_cells + .marked_cells + .iter() + .skip(1) + .cloned() + .collect(); + let tick_increase: f32 = self.marked_cells.selected_unit.get_digging_power(); let task: Tasks = Tasks::Digging(DiggingTask::new(path, tick_increase)); @@ -318,21 +325,101 @@ impl BoardState { } } - fn get_active_tasks(&self) -> Vec<&Tasks> { - self.cells - .iter() - .flat_map(|row| row.iter()) - .filter_map(|cell| { - cell.get_ref_option_unit() - .as_ref() - .and_then(|unit| unit.get_tasks().front()) - }) - .collect() - } + // fn get_active_tasks(&self) -> Vec<&Tasks> { + // self.cells + // .iter() + // .flat_map(|row| row.iter()) + // .filter_map(|cell| { + // cell.get_ref_option_unit() + // .as_ref() + // .and_then(|unit| unit.get_ref_tasks().front()) + // }) + // .collect() + // // for row in self.marked_cells.marked_cells { + + // // } + // } pub fn advance_turn(&mut self) { - for task in self.get_active_tasks() { - // task.progress() + for row in 0..self.map_height { + for col in 0..self.map_width { + /* --------------------------------------------------------- + * 1️⃣ Take the unit out of the current cell (if any). This + * gives us an *owned* `Units`, so we no longer hold a + * mutable reference into `self`. + * ------------------------------------------------------- */ + let maybe_unit: Option = + self.get_mut_cell(row, col).get_mut_option_unit().take(); + + let Some(mut unit) = maybe_unit else { + continue; // no unit in this cell + }; + + /* --------------------------------------------------------- + * 2️⃣ Look at the unit’s task queue. We need a mutable + * reference to the *front* task only while we are + * processing it. The mutable borrow is confined to a + * small inner block so that it ends before we move the + * unit itself. + * ------------------------------------------------------- */ + if let Some(task) = unit.get_mut_tasks().front_mut() { + // `Tasks` currently only has the Digging variant. + // If new variants appear later, you can handle them here. + let maybe_target: Option<(usize, usize)> = { + // ------------------------------------------------- + // Mutable borrow of the task lives only inside this + // block. When the block ends, `dig` is dropped. + // ------------------------------------------------- + let dig: &mut DiggingTask = match task { + Tasks::Digging(d) => d, + }; + + dig.progress(); + + // Remember the coordinates of the next tunnel cell. + let target: Option<(usize, usize)> = dig.current_target(); + + // If we actually moved, the current step of the + // digging task is finished – pop it from the queue. + if target.is_some() { + dig.pop_front(); + } + + target + }; // ← `dig` (and the mutable borrow) ends here + + if let Some((t_row, t_col)) = maybe_target { + /* ------------------------------------------------- + * 3️⃣ We have a target – create the tunnel, move the + * unit, and clean up the source cell. + * ------------------------------------------------- */ + + // a) create the tunnel in the target cell + self.get_mut_cell(t_row, t_col) + .set_structure(Structures::Tunnel(Tunnel::new())); + + // b) (optional) keep the old coordinates – they are + // no longer needed but kept for possible future use + let _old_coords: (usize, usize) = unit.get_coords(); + + // c) move the unit into the target cell + *self.get_mut_cell(t_row, t_col).get_mut_option_unit() = Some(unit); + + // d) the source cell is already empty because of the + // earlier `take()`. Nothing else to do. + } else { + // No reachable target – put the unit back where it was. + self.get_mut_cell(row, col) + .get_mut_option_unit() + .replace(unit); + } + } else { + // The unit has no tasks – simply put it back. + self.get_mut_cell(row, col) + .get_mut_option_unit() + .replace(unit); + } + } } } } diff --git a/src/app/states/skirmish_states/tasks/digging.rs b/src/app/states/skirmish_states/tasks/digging.rs index d31fc75..cefef21 100644 --- a/src/app/states/skirmish_states/tasks/digging.rs +++ b/src/app/states/skirmish_states/tasks/digging.rs @@ -16,6 +16,15 @@ impl DiggingTask { tick_increase, } } + + pub fn pop_front(&mut self) { + self.path.pop_front(); + self.progress = 0.0; + } + + pub fn current_target(&self) -> Option<(usize, usize)> { + self.path.front().copied() + } } impl Task for DiggingTask { diff --git a/src/app/states/skirmish_states/units/miner.rs b/src/app/states/skirmish_states/units/miner.rs index 3c41cf2..a9330bb 100644 --- a/src/app/states/skirmish_states/units/miner.rs +++ b/src/app/states/skirmish_states/units/miner.rs @@ -79,10 +79,14 @@ impl Unit for MinerUnit { self.coords } - fn get_tasks(&self) -> &VecDeque { + fn get_ref_tasks(&self) -> &VecDeque { &self.tasks } + fn get_mut_tasks(&mut self) -> &mut VecDeque { + &mut self.tasks + } + fn get_tasks_formatted(&self) -> Vec> { Vec::from( self.tasks diff --git a/src/app/states/skirmish_states/units/unit_trait.rs b/src/app/states/skirmish_states/units/unit_trait.rs index cd221fc..3cf7c26 100644 --- a/src/app/states/skirmish_states/units/unit_trait.rs +++ b/src/app/states/skirmish_states/units/unit_trait.rs @@ -26,7 +26,9 @@ pub trait Unit { fn get_coords(&self) -> (usize, usize); - fn get_tasks(&self) -> &VecDeque; + fn get_ref_tasks(&self) -> &VecDeque; + + fn get_mut_tasks(&mut self) -> &mut VecDeque; fn set_task(&mut self, task: Tasks); @@ -39,7 +41,7 @@ pub trait Unit { let hp_percent: u16 = hp * 100 / max_hp; let can_dig: bool = self.get_can_dig(); let digging_power: f32 = self.get_digging_power(); - let have_any_tasks: bool = self.get_tasks().is_empty(); + let have_any_tasks: bool = self.get_ref_tasks().is_empty(); let tasks: Vec> = self.get_tasks_formatted(); let mut lines: Vec> = Vec::from([ diff --git a/src/app/states/skirmish_states/units/units_enum.rs b/src/app/states/skirmish_states/units/units_enum.rs index 2ea21a5..b632223 100644 --- a/src/app/states/skirmish_states/units/units_enum.rs +++ b/src/app/states/skirmish_states/units/units_enum.rs @@ -3,12 +3,9 @@ use crate::app::states::skirmish_states::{ tasks::Tasks, units::{MinerUnit, Unit}, }; -use once_cell::sync::Lazy; use ratatui::text::Line; use std::collections::VecDeque; -static EMPTY_TASKS: Lazy> = Lazy::new(|| VecDeque::new()); - #[derive(Debug, Clone, PartialEq)] pub enum Units { Miner(MinerUnit), @@ -16,14 +13,14 @@ pub enum Units { impl Units { #[inline] - fn u(&self) -> &dyn Unit { + pub fn u(&self) -> &dyn Unit { match self { Self::Miner(m) => m, } } #[inline] - fn u_mut(&mut self) -> &mut dyn Unit { + pub fn u_mut(&mut self) -> &mut dyn Unit { match self { Self::Miner(m) => m, } @@ -63,8 +60,12 @@ impl Unit for Units { self.u().get_coords() } - fn get_tasks(&self) -> &VecDeque { - self.u().get_tasks() + fn get_ref_tasks(&self) -> &VecDeque { + self.u().get_ref_tasks() + } + + fn get_mut_tasks(&mut self) -> &mut VecDeque { + self.u_mut().get_mut_tasks() } fn get_tasks_formatted(&self) -> Vec> { @@ -113,8 +114,16 @@ impl Unit for Option { self.as_ref().map_or((0, 0), |u| u.get_coords()) } - fn get_tasks(&self) -> &VecDeque { - self.as_ref().map_or(&EMPTY_TASKS, |u| u.get_tasks()) + fn get_ref_tasks(&self) -> &VecDeque { + self.as_ref() + .expect("attempted to get referenced tasks from `None`") + .get_ref_tasks() + } + + fn get_mut_tasks(&mut self) -> &mut VecDeque { + self.as_mut() + .expect("attempted to get mutable tasks from `None`") + .get_mut_tasks() } fn get_tasks_formatted(&self) -> Vec> {