Skip to main content

rustorio_engine/
tick.rs

1use std::fmt::Display;
2
3/// The tick is used to keep track of time in the game.
4/// You can advance the game using the [`advance`](Tick::advance) method or similar.
5/// Many functions and building methods require a [`Tick`] to be passed in, which allows them to update their state.
6/// If a function takes a [`&mut Tick`](Tick), then the function will take time.
7/// If a function merely takes a [`&Tick`](Tick), it will never advance the game time, but instead just roll forward it's internal state to match the current tick.
8///
9/// # Examples
10///
11/// Let's say we have two furnaces the we want to fill with `iron_ore` and `copper_ore` respectively, and then advance time so they can smelt the ore into ingots:
12/// ```
13/// // Add ore to the furnaces at the current tick
14/// furnace1.inputs(&tick).0.add(iron_ore);
15/// furnace2.inputs(&tick).0.add(copper_ore);
16/// // Advance time by 10 ticks so the furnaces can process some of the ore.
17/// tick.advance_by(10);
18/// // Now we can extract the smelted ingots from the furnaces
19/// let iron_ingots = furnace1.outputs(&tick).0.empty().unwrap();
20/// let copper_ingots = furnace2.outputs(&tick).0.empty().unwrap();
21/// ```
22#[derive(Debug)]
23pub struct Tick {
24    /// The current tick number.
25    tick: u64,
26    log: bool,
27}
28
29impl Tick {
30    pub(crate) const fn start() -> Self {
31        Self {
32            tick: 0,
33            log: false,
34        }
35    }
36
37    /// Sets whether or not to log on tick advancement.
38    pub const fn log(&mut self, log: bool) {
39        self.log = log;
40    }
41
42    /// Advances the game by one tick.
43    ///
44    /// By default prints the current tick number to the console.
45    /// If you want to disable this, use the [`log`](Tick::log) method.
46    pub fn advance(&mut self) {
47        self.advance_by(1);
48    }
49
50    /// Advances the game by the specified number of ticks.
51    ///
52    /// By default prints the current tick number to the console.
53    /// If you want to disable this, use the [`log`](Tick::log) method.
54    pub fn advance_by(&mut self, ticks: u64) {
55        self.tick = self.tick.checked_add(ticks).expect("Tick overflow. Well done you've found an exploit! Or you would have if `https://github.com/albertsgarde/rustorio/issues/3` hadn't beaten you to it!");
56        if self.log {
57            println!("{self}");
58        }
59    }
60
61    /// Advances the game until the specified tick number is reached.
62    /// Does nothing if the target tick is less than or equal to the current tick.
63    ///
64    /// By default prints the current tick number to the console.
65    /// If you want to disable this, use the [`log`](Tick::log) method.
66    pub fn advance_to_tick(&mut self, target_tick: u64) {
67        if target_tick > self.tick {
68            self.advance_by(target_tick - self.tick);
69        }
70    }
71
72    /// Advances the game until the specified condition is met or the maximum number of ticks has passed.
73    /// Returns `true` if the condition was met, or `false` if the maximum number of ticks was reached first.
74    ///
75    /// By default prints the current tick number to the console every tick.
76    /// If you want to disable this, use the [`log`](Tick::log) method.
77    pub fn advance_until<F>(&mut self, mut condition: F, max_ticks: u64) -> bool
78    where
79        F: FnMut(&Tick) -> bool,
80    {
81        let start_tick = self.tick;
82        while !condition(self) && self.tick - start_tick < max_ticks {
83            self.advance();
84        }
85        self.tick - start_tick < max_ticks
86    }
87
88    /// Returns the current tick number.
89    pub const fn cur(&self) -> u64 {
90        self.tick
91    }
92}
93
94impl From<&Tick> for u64 {
95    fn from(tick: &Tick) -> Self {
96        tick.tick
97    }
98}
99
100impl PartialOrd<u64> for &Tick {
101    fn partial_cmp(&self, other: &u64) -> Option<std::cmp::Ordering> {
102        Some(self.tick.cmp(other))
103    }
104}
105
106impl PartialOrd<&Tick> for u64 {
107    fn partial_cmp(&self, other: &&Tick) -> Option<std::cmp::Ordering> {
108        Some(self.cmp(&other.tick))
109    }
110}
111
112impl PartialEq<u64> for &Tick {
113    fn eq(&self, other: &u64) -> bool {
114        self.tick == *other
115    }
116}
117
118impl PartialEq<&Tick> for u64 {
119    fn eq(&self, other: &&Tick) -> bool {
120        *self == other.tick
121    }
122}
123
124impl Display for Tick {
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        write!(f, "Tick {}", self.tick)
127    }
128}