MFMv2.0.10
Movable Feast Machine Simulator 2.0.10
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Element_MQBar.h
1 #ifndef ELEMENT_MQBAR_H /* -*- C++ -*- */
2 #define ELEMENT_MQBAR_H
3 
4 #include "Element.h"
5 #include "EventWindow.h"
6 #include "ElementTable.h"
7 #include "Element_Empty.h"
8 #include "Element_Res.h"
9 #include "itype.h"
10 #include "FXP.h"
11 #include "P3Atom.h"
12 #include "ColorMap.h"
13 
14 namespace MFM
15 {
16 
17 #define QBAR_VERSION 4
18 
48  template <class CC>
49  class Element_MQBar : public Element<CC>
50  {
51  // Extract short names for parameter types
52  typedef typename CC::ATOM_TYPE T;
53  typedef typename CC::PARAM_CONFIG P;
54  enum { R = P::EVENT_WINDOW_RADIUS };
55 
56  template <u32 TVBITS>
57  static u32 toMag(u32 value) {
58  const u32 MAX = (1<<TVBITS)-1;
59  if (value < 0) {
60  FAIL(ILLEGAL_ARGUMENT);
61  }
62  if (value > MAX)
63  value = MAX;
64  u32 val = value;
65  return val;
66  }
67 
68  template <u32 TVBITS>
69  static u32 fromMag(const u32 value) {
70  const u32 MASK = (1<<TVBITS)-1;
71  u32 val = value&MASK;
72  return val;
73  }
74 
75  template <u32 TXBITS, u32 TYBITS>
76  static u32 toUTiny(const UPoint & v) {
77  u32 x = toMag<TXBITS>(v.GetX());
78  u32 y = toMag<TYBITS>(v.GetY());
79  return (x<<TYBITS)|y;
80  }
81 
82  template <u32 TXBITS, u32 TYBITS>
83  static UPoint toUPoint(const u32 bits) {
84 
85  u32 x = fromMag<TXBITS>(bits>>TYBITS);
86  u32 y = fromMag<TYBITS>(bits);
87  return UPoint(x,y);
88  }
89 
90  public:
91 
92  static Element_MQBar THE_INSTANCE;
93  static const u32 TYPE() {
94  return THE_INSTANCE.GetType();
95  }
96 
97  static bool IsOurType(u32 type) {
98  return type==TYPE();
99  }
100 
101  static const u32 BITS_WIDE = 5;
102  static const u32 BITS_HIGH = 7;
103  static const u32 BITS_SYMI = 2;
104 
105  static const u32 BITS_TIMER = 4; // Slow down the timer
106  static const u32 MAX_TIMER_VALUE = 9; //(1<<BITS_TIMER)-1;
107 
108  static const u32 BITS_BAR_COORD_LEN = BITS_WIDE + BITS_HIGH;
109 
110  static const u32 STATE_BITS_START = P3Atom<P>::P3_STATE_BITS_POS;
112 
117 
118  static const u32 STATE_BITS_END = AFTimer::END;
119  static const u32 STATE_BITS_COUNT = STATE_BITS_END - STATE_BITS_START + 1;
120 
121  Element_MQBar() :
122  Element<CC>(MFM_UUID_FOR("MQBar", QBAR_VERSION))
123  {
124  LOG.Message("%@ ctor %p", &this->GetUUID(), this);
125 
127  }
128 
129  u32 GetSymI(const T &atom) const {
130  if (!IsOurType(atom.GetType()))
131  FAIL(ILLEGAL_STATE);
132  return AFSymI::Read(this->GetBits(atom));
133  }
134 
135  SPoint GetMax(const T &atom) const {
136  if (!IsOurType(atom.GetType()))
137  FAIL(ILLEGAL_STATE);
138  return MakeSigned(toUPoint<BITS_WIDE,BITS_HIGH>(AFSize::Read(this->GetBits(atom))));
139  }
140 
141  SPoint GetPos(const T &atom) const {
142  if (!IsOurType(atom.GetType()))
143  FAIL(ILLEGAL_STATE);
144  return MakeSigned(toUPoint<BITS_WIDE,BITS_HIGH>(AFPos::Read(this->GetBits(atom))));
145  }
146 
147  u32 GetTimer(const T &atom) const {
148  if (!IsOurType(atom.GetType()))
149  FAIL(ILLEGAL_STATE);
150  return AFTimer::Read(this->GetBits(atom));
151  }
152 
153  bool FitsInRep(const SPoint & v) const {
154  return v.BoundedBy(SPoint(0,0),SPoint(MakeMaskClip(BITS_WIDE),MakeMaskClip(BITS_HIGH)));
155  }
156 
157  void SetSize(T &atom, const SPoint & v) const {
158  if (!IsOurType(atom.GetType()))
159  FAIL(ILLEGAL_STATE);
160  if (!FitsInRep(v))
161  FAIL(ILLEGAL_ARGUMENT);
162  AFSize::Write(this->GetBits(atom),toUTiny<BITS_WIDE,BITS_HIGH>(MakeUnsigned(v)));
163  }
164 
165  void SetPos(T &atom, const SPoint v) const {
166  if (!IsOurType(atom.GetType()))
167  FAIL(ILLEGAL_STATE);
168  if (!FitsInRep(v))
169  FAIL(ILLEGAL_ARGUMENT);
170  AFPos::Write(this->GetBits(atom),toUTiny<BITS_WIDE,BITS_HIGH>(MakeUnsigned(v)));
171  }
172 
173  void SetSymI(T &atom, const u32 sym) const {
174  if (!IsOurType(atom.GetType()))
175  FAIL(ILLEGAL_STATE);
176  if (sym >= PSYM_SYMMETRY_COUNT)
177  FAIL(ILLEGAL_ARGUMENT);
178  AFSymI::Write(this->GetBits(atom),sym);
179  }
180 
181  void SetTimer(T &atom, const u32 tmr) const {
182  if (!IsOurType(atom.GetType()))
183  FAIL(ILLEGAL_STATE);
184  if (tmr > MAX_TIMER_VALUE)
185  FAIL(ILLEGAL_ARGUMENT);
186  AFTimer::Write(this->GetBits(atom),tmr);
187  }
188 
189  virtual const T & GetDefaultAtom() const
190  {
191  static T defaultAtom(TYPE(), 0, 0, STATE_BITS_COUNT);
192  const SPoint QBAR_SIZE(27, 3 * 27);
193  SetSize(defaultAtom, QBAR_SIZE);
194  SetPos(defaultAtom, QBAR_SIZE / 4);
195  SetSymI(defaultAtom, 0);
196  return defaultAtom;
197  }
198 
199  virtual T BuildDefaultAtom() const
200  {
201  T atom = GetDefaultAtom();
202  return atom;
203  }
204 
205  virtual u32 DefaultPhysicsColor() const
206  {
207  return 0xffffff00;
208  }
209 
210  virtual u32 DefaultLowlightColor() const
211  {
212  return 0xff7f7f00;
213  }
214 
215  virtual u32 PercentMovable(const T& you, const T& me, const SPoint& offset) const
216  {
217  return 0;
218  }
219 
220 
221  virtual u32 LocalPhysicsColor(const T & atom, u32 selector) const
222  {
223  switch (selector) {
224  case 1: {
225  SPoint barMax = GetMax(atom);
226  SPoint myPos = GetPos(atom);
227  return ColorMap_SEQ6_PuRd::THE_INSTANCE.
228  GetInterpolatedColor(myPos.GetEuclideanLength(),
229  0,barMax.GetEuclideanLength(),
230  0xffff0000);
231  }
232  default:
233  {
234  u32 timer = GetTimer(atom);
235  return ColorMap_SEQ6_GnBu::THE_INSTANCE.
236  GetInterpolatedColor(timer,0,MAX_TIMER_VALUE - 1, Element<CC>::PhysicsColor());
237  }
238  }
239  return 0x0;
240  }
241 
245  virtual u32 Diffusability(EventWindow<CC> & ew, SPoint nowAt, SPoint maybeAt) const {
246  return this->NoDiffusability(ew, nowAt, maybeAt);
247  }
248 
249  virtual void Behavior(EventWindow<CC>& window) const
250  {
251  // Get self, sanity check
252  T self = window.GetCenterAtom();
253  const u32 selfType = self.GetType();
254  if (!IsOurType(selfType)) FAIL(ILLEGAL_STATE);
255 
256  u32 ourTimer = this->GetTimer(self);
257 
258  // Establish our symmetry before non-self access through window
259  u32 symi = this->GetSymI(self);
260  window.SetSymmetry((PointSymmetry) symi);
261 
262  Random & random = window.GetRandom();
263 
264  SPoint barMax = this->GetMax(self);
265  SPoint myPos = this->GetPos(self);
266 
267  const MDist<R> md = MDist<R>::get();
268 
269  SPoint anInconsistent;
270  u32 inconsistentCount = 0;
271  T unmakeGuy;
272 
273  u32 consistentCount = 0;
274 
275  SPoint toMake;
276  T makeGuy;
277  u32 makeCount = 0;
278 
279  SPoint toEat;
280  u32 eatCount = 0;
281 
282  bool neighborTimer = false;
283  u32 minTimer = 0;
284  u32 maxTimer = 0;
285 
286  // Scan event window outside self
287  for (u32 idx = md.GetFirstIndex(1); idx <= md.GetLastIndex(R); ++idx) {
288  const SPoint sp = md.GetPoint(idx);
289 
290  // First question: A 'bar grid' site?
291  bool onGrid = (sp.GetX()&1)==0 && (sp.GetY()&1)==0;
292 
293  // Second question: Inside _our_ bar?
294  const SPoint theirBarPos = sp+myPos;
295  bool inBar = theirBarPos.BoundedBy(SPoint(0,0),barMax);
296 
297  if (onGrid) {
298  // Next question: Site within the bounds of the bar?
299 
300  if (inBar) {
301  // Next question: Site empty?
302 
303  const T other = window.GetRelativeAtom(sp);
304  const u32 otherType = other.GetType();
305 
306  bool isEmpty = Element_Empty<CC>::THE_INSTANCE.IsType(otherType);
307 
308  if (isEmpty) {
309 
310  if (random.OneIn(++makeCount)) {
311  toMake = sp;
312  makeGuy = self; // Start with us
313  SetPos(makeGuy,theirBarPos); // Update position
314  SetTimer(makeGuy, 0); // They are young
315  }
316 
317  } else {
318 
319  // Next question: Are they also a bar?
320  if (IsOurType(otherType)) {
321 
322  // Next question: Are they consistent with us?
323 
324  SPoint otherBarMax = GetMax(other);
325  SPoint otherPos = GetPos(other);
326 
327  SPoint otherPosMapped = otherPos-sp;
328  u32 otherTimer = GetTimer(other);
329 
330  if (otherBarMax==barMax && otherPosMapped == myPos) {
331  ++consistentCount;
332 
333  // They are consistent. Inspect their timer
334  if (!neighborTimer || otherTimer < minTimer)
335  minTimer = otherTimer;
336  if (!neighborTimer || otherTimer > maxTimer)
337  maxTimer = otherTimer;
338  neighborTimer = true;
339 
340  } else {
341  u32 otherTimer = GetTimer(other);
342 
343  // An inconsistent guy younger than us decays
344  if (otherTimer < ourTimer && random.OneIn(++inconsistentCount)) {
345  anInconsistent = sp;
346  // Inconsistent Bars decay to Res
348  }
349  }
350  }
351 
352  }
353  }
354  } else {
355  // This is a non-grid site. If it's in our bar, We'd kind
356  // of like it to be Res, and if not that, empty, but we'd
357  // really like it not to have Bar's in it
358 
359  if (inBar) {
360  const T other = window.GetRelativeAtom(sp);
361  const u32 otherType = other.GetType();
362 
363  bool isRes = otherType == Element_Res<CC>::TYPE();
364  if (isRes) {
365  ++consistentCount;
366  if (random.OneIn(++eatCount)) {
367  toEat = sp;
368  }
369  }
370  else {
371 
372  bool isEmpty = Element_Empty<CC>::THE_INSTANCE.IsType(otherType);
373 
374  if (isEmpty) ++consistentCount;
375  else {
376  bool iQBar = IsOurType(otherType);
377  if (iQBar) {
378  u32 iQBarTimer = GetTimer(other);
379  if (iQBarTimer < ourTimer && random.OneIn(++inconsistentCount)) {
380  anInconsistent = sp;
382  }
383  }
384  }
385  }
386  }
387  }
388  }
389 
390  // Scan finished. Let's decide what to do.
391 
392  // First question: Are we inconsistent with anybody?
393  if (inconsistentCount > 0) {
394 
395  // Next question: Are we much more consistent than inconsistent?
396  if (consistentCount > 3 * inconsistentCount) {
397 
398  // Yes. Punish selected loser
399  window.SetRelativeAtom(anInconsistent, unmakeGuy);
400 
401  } else if (inconsistentCount > 3 * consistentCount) {
402 
403  // If we're way inconsistent, let's res out and let them have us
405 
406  } else {
407 
408 #if 0
409  // We're neither way consistent nor way inconsistent. We
410  // will survive but dock our timer
411  u32 ourTimer = GetTimer(self);
412  if (ourTimer > 0) {
413  if (neighborTimer && minTimer < ourTimer)
414  ourTimer = minTimer;
415  else
416  --ourTimer;
417  SetTimer(self,ourTimer);
418  window.SetCenterAtom(self);
419  }
420 #endif
421  }
422  } else {
423  // No inconsistencies. Do we have something to make, and eat?
424  if (makeCount > 0 && eatCount > 0) {
425  window.SetRelativeAtom(toMake, makeGuy);
427  }
428  else {
429  // Super-special case: Are we the max corner and all consistent?
430  if (myPos == barMax-SPoint(1,1)) {
431  // Is there an empty off end to us?
432  SPoint offset(0,2);
433  T offEnd = window.GetRelativeAtom(offset);
434  const u32 offType = offEnd.GetType();
435  if (Element_Empty<CC>::THE_INSTANCE.IsType(offType) && eatCount > 0) {
436  T corner = self;
437  u32 symi = GetSymI(self);
438  ++symi;
439  if (symi > PSYM_DEG270L)
440  symi = PSYM_DEG000L;
441  SetSymI(corner,symi);
442  SetPos(corner,SPoint(0,0));
443  SetTimer(corner,0);
444  window.SetRelativeAtom(offset, corner);
446  }
447  }
448  {
449  // We are alllll good, with nothing to do. What is our timer situation?
450  u32 ourTimer = GetTimer(self);
451  if (ourTimer < MAX_TIMER_VALUE && (ourTimer==0 || (neighborTimer && minTimer+1 >= ourTimer))) {
452  if (random.OneIn(ourTimer+1)) {
453  ++ourTimer;
454  SetTimer(self,ourTimer);
455  window.SetCenterAtom(self);
456  }
457  }
458  }
459  }
460  }
461 
462  }
463 
464  };
465 
466  template <class CC>
467  Element_MQBar<CC> Element_MQBar<CC>::THE_INSTANCE;
468 
469 }
470 
471 #endif /* ELEMENT_MQBAR_H */
u32 GetFirstIndex(const u32 radius) const
Definition: MDist.h:112
static void Write(BV &bv, u32 val)
Definition: BitField.h:84
Definition: Element_MQBar.h:49
virtual u32 DefaultLowlightColor() const
Definition: Element_MQBar.h:210
virtual const T & GetDefaultAtom() const
Definition: Element_MQBar.h:189
u32 GetType() const
Definition: Element.h:290
virtual u32 DefaultPhysicsColor() const
Definition: Element_MQBar.h:205
Definition: Element_Empty.h:41
static u32 Read(const BV &bv)
Definition: BitField.h:73
Definition: Random.h:45
u32 GetLastIndex(const u32 radius) const
Definition: MDist.h:129
void SetSymmetry(const PointSymmetry psym)
Definition: EventWindow.h:110
void SetCenterAtom(const T &atom)
Definition: EventWindow.h:220
u32 NoDiffusability(EventWindow< CC > &ew, SPoint nowAt, SPoint maybeAt) const
Definition: Element.h:508
void SetAtomicSymbol(const char *symbol)
Definition: Element.h:193
bool BoundedBy(const Point< T > &lowerBound, const Point< T > &upperBound) const
Definition: Point.tcc:223
bool OneIn(u32 odds)
Definition: Random.h:96
T GetY() const
Definition: Point.tcc:40
Random & GetRandom()
Definition: EventWindow.h:122
const T & GetRelativeAtom(const SPoint &offset) const
Definition: EventWindow.tcc:26
Definition: Atom.h:45
const T & GetCenterAtom() const
Definition: EventWindow.h:209
const UUID & GetUUID() const
Definition: Element.h:355
virtual const T & GetDefaultAtom() const
Definition: Element.h:382
Definition: MDist.h:69
bool IsType(u32 type) const
Definition: Element.h:345
virtual u32 LocalPhysicsColor(const T &atom, u32 selector) const
Definition: Element_MQBar.h:221
static MDist< R > & get()
Definition: MDist.tcc:193
virtual T BuildDefaultAtom() const
Definition: Element_MQBar.h:199
virtual u32 Diffusability(EventWindow< CC > &ew, SPoint nowAt, SPoint maybeAt) const
Definition: Element_MQBar.h:245
Definition: Element_Res.h:48
Definition: ElementTable.h:43
Definition: BitVector.h:47
double GetEuclideanLength() const
Definition: Point.tcc:58
void Message(const char *format,...)
Definition: Logger.h:287
const BitVector< P::BITS_PER_ATOM > & GetBits(const T &atom) const
Definition: Element.h:132
bool SetRelativeAtom(const SPoint &offset, const T &atom)
Definition: EventWindow.tcc:15
Definition: P3Atom.h:44
Definition: Atom.h:43
virtual u32 PercentMovable(const T &you, const T &me, const SPoint &offset) const
Definition: Element_MQBar.h:215
virtual void Behavior(EventWindow< CC > &window) const
Definition: Element_MQBar.h:249
T GetX() const
Definition: Point.tcc:34