Libsaki
Core library of Pancake Mahjong
comeld.h
1 #ifndef SAKI_COMELD_H
2 #define SAKI_COMELD_H
3 
4 #include "tile.h"
5 
6 #include <algorithm>
7 
8 
9 
10 namespace saki
11 {
12 
13 
14 
18 class C34
19 {
20 public:
30  enum class Type
31  {
32  SEQ, TRI, BIFACE, CLAMP, SIDE, PAIR, FREE
33  };
34 
36  C34()
37  {
38  }
39 
40  C34(Type type, T34 head)
41  : mType(type)
42  , mHead(head)
43  {
44 #ifndef NDEBUG
45  int v = head.val();
46  bool num = head.isNum();
47  assert((type != Type::SEQ || (num && v <= 7))
48  && (type != Type::BIFACE || (num && 2 <= v && v <= 7))
49  && (type != Type::CLAMP || (num && v <= 7))
50  && (type != Type::SIDE || (num && (v == 1 || v == 8))));
51 #endif
52  }
53 
54  C34(const C34 &copy) = default;
55  C34 &operator=(const C34 &assign) = default;
56  ~C34() = default;
57 
58  Type type() const
59  {
60  return mType;
61  }
62 
63  T34 head() const
64  {
65  return mHead;
66  }
67 
68  int work() const
69  {
70  switch (mType) {
71  case Type::SEQ:
72  case Type::TRI:
73  return 2;
74  case Type::BIFACE:
75  case Type::CLAMP:
76  case Type::SIDE:
77  case Type::PAIR:
78  return 1;
79  default:
80  return 0;
81  }
82  }
83 
84  util::Stactor<T34, 3> t34s() const
85  {
86  // save typing
87  const T34 h = mHead;
88 
89  switch (mType) {
90  case Type::SEQ:
91  return { h, h.next(), h.nnext() };
92  case Type::TRI:
93  return { h, h, h };
94  case Type::BIFACE:
95  return { h, h.next() };
96  case Type::CLAMP:
97  return { h, h.nnext() };
98  case Type::SIDE:
99  return { h, h.next() };
100  case Type::PAIR:
101  return { h, h };
102  case Type::FREE:
103  return { h };
104  default:
105  unreached();
106  }
107  }
108 
113  {
114  // save typing
115  const T34 h = mHead;
116  const int v = h.val();
117 
118  switch (mType) {
119  case Type::SEQ:
120  return {};
121  case Type::TRI:
122  return {};
123  case Type::BIFACE:
124  return { h.prev(), h.nnext() };
125  case Type::CLAMP:
126  return { h.next() };
127  case Type::SIDE:
128  return { h.val() == 1 ? h.nnext() : h.prev() };
129  case Type::PAIR:
130  return { h };
131  case Type::FREE:
132  if (h.isZ())
133  return { h };
134  else if (v == 1)
135  return { h, h.next(), h.nnext() };
136  else if (v == 2)
137  return { h.prev(), h, h.next(), h.nnext() };
138  else if (v == 8)
139  return { h.pprev(), h.prev(), h, h.next() };
140  else if (v == 9)
141  return { h.pprev(), h.prev(), h };
142  else // 3 ~ 7
143  return { h.pprev(), h.prev(), h, h.next(), h.nnext() };
144  default:
145  unreached();
146  }
147  }
148 
149  bool has(T34 t) const
150  {
151  const auto &ts = t34s();
152  return std::find(ts.begin(), ts.end(), t) != ts.end();
153  }
154 
155  bool is3() const
156  {
157  return mType == Type::SEQ || mType == Type::TRI;
158  }
159 
160  bool is2() const
161  {
162  return isSeq2() || mType == Type::PAIR;
163  }
164 
165  bool isSeq2() const
166  {
167  return mType == Type::BIFACE || mType == Type::CLAMP || mType == Type::SIDE;
168  }
169 
173  util::Stactor<T34, 3> tilesTo(const C34 &that) const
174  {
175  return tilesTo(that.t34s());
176  }
177 
182  {
184  auto need = [this](T34 t) { return !has(t); };
185  std::copy_if(tar.begin(), tar.end(), std::back_inserter(res), need);
186  return res;
187  }
188 
189  bool operator==(const C34 &that) const
190  {
191  return mType == that.mType && mHead == that.mHead;
192  }
193 
194  bool operator!=(const C34 &that) const
195  {
196  return !(*this == that);
197  }
198 
199  bool operator<(const C34 &that) const
200  {
201  if (mType != that.mType) {
202  int a = static_cast<int>(mType);
203  int b = static_cast<int>(that.mType);
204  return a < b;
205  }
206 
207  return mHead < that.mHead;
208  }
209 
210 private:
211  Type mType;
212  T34 mHead;
213 };
214 
215 
216 
217 inline std::ostream &operator<<(std::ostream &os, C34 c)
218 {
219  int v = c.head().val();
220  char s = T34::charOf(c.head().suit());
221  switch (c.type()) {
222  case C34::Type::SEQ:
223  return os << v << (v + 1) << (v + 2) << s;
224  case C34::Type::TRI:
225  return os << v << v << v << s;
226  case C34::Type::BIFACE:
227  return os << v << (v + 1) << s;
228  case C34::Type::CLAMP:
229  return os << v << (v + 2) << s;
230  case C34::Type::SIDE:
231  return os << v << (v + 1) << s;
232  case C34::Type::PAIR:
233  return os << v << v << s;
234  case C34::Type::FREE:
235  return os << c.head();
236  default:
237  unreached();
238  }
239 }
240 
241 template<size_t MAX>
242 inline std::ostream &operator<<(std::ostream &os, const util::Stactor<C34, MAX> &cs)
243 {
244  bool first = true;
245 
246  for (C34 c : cs) {
247  if (first)
248  first = false;
249  else
250  os << ' ';
251 
252  os << c;
253  }
254 
255  return os;
256 }
257 
258 
259 
260 } // namespace saki
261 
262 
263 
264 #endif // SAKI_COMELD_H
util::Stactor< T34, 5 > effA4() const
Get first-class effective tiles assuming this comeld is a waiter.
Definition: comeld.h:112
util::Stactor< T34, 3 > tilesTo(const util::Stactor< T34, 3 > &tar) const
Tiles needed to form this to tar.
Definition: comeld.h:181
util::Stactor< T34, 3 > tilesTo(const C34 &that) const
Tiles needed to transform from this into that.
Definition: comeld.h:173
Comeld, a meld or a part of a meld.
Definition: comeld.h:18
Definition: tile.h:25
Type
Definition: comeld.h:30
Definition: ai.cpp:18
Stactor = statically allocated vector.
Definition: stactor.h:247
C34()
Garbage value.
Definition: comeld.h:36