Advertisement
Guest User

Untitled

a guest
Nov 26th, 2014
152
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.25 KB | None | 0 0
  1. #ifndef SHIPWRECK_HH
  2. #define SHIPWRECK_HH
  3.  
  4. #include <algorithm>
  5. #include <cassert>
  6. #include <ostream>
  7. #include <tuple>
  8.  
  9. using number_t = unsigned int;
  10.  
  11. template <number_t Cannon, number_t Mast, number_t Oar>
  12. struct ShipGear {
  13.     static const number_t cannon = Cannon;
  14.     static const number_t mast = Mast;
  15.     static const number_t oar = Oar;
  16. };
  17.  
  18. using Cannon = ShipGear<1, 0, 0>;
  19. using Mast = ShipGear<0, 1, 0>;
  20. using Oar = ShipGear<0, 0, 1>;
  21.  
  22. template <typename G1, typename G2>
  23. struct add_gear {
  24.     using type = ShipGear<G1::cannon + G2::cannon, G1::mast + G2::mast, G1::oar + G2::oar>;
  25. };
  26.  
  27. constexpr number_t substract(number_t A, number_t B) {
  28.     return (B > A) ? 0 : A - B;
  29. }
  30.  
  31. template <typename G1, typename G2>
  32. struct remove_gear {
  33.     using type = ShipGear< substract(G1::cannon, G2::cannon), substract(G1::mast, G2::mast), substract(G1::oar, G2::oar) >;
  34. };
  35.  
  36. template <typename G1, unsigned int N>
  37. struct multiply_gear {
  38.     using type = ShipGear< G1::cannon * N, G1::mast * N, G1::oar * N>;
  39. };
  40.  
  41. template <typename G1, unsigned int N>
  42. struct split_gear {
  43.     static_assert(N != 0, "N must not be zero");
  44.  
  45.     using type = ShipGear< G1::cannon / N, G1::mast / N, G1::oar / N>;
  46. };
  47.  
  48. template <typename Gear>
  49. class Squad {
  50.     public:
  51.         using gear_type = Gear;
  52.  
  53.         Squad(): Squad(1) {}
  54.         explicit Squad(const unsigned int count): count(count) {}
  55.  
  56.         unsigned int get_count() const {
  57.             return count;
  58.         }
  59.  
  60.         static gear_type gear;
  61.  
  62.         Squad& operator += (const Squad& other) {
  63.             count += other.get_count();
  64.             return *this;
  65.         }
  66.  
  67.         Squad& operator -= (const Squad& other) {
  68.             if(other.get_count() > count) {
  69.                 count = 0;
  70.             } else {
  71.                 count -= other.get_count();
  72.             }
  73.             return *this;
  74.         }
  75.  
  76.         Squad& operator *= (const unsigned int value) {
  77.             count *= value;
  78.  
  79.             return *this;
  80.         }
  81.  
  82.         Squad& operator /= (const unsigned int value) {
  83.             assert(value != 0);
  84.  
  85.             count /= value;
  86.  
  87.             return *this;
  88.         }
  89.  
  90.     private:
  91.         unsigned int count;
  92. };
  93.  
  94. template <typename Gear>
  95. const Squad<Gear> operator + (Squad<Gear> S1, const Squad<Gear>& S2) {
  96.     return S1 += S2;
  97. }
  98.  
  99. template <typename Gear>
  100. const Squad<Gear> operator - (Squad<Gear> S1, const Squad<Gear>& S2) {
  101.     return S1 -= S2;
  102. }
  103.  
  104. template <typename Gear>
  105. const Squad<Gear> operator * (Squad<Gear> S, const unsigned int value) {
  106.     return S *= value;
  107. }
  108.  
  109. template <typename Gear>
  110. const Squad<Gear> operator / (Squad<Gear> S, const unsigned int value) {
  111.     return S /= value;
  112. }
  113.  
  114. template <typename G1, typename G2>
  115. bool operator == (const Squad<G1>& S1, const Squad<G2>& S2) {
  116.     return G1::cannon == G2::cannon &&
  117.            G1::mast == G2::mast &&
  118.            G1::oar == G2::oar &&
  119.            S1.get_count() == S2.get_count();
  120. }
  121.  
  122. template <typename G1, typename G2>
  123. bool operator != (const Squad<G1>& S1, const Squad<G2>& S2) {
  124.     return ! (S1 == S2);
  125. }
  126.  
  127. template <typename G1, typename G2>
  128. bool operator < (const Squad<G1>& S1, const Squad<G2>& S2) {
  129.     if(G1::cannon == G2::cannon && G1::mast == G2::mast && G1::oar == G2::oar)
  130.         return S1.get_count() < S2.get_count();
  131.     return G1::cannon < G2::cannon;
  132. }
  133.  
  134. template <typename G1, typename G2>
  135. bool operator > (const Squad<G1>& S1, const Squad<G2>& S2) {
  136.     return S2 < S1;
  137. }
  138.  
  139. template <typename G1, typename G2>
  140. bool operator <= (const Squad<G1>& S1, const Squad<G2>& S2) {
  141.     return !(S1 > S2);
  142. }
  143. template <typename G1, typename G2>
  144. bool operator >= (const Squad<G1>& S1, const Squad<G2>& S2) {
  145.     return S2 <= S1;
  146. }
  147.  
  148. template <typename Gear>
  149. std::ostream& operator << (std::ostream& out, const Squad<Gear>& S) {
  150.     return out << "Ships: " << S.get_count() << "; Ship gear: Cannons: " << Gear::cannon << ", Masts: " << Gear::mast << ", Oars: " << Gear::oar;
  151. }
  152.  
  153. template <typename Gear, typename OtherGear>
  154. auto join_ships(const Squad<Gear>& S1, const Squad<OtherGear>& S2) -> const Squad<typename add_gear<Gear, OtherGear>::type > {
  155.     using result_type = typename add_gear<Gear, OtherGear>::type;
  156.  
  157.     unsigned int total_cannons = Gear::cannon * S1.get_count() + OtherGear::cannon * S2.get_count();
  158.     unsigned int total_masts = Gear::mast * S1.get_count() + OtherGear::mast * S2.get_count();
  159.     unsigned int total_oars = Gear::oar * S1.get_count() + OtherGear::oar * S2.get_count();
  160.  
  161.     std::vector<unsigned int> min_candidates;
  162.     if(result_type::cannon != 0) min_candidates.emplace_back(total_cannons / result_type::cannon);
  163.     if(result_type::mast != 0) min_candidates.emplace_back(total_masts / result_type::mast);
  164.     if(result_type::oar != 0) min_candidates.emplace_back(total_oars / result_type::oar);
  165.     min_candidates.emplace_back(S1.get_count() + S2.get_count());
  166.  
  167.     unsigned int ship_number = *min_element(min_candidates.begin(), min_candidates.end());
  168.  
  169.     return Squad<result_type>{ship_number};
  170. }
  171.  
  172. template <typename Gear>
  173. auto split_ships(const Squad<Gear>& S) -> const Squad<typename split_gear<Gear, 2>::type > {
  174.     using result_type = typename split_gear<Gear, 2>::type;
  175.  
  176.     return Squad<result_type>(S.get_count());
  177. }
  178.  
  179. template <typename G1, typename G2>
  180. constexpr int do_compare() {
  181.     return
  182.         (G1::cannon < G2::cannon) ? -1 :
  183.         (G1::cannon > G2::cannon) ? +1 :
  184.         (G1::mast < G2::mast) ? -1 :
  185.         (G1::mast > G2::mast) ? +1 :
  186.         (G1::oar < G2::oar) ? -1 :
  187.         (G1::oar > G2::oar) ? +1 :
  188.         0;
  189. }
  190.  
  191. template <typename G1, typename G2>
  192. struct compare {
  193.     static const int value = do_compare<G1, G2>();
  194. };
  195.  
  196. template <typename G1, typename G2, int = compare<G1, G2>::value>
  197. struct expected_booty_impl {
  198.     using result_type = Squad<G1>;
  199.     static const Squad<G1> expected_booty(const Squad<G1>& S1, const Squad<G2>&) {
  200.         return S1;
  201.     }
  202. };
  203.  
  204. template <typename G1>
  205. struct expected_booty_impl<G1, G1, 0> {
  206.     using result_type = Squad<G1>;
  207.     static const Squad<G1> expected_booty(const Squad<G1>& S1, const Squad<G1>& S2) {
  208.         if(S1.get_count() < S2.get_count())
  209.             return S1;
  210.         else
  211.             return S2;
  212.     }
  213. };
  214.  
  215. template <typename G1, typename G2>
  216. struct expected_booty_impl<G1, G2, 1> {
  217.     using result_type = Squad<G2>;
  218.     static const Squad<G2> expected_booty(const Squad<G1>&, const Squad<G2>& S2) {
  219.         return S2;
  220.     }
  221. };
  222.  
  223. template <typename G1, typename G2>
  224. auto expected_booty(const Squad<G1>& S1, const Squad<G2>& S2) -> const typename expected_booty_impl<G1, G2>::result_type {
  225.     return expected_booty_impl<G1, G2>::expected_booty(S1, S2);
  226. }
  227.  
  228. #endif /* SHIPWRECK_HH */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement