You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

214 lines
4.7 KiB

  1. use std::cmp::min;
  2. use std::ops::{Index, IndexMut, Mul};
  3. use glc::vector::Vector2f;
  4. use serde::{Deserialize, Serialize};
  5. use specs::{Component, Entity, VecStorage};
  6. #[derive(Clone, Debug, Serialize, Deserialize)]
  7. pub struct Ship {
  8. type_: Type,
  9. #[serde(skip)]
  10. obstacle: Obstacle,
  11. #[serde(skip)]
  12. target_pos: Vector2f,
  13. #[serde(skip)]
  14. target_dir: Vector2f,
  15. }
  16. #[derive(Copy, Clone, Debug, PartialEq, Eq)]
  17. pub enum Obstacle {
  18. Known(Entity),
  19. Search,
  20. Done,
  21. }
  22. #[derive(Copy, Clone, Debug, Default)]
  23. pub struct Count {
  24. pub fighter: usize,
  25. pub bomber: usize,
  26. pub transporter: usize,
  27. }
  28. #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
  29. pub enum Type {
  30. Fighter,
  31. Bomber,
  32. Transporter,
  33. }
  34. impl Ship {
  35. #[inline]
  36. pub fn new(type_: Type) -> Self {
  37. Self {
  38. type_,
  39. obstacle: Default::default(),
  40. target_pos: Default::default(),
  41. target_dir: Default::default(),
  42. }
  43. }
  44. #[inline]
  45. pub fn type_(&self) -> Type {
  46. self.type_
  47. }
  48. #[inline]
  49. pub fn target_pos(&self) -> &Vector2f {
  50. &self.target_pos
  51. }
  52. #[inline]
  53. pub fn target_dir(&self) -> &Vector2f {
  54. &self.target_dir
  55. }
  56. #[inline]
  57. pub(crate) fn set_target(&mut self, pos: Vector2f, dir: Vector2f) {
  58. self.target_pos = pos;
  59. self.target_dir = dir;
  60. }
  61. #[inline]
  62. pub fn obstacle(&self) -> Obstacle {
  63. self.obstacle
  64. }
  65. #[inline]
  66. pub(crate) fn set_obstacle(&mut self, value: Obstacle) {
  67. self.obstacle = value;
  68. }
  69. }
  70. impl Component for Ship {
  71. type Storage = VecStorage<Self>;
  72. }
  73. impl Default for Obstacle {
  74. fn default() -> Self {
  75. Self::Search
  76. }
  77. }
  78. impl Count {
  79. pub fn all() -> Self {
  80. Self {
  81. fighter: usize::MAX,
  82. bomber: usize::MAX,
  83. transporter: usize::MAX,
  84. }
  85. }
  86. pub fn none() -> Self {
  87. Self {
  88. fighter: 0,
  89. bomber: 0,
  90. transporter: 0,
  91. }
  92. }
  93. pub fn total(&self) -> usize {
  94. self.fighter
  95. .saturating_add(self.bomber)
  96. .saturating_add(self.transporter)
  97. }
  98. pub fn merge(&self, other: &Self) -> Self {
  99. Self {
  100. fighter: min(self.fighter, other.fighter),
  101. bomber: min(self.bomber, other.bomber),
  102. transporter: min(self.transporter, other.transporter),
  103. }
  104. }
  105. pub fn is_all(&self) -> bool {
  106. self.fighter == usize::MAX && self.bomber == usize::MAX && self.transporter == usize::MAX
  107. }
  108. }
  109. impl Index<usize> for Count {
  110. type Output = usize;
  111. fn index(&self, index: usize) -> &Self::Output {
  112. match index {
  113. 0 => &self.fighter,
  114. 1 => &self.bomber,
  115. 2 => &self.transporter,
  116. x => panic!("Invalid ship count index: {}", x),
  117. }
  118. }
  119. }
  120. impl IndexMut<usize> for Count {
  121. fn index_mut(&mut self, index: usize) -> &mut Self::Output {
  122. match index {
  123. 0 => &mut self.fighter,
  124. 1 => &mut self.bomber,
  125. 2 => &mut self.transporter,
  126. x => panic!("Invalid ship count index: {}", x),
  127. }
  128. }
  129. }
  130. impl Index<Type> for Count {
  131. type Output = usize;
  132. fn index(&self, index: Type) -> &Self::Output {
  133. match index {
  134. Type::Fighter => &self.fighter,
  135. Type::Bomber => &self.bomber,
  136. Type::Transporter => &self.transporter,
  137. }
  138. }
  139. }
  140. impl IndexMut<Type> for Count {
  141. fn index_mut(&mut self, index: Type) -> &mut Self::Output {
  142. match index {
  143. Type::Fighter => &mut self.fighter,
  144. Type::Bomber => &mut self.bomber,
  145. Type::Transporter => &mut self.transporter,
  146. }
  147. }
  148. }
  149. impl Mul<f32> for Count {
  150. type Output = Count;
  151. #[allow(unused_assignments)]
  152. fn mul(self, rhs: f32) -> Self::Output {
  153. let expected = self.total() as f32;
  154. let expected = (rhs * expected).ceil() as usize;
  155. let mut fighter = (rhs * self.fighter as f32) as usize;
  156. let mut bomber = (rhs * self.bomber as f32) as usize;
  157. let mut transporter = (rhs * self.transporter as f32) as usize;
  158. let mut actual = fighter.saturating_add(bomber).saturating_add(transporter);
  159. if actual < expected && fighter < self.fighter {
  160. fighter += 1;
  161. actual += 1;
  162. }
  163. if actual < expected && bomber < self.bomber {
  164. bomber += 1;
  165. actual += 1;
  166. }
  167. if actual < expected && transporter < self.transporter {
  168. transporter += 1;
  169. actual += 1;
  170. }
  171. Count {
  172. fighter,
  173. bomber,
  174. transporter,
  175. }
  176. }
  177. }