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