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}