HOG2
Witness.h
Go to the documentation of this file.
1 //
2 // Witness.h
3 // hog2 glut
4 //
5 // Created by Nathan Sturtevant on 10/20/18.
6 // Copyright © 2018 University of Denver. All rights reserved.
7 //
8 #ifndef HOG2_ENVIRONMENTS_WITNESS_H
9 #define HOG2_ENVIRONMENTS_WITNESS_H
10 
11 #include <algorithm>
12 #include <array>
13 #include <bitset>
14 #include <cassert>
15 #include <cstring>
16 #include <iostream>
17 #include <numeric>
18 #include <regex>
19 #include <sstream>
20 #include <string>
21 
22 #include "SearchEnvironment.h"
23 #include "vectorCache.h"
24 
25 template<int width, int height>
26 int GetEdgeHash(bool horizontal, int x, int y)
27 {
28  return (horizontal) ? y * (width) + x : width * (height + 1) + y * (width + 1) + x;
29 }
30 
31 template<int width, int height>
32 int GetEdgeHash(int x1, int y1, int x2, int y2)
33 {
34  if (y1 == y2)
35  return GetEdgeHash<width, height>(true, std::min(x1, x2), y1);
36  else if (x1 == x2)
37  return GetEdgeHash<width, height>(false, x1, std::min(y1, y2));
38  assert(false);
39 }
40 
41 template<int width, int height>
42 class WitnessState {
43 public:
44  std::vector<std::pair<int, int>> path;
45  std::bitset<(width + 1) * (height + 1)> occupiedCorners;
46  std::bitset<(width + 1) * (height) + (width) * (height + 1)> occupiedEdges;
47 
49 
51  {
52  path = state.path;
55  }
56 
57  void Reset()
58  {
59  path.resize(0);
60  occupiedCorners.reset();
61  occupiedEdges.reset();
62  }
63 
64  bool Occupied(int which)
65  {
66  if (which < width * (height + 1))
67  {
68  int x = which % (width);
69  int y = which / (width);
70  return OccupiedEdge(x, y, x + 1, y);
71  }
72  which -= width * (height + 1);
73  if (which < (width + 1) * height)
74  {
75  int x = which % (width + 1);
76  int y = which / (width + 1);
77  return OccupiedEdge(x, y, x, y + 1);
78  }
79  which -= (width + 1) * height;
80  // constraint on corner
81  int x = which % (width + 1);
82  int y = which / (width + 1);
83  return Occupied(x, y);
84  // AddCannotCrossConstraint(x, y);
85  }
86 
87  bool isAlongTheWall() const
88  {
89  if (path.size() < 2)
90  return false;
91  auto &prevPos = path[path.size() - 2];
92  auto &currPos = path.back();
93  return ((currPos.first == 0 || currPos.first == width) && currPos.first == prevPos.first) ||
94  ((currPos.second == 0 || currPos.second == height) && currPos.second == prevPos.second);
95  }
96 
97  bool hitTheWall() const
98  {
99  if (path.size() <= 1)
100  return false;
101  auto &p = path.back();
102  return (p.first == 0 || p.first == width) ||
103  (p.second == 0 || p.second == height);
104  }
105 
106  bool Occupied(int x, int y) const { return occupiedCorners[y * (width + 1) + x]; }
107 
108  void Occupy(int x, int y) { occupiedCorners.set(y * (width + 1) + x, true); }
109 
110  void Unoccupy(int x, int y)
111  {
112  if (x >= 0 && x <= width && y >= 0 && y <= height) occupiedCorners.set(y * (width + 1) + x, false);
113  }
114 
115  bool OccupiedEdge(int x1, int y1, int x2, int y2) const
116  {
117  return occupiedEdges[GetEdgeHash<width, height>(x1, y1, x2, y2)];
118  }
119 
120  void OccupyEdge(int x1, int y1, int x2, int y2) { occupiedEdges.set(GetEdgeHash<width, height>(x1, y1, x2, y2)); }
121 
122  void UnoccupyEdge(int x1, int y1, int x2, int y2)
123  {
124  occupiedEdges.set(GetEdgeHash<width, height>(x1, y1, x2, y2), false);
125  }
126 
127  bool InGoal() const
128  {
129  return path.back().first < 0 || path.back().first > width ||
130  path.back().second < 0 || path.back().second > height;
131  }
132 };
133 
141 };
142 
143 template<int width, int height>
145 {
146  return a == b;
147 }
148 
149 template<int width, int height>
151 public:
152  void Reset()
153  {
154  ws.Reset();
155  frac = 0;
157  }
158 
160  {
161  if (currState != kWaitingStart) return;
162  frac += 0.04;
163  if (frac > 3) frac = 0;
164  }
165 
167  // for drawing
168  float frac;
169  std::pair<int, int> target; // where we are heading next
171 
177  };
179 };
180 
184  kStar = 2,
185  kTetris = 3,
188  kEraser = 6,
190 };
191 
194  int parameter{};
196 
197  bool operator==(const WitnessRegionConstraint &a) const
198  {
199  return a.t == this->t && a.parameter == this->parameter && a.c == this->c;
200  }
201  bool operator!=(const WitnessRegionConstraint &a) const
202  {
203  return !(*this == a);
204  }
205  operator std::string() const
206  {
207  std::stringstream ss;
208  ss << "{\"type\":" << t << ",\"param\":" << parameter << ",\"color\":\"" << c.hex() << "\"}";
209  return ss.str();
210  }
211 };
212 
218 };
219 
220 template<int width, int height>
221 class Witness : public SearchEnvironment<WitnessState<width, height>, WitnessAction> {
222 public:
223  enum legality {
231  };
232 
233  // Must cross edge/node
235  bool horiz;
236  std::pair<int, int> location;
237 
239  {
240  return a.horiz == this->horiz && a.location == this->location;
241  }
242  };
243 
244  /* Hexagon constraints - path must cross this point */
245  static constexpr int GetNumPathConstraints();
246 
247  std::array<WitnessPathConstraintType, Witness<width, height>::GetNumPathConstraints()> pathConstraints;
248  std::array<std::pair<Graphics::point, Graphics::rect>,
250 
251  // std::vector<mustCrossEdgeConstraint> mustCrossEdgeConstraints;
252  // std::vector<std::pair<int, int>> mustCrossConstraints;
253  //
254  // std::vector<mustCrossEdgeConstraint> cannotCrossEdgeConstraints;
255  // std::vector<std::pair<int, int>> cannotCrossConstraints;
256 
259 
260  bool valid;
262  };
263 
264  std::array<std::array<WitnessRegionConstraint, height>, width> regionConstraints;
265  // constraint constraints[width][height];
267 
268  // TODO: merge these
269  // std::vector<separationObject> separationConstraints;
270  // int separationCount;
271  //
272  // std::vector<int> tetrisConstraints;
273  // int tetrisCount;
274  //
275  // std::vector<int> triangleConstraints;
276  // int triangleCount;
277  std::array<std::pair<Graphics::point, Graphics::rect>, width*height> regionConstraintLocations;
278 
279  Witness() // :separationConstraints(width*height), separationCount(0), tetrisConstraints(width*height),
280  // tetrisCount(0)
281  {
282  static_assert(
283  (width <= 8) && (height <= 8) && (width > 0) && (height > 0),
284  "Error: width/height must be between 1...8");
285  Reset();
286  }
287 
289  {
290  *this = w;
291  // pathConstraints = w.pathConstraints;
296  //
297  // constraints = w.constraints;
298  // constraintCount = w.constraintCount;
299  // start = w.start;
300  // goal = w.goal;
301  }
302 
304  {
306  // mustCrossEdgeConstraints = w.mustCrossEdgeConstraints;
307  // mustCrossConstraints = w.mustCrossConstraints;
308  // cannotCrossEdgeConstraints = w.cannotCrossEdgeConstraints;
309  // cannotCrossConstraints = w.cannotCrossConstraints;
312  start = w.start;
313  goal = w.goal;
314  goalMap = w.goalMap;
315  return *this;
316  }
317 
318  void Reset()
319  {
320  for (int c = 0; c < kRegionConstraintCount; c++)
321  constraintCount[c] = 0;
323 
324  for (int x = 0; x < width; x++)
325  {
326  for (int y = 0; y < height; y++)
327  {
329  Graphics::point p1 = GetScreenCoord(x, y);
330  Graphics::point p2 = GetScreenCoord(x + 1, y + 1);
331  Graphics::point p3 = (p1 + p2) * 0.5;
332  regionConstraintLocations[x + y * width] = std::make_pair(p3, Graphics::rect{p3, 0.15});
333  }
334  }
335 
336  for (int x = 0; x < GetNumPathConstraints(); x++)
338 
339  for (int x = 0; x < width; x++)
340  {
341  for (int y = 0; y <= height; y++)
342  {
343  Graphics::point p = (GetScreenCoord(x, y) + GetScreenCoord(x + 1, y)) * 0.5;
344  // horizontal
345  pathConstraintLocations[x + y * width] = std::make_pair(p, Graphics::rect{p, 0.05});
346  }
347  }
348  for (int x = 0; x <= width; x++)
349  {
350  for (int y = 0; y < height; y++)
351  {
352  Graphics::point p = (GetScreenCoord(x, y) + GetScreenCoord(x, y + 1)) * 0.5;
353  // vertical
354  pathConstraintLocations[width * (height + 1) + x * height + y] =
355  std::make_pair(p, Graphics::rect{p, 0.05});
356  }
357  }
358  for (int x = 0; x < width + 1; x++)
359  {
360  for (int y = 0; y < height + 1; y++)
361  {
363  // vertex
364  pathConstraintLocations[width * (height + 1) + (width + 1) * height + (width + 1) * y + x] =
365  std::make_pair(p, Graphics::rect{p, 0.05});
366  }
367  }
368 
369  // mustCrossConstraints.clear();
370  // mustCrossEdgeConstraints.clear();
371  // cannotCrossConstraints.clear();
372  // cannotCrossEdgeConstraints.clear();
373  start.clear();
374  start.emplace_back(0, 0);
375  SetGoal(width, height + 1);
376  // goal.clear();
377  // goal.push_back({width,height});
378  // goal.push_back({width-1,height});
379  // goal.push_back({width,height-1});
380  }
381 
382  void GetSuccessors(
383  const WitnessState<width, height> &nodeID, std::vector <WitnessState<width, height>> &neighbors) const;
384 
385  void GetActions(const WitnessState<width, height> &nodeID, std::vector <WitnessAction> &actions) const;
386 
388 
389  void ApplyAction(std::pair<int, int> &s, WitnessAction a) const;
390 
391  bool InvertAction(WitnessAction &a) const;
392 
394 
396 
398 
400  double HCost(const WitnessState<width, height> &node1, const WitnessState<width, height> &node2) const;
401 
402  double GCost(const WitnessState<width, height> &node1, const WitnessState<width, height> &node2) const;
403 
404  double GCost(const WitnessState<width, height> &node, const WitnessAction &act) const;
405 
407 
408  bool GoalTest(const WitnessState<width, height> &node) const;
409 
410  uint64_t GetMaxHash() const;
411 
412  uint64_t GetStateHash(const WitnessState<width, height> &node) const;
413 
414  void GetStateFromHash(uint64_t parent, WitnessState<width, height> &s) const;
415 
416  uint64_t GetActionHash(WitnessAction act) const;
417 
418  void OpenGLDraw() const {};
419 
420  void OpenGLDraw(const WitnessState<width, height> &) const {};
421 
424 
425  void OpenGLDraw(const WitnessState<width, height> &, const WitnessAction &) const {};
426 
427  void GLLabelState(const WitnessState<width, height> &, const char *) const {}; // draw label over state
429 
431  Graphics::Display &display, const WitnessRegionConstraint &constraint, const Graphics::point &p3) const;
432 
433  void Draw(Graphics::Display &display) const;
434 
435  void Draw(Graphics::Display &display, const WitnessState<width, height> &) const;
436 
437  void Draw(Graphics::Display &display, const InteractiveWitnessState<width, height> &) const;
438 
439  // returns true if the goal was reached
441 
443 
444  const WitnessRegionConstraint& GetRegionConstraint(int x, int y) const
445  {
446  return regionConstraints[x][y];
447  }
448 
449  void SetStart(int x, int y)
450  {
451  start.clear();
452  start.emplace_back(x, y);
453  }
454 
455  void AddStart(int x, int y) { start.emplace_back(x, y); }
456 
457  void SetGoal(int x, int y)
458  {
459  goal.clear();
460  std::fill(goalMap.begin(), goalMap.end(), 0);
461  AddGoal(x, y);
462  }
463 
464  bool AddGoal(int x, int y)
465  {
466  if (x == -1 || x == width + 1 || y == -1 || y == height + 1)
467  {
468  goal.emplace_back(x, y);
469  if (x > width) x = width;
470  if (x < 0) x = 0;
471  if (y > height) y = height;
472  if (y < 0) y = 0;
473  // this is the location from which we reach that goal (note: off by 1 to keep semantics of 0)
474  goalMap[GetPathIndex(x, y)] = (int)goal.size();
475  return true;
476  }
477  else
478  {
479  printf("Error: invalid goal location\n");
480  return false;
481  }
482  }
483 
485 
486  //{ mustCrossConstraints.clear(); mustCrossEdgeConstraints.clear(); }
487  void SetMustCrossConstraint(int);
488 
489  bool GetMustCrossConstraint(int) const;
490 
491  bool GetMustCrossConstraint(int, int) const;
492 
493  bool GetMustCrossConstraint(bool, int, int) const;
494 
495  void ClearMustCrossConstraint(int);
496 
497  void AddMustCrossConstraint(bool horiz, int x, int y); // { mustCrossEdgeConstraints.push_back({horiz, {x, y}});}
498  void AddMustCrossConstraint(int x, int y); // { mustCrossConstraints.push_back({x, y});}
499  void AddMustCrossConstraint(int); // { mustCrossConstraints.push_back({x, y});}
500  void RemoveMustCrossConstraint(bool horiz, int x, int y); // { mustCrossEdgeConstraints.pop_back();}
501  void RemoveMustCrossConstraint(int x, int y); // { mustCrossConstraints.pop_back();}
502 
503  /* Hexagon constraints - cannot cross this point */
504  constexpr int GetNumCannotCrossConstraints() const;
505 
506  void SetCannotCrossConstraint(int);
507 
508  bool GetCannotCrossConstraint(int) const;
509 
510  bool GetCannotCrossConstraint(int, int) const;
511 
512  bool GetCannotCrossConstraint(bool, int, int) const;
513 
514  void ClearCannotCrossConstraint(int);
515 
516  void AddCannotCrossConstraint(bool horiz, int x, int y); // { cannotCrossEdgeConstraints.push_back({horiz, {x, y}});}
517  void AddCannotCrossConstraint(int x, int y); // { cannotCrossConstraints.push_back({x, y});}
518  void AddCannotCrossConstraint(int); // { cannotCrossConstraints.push_back({x, y});}
519  void RemoveCannotCrossConstraint(bool horiz, int x, int y); // { cannotCrossEdgeConstraints.pop_back();}
520  void RemoveCannotCrossConstraint(int x, int y); // { cannotCrossConstraints.pop_back();}
521 
523  {
524  for (int x = 0; x < width; x++)
525  {
526  for (int y = 0; y < height; y++)
527  {
529  }
530  }
531  for (int c = 0; c < kRegionConstraintCount; c++)
532  constraintCount[c] = 0;
534  }
535 
537  {
538  for (int x = 0; x < width; x++)
539  {
540  for (int y = 0; y < height; y++)
541  {
542  if (t == regionConstraints[x][y].t)
543  {
544  constraintCount[t]--;
547  }
548  }
549  }
550  }
551 
552  void RemoveRegionConstraint(int x, int y)
553  {
557  }
558 
559  /* Triangles - must cross as many edges as triangles */
560  static constexpr int GetNumTriangleConstraints() { return width * height; }
561 
563  {
565  // triangleConstraints.clear(); triangleConstraints.resize(width*height); triangleCount = 0;
566  }
567 
568  void AddTriangleConstraint(int x, int y, int count)
569  {
570  if (x >= width || y >= height || y < 0 || x < 0)
571  {
572  printf("(%d, %d) out of bounds\n", x, y);
573  return;
574  }
575  assert(count >= 1 && count <= 3);
578  regionConstraints[x][y].t = kTriangle;
579  regionConstraints[x][y].parameter = count;
581  }
582 
583  // { triangleCount++; triangleConstraints[y*width+x] = count; }
584  void AddTriangleConstraint(int which, int count) //{ triangleCount++; triangleConstraints[which] = count; }
585  {
586  AddTriangleConstraint(which % width, which / width, count);
587  }
588 
589  /* Color (rounded) square - must separate these */
590  /* TODO: Star constraints are a special case */
592 
593  //{ separationConstraints.clear(); separationConstraints.resize(width*height), separationCount = 0; }
594  static constexpr int GetNumSeparationConstraints() { return width * height; }
595 
596  // constexpr int GetNumSeparationConstraints() const { return width*height; }
597  void AddSeparationConstraint(int x, int y, rgbColor c)
598  {
601  regionConstraints[x][y].t = kSeparation;
602  regionConstraints[x][y].c = c;
603  }
604 
605  // { auto &i = separationConstraints[y*width+x]; i.color = c; i.valid = true; separationCount++;}
607  //{ auto &i = separationConstraints[which]; i.color = c; i.valid = true; separationCount++;}
608  {
610  }
611  // void RemoveSeparationConstraint(int x, int y) { separationConstraints[y*width+x].valid = false;
612  // separationCount--;} void RemoveSeparationConstraint(int which) { separationConstraints[which].valid = false;
613  // separationCount--;}
614 
616 
617  //{ separationConstraints.clear(); separationConstraints.resize(width*height), separationCount = 0; }
618  constexpr int GetNumEraserConstraints() const { return width * height; }
619 
620  void AddEraserConstraint(int x, int y)
621  {
624  regionConstraints[x][y].t = kEraser;
626  }
627 
628  // { auto &i = separationConstraints[y*width+x]; i.color = c; i.valid = true; separationCount++;}
629  void AddEraserConstraint(int which)
630  //{ auto &i = separationConstraints[which]; i.color = c; i.valid = true; separationCount++;}
631  {
633  }
634 
635  // TODO: Not yet complete - don't handle tilted
636  /* Tetris constraints - must solve packing problem to validate these */
637  /* We allow most constraints with 1...4 blocks -- 14 total */
638  /* 1 *
639  * 2 **
640  * 3 *
641  * *
642  * 4 **
643  * *
644  * 5 **
645  * *
646  * 6 *
647  * **
648  * 7 *
649  * **
650  * 8 ***
651  * 9 *
652  * *
653  * *
654  * 10 **
655  * **
656  * 11 ***
657  * *
658  * 12 *
659  * ***
660  * 13 ***
661  * *
662  * 14 *
663  * ***
664  * 15 **
665  * *
666  * *
667  * 16 **
668  * *
669  * *
670  * 17 *
671  * *
672  * **
673  * 18 *
674  * *
675  * **
676  * 19 ****
677  * 20 *
678  * *
679  * *
680  * *
681  * 21 ***
682  * *
683  * 22 *
684  * ***
685  * 23 *
686  * **
687  * *
688  * 24 *
689  * **
690  * *
691  */
693  //{ tetrisConstraints.resize(0); tetrisConstraints.resize(width*height); tetrisCount = 0; }
694  {
697  }
698 
699  void AddNegativeTetrisConstraint(int x, int y, int which)
700  {
701  assert(which >= 1);
705  regionConstraints[x][y].c = tetrisBlue;
706  regionConstraints[x][y].parameter = which;
707  }
708 
709  void AddTetrisConstraint(int x, int y, int which)
710  {
711  assert(which >= 1);
714  regionConstraints[x][y].t = kTetris;
716  regionConstraints[x][y].parameter = which;
717  }
718 
719  void AddNegativeTetrisConstraint(int loc, int which)
720  {
722  }
723 
724  void AddTetrisConstraint(int loc, int which) // { tetrisConstraints[loc] = which; tetrisCount++; }
725  {
727  }
728 
729  static constexpr int GetNumTetrisConstraints() { return width * height; }
730 
731  // TODO: don't increase count if piece is already there
732  const uint16_t tetrisBits[25] = {0, 0x8000, 0xC000, 0x8800, 0xC800, 0xC400, 0x8C00, 0x4C00, 0xE000, 0x8880, 0xCC00,
733  0xE800, 0x8E00, 0xE200, 0x2E00, 0xC880, 0xC440, 0x88C0, 0x44C0, 0xF000, 0x8888,
734  0xE400, 0x4E00, 0x8C80, 0x4C40};
735  const uint64_t tetrisBits64[25] = {0, 0x8000000000000000ull, 0xC000000000000000ull, 0x8080000000000000ull,
736  0x80C0000000000000ull, 0x40C0000000000000ull, 0xC080000000000000ull,
737  0xC040000000000000ull,
738  0xE000000000000000ull, 0x8080800000000000ull, 0xC0C0000000000000ull,
739  0x80E0000000000000ull,
740  0xE080000000000000ull, 0x20E0000000000000ull, 0xE020000000000000ull,
741  0x8080C00000000000ull,
742  0x4040C00000000000ull, 0xC080800000000000ull, 0xC040400000000000ull,
743  0xF000000000000000ull,
744  0x8080808000000000ull, 0x40E0000000000000ull, 0xE040000000000000ull,
745  0x80C0800000000000ull,
746  0x40C0400000000000ull};
747  const uint16_t tetrisSize[25] = {0, 1, 2, 2, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4};
748  const uint16_t tetrisWH[25][2] = {{0, 0},
749  {1, 1},
750  {2, 1},
751  {1, 2},
752  {2, 2},
753  {2, 2},
754  {2, 2},
755  {2, 2},
756  {3, 1},
757  {1, 3},
758  {2, 2},
759  {3, 2},
760  {3, 2},
761  {3, 2},
762  {3, 2},
763  {2, 3},
764  {2, 3},
765  {2, 3},
766  {2, 3},
767  {4, 1},
768  {1, 4},
769  {3, 2},
770  {3, 2},
771  {2, 3},
772  {2, 3}};
773 
775 
776  static constexpr int GetNumStarConstraints() { return width * height; }
777 
778  void AddStarConstraint(int x, int y, rgbColor c)
779  {
780  if (x >= width || y >= height || y < 0 || x < 0)
781  {
782  printf("(%d, %d) out of bounds\n", x, y);
783  return;
784  }
787  regionConstraints[x][y].t = kStar;
788  regionConstraints[x][y].c = c;
789  }
790 
791  void AddStarConstraint(int which, rgbColor c)
792  {
794  }
795 
797  {
798  switch (constraint.t)
799  {
800  case kSeparation:
802  break;
803  case kStar:
804  AddStarConstraint(x, y, constraint.c);
805  break;
806  case kTetris:
807  AddTetrisConstraint(x, y, constraint.parameter);
808  break;
809  case kNegativeTetris:
810  AddNegativeTetrisConstraint(x, y, constraint.parameter);
811  break;
812  case kTriangle:
813  AddTriangleConstraint(x, y, constraint.parameter);
814  break;
815  case kEraser:
816  AddEraserConstraint(x, y);
817  break;
818  default: // kNoRegionConstraint, kRegionConstraintCount
819  break;
820  }
821  }
822 
824  {
826  }
827 
828  std::vector<std::pair<int, int>> start;
829  std::vector<std::pair<int, int>> goal;
830  // constant-time lookup for which goal is nearby
831  // value is hte index in the goal array+1 (0 index means no goal)
832  std::array<int, (width + 1) * (height + 1)> goalMap;
833  // const int kStartX = 0, kStartY = 0;
834 
835  operator std::string() const
836  {
837  std::string quote = "\"";
838  std::stringstream ss;
839  ss << "{\"width\":" << width << ", \"height\":" << height << ", \"start\":[";
840  for (const auto &s: start)
841  {
842  ss << "{\"x\":" << s.first << ", \"y\":" << s.second << "}";
843  if (&s != &start.back())
844  ss << ",";
845  }
846  ss << "], \"goal\":[";
847  for (const auto &g: goal)
848  {
849  ss << "{\"x\":" << g.first << ", \"y\":" << g.second << "}";
850  if (&g != &goal.back())
851  ss << ",";
852  }
853  ss << "], \"constraints\":{\"regionConstraints\":[";
854  unsigned count = std::accumulate(constraintCount.begin() + 1, constraintCount.end(), 0);
855  for (unsigned x = 0; x < width; ++x)
856  {
857  for (unsigned y = 0; y < height; ++y)
858  {
861  {
862  ss << "{\"x\":" << x << ",\"y\":" << y
863  << ",\"constraint\":" << std::string(constraint) << "}";
864  if (count > 1)
865  {
866  ss << ",";
867  --count;
868  }
869  }
870  }
871  }
872  ss << "], \"pathConstraints\":[";
873  count = std::accumulate(pathConstraints.begin(), pathConstraints.end(), 0, [&](int c, WitnessPathConstraintType t) {
874  if (t != kNoPathConstraint)
875  return c + 1;
876  return c;
877  });
878  for (unsigned i = 0; i < pathConstraints.size(); ++i)
879  {
881  if (pathConstraints[i] != 0)
882  {
883  ss << "{\"locationType\":" << p.t << ",\"x\":" << p.x << ",\"y\":" << p.y
884  << ",\"constraint\":" << pathConstraints[i] << "}";
885  if (count > 1)
886  {
887  ss << ",";
888  --count;
889  }
890  }
891  }
892  ss << "]}";
893  ss << "}";
894  return ss.str();
895  }
896 
897  std::ostream& Serialize(std::ostream &os) const
898  {
899  return os << std::string(*this);
900  }
901 
902  std::istream& Deserialize(std::istream &is)
903  {
904  std::string input((std::istreambuf_iterator<char>(is)), std::istreambuf_iterator<char>());
905  std::regex wh("\"width\":\\s*(\\d+),\\s*\"height\":\\s*(\\d+)");
906  std::smatch match;
907  if (!std::regex_search(input, match, wh))
908  {
909  std::cerr << "incorrect string" << std::endl;
910  return is;
911  }
912  int w = std::stoi(match[1].str());
913  int h = std::stoi(match[2].str());
914  if (w != width || h != height)
915  {
916  std::cerr << "unmatched width and height" << std::endl;
917  return is;
918  }
919  std::regex regStart("\"start\":\\s*\\[(\\{\"x\":\\s*\\d+,\\s*\"y\":\\s*\\d+\\})*\\],");
920  if (!std::regex_search(input, match, regStart))
921  {
922  std::cerr << "incorrect string" << std::endl;
923  return is;
924  }
925  std::regex regXy("\"x\":\\s*(\\d+),\\s*\"y\":\\s*(\\d+)");
926  for (size_t i = 1; i < match.size(); ++i)
927  {
928  std::string s = match[i].str();
929  std::smatch nums;
930  std::regex_search(s, nums, regXy);
931  int x = std::stoi(nums[1].str());
932  int y = std::stoi(nums[2].str());
933  if (std::find(start.begin(), start.end(), std::pair<int, int>{x, y}) == start.end())
934  AddStart(x, y);
935  }
936  std::regex regGoal("\"goal\":\\s*\\[(\\{\"x\":\\s*\\d+,\\s*\"y\":\\s*\\d+\\})*\\],");
937  if (!std::regex_search(input, match, regGoal))
938  {
939  std::cerr << "incorrect string" << std::endl;
940  return is;
941  }
942  for (size_t i = 1; i < match.size(); ++i)
943  {
944  std::string s = match[i].str();
945  std::smatch nums;
946  std::regex_search(s, nums, regXy);
947  int x = std::stoi(nums[1].str());
948  int y = std::stoi(nums[2].str());
949  if (std::find(goal.begin(), goal.end(), std::pair<int, int>{x, y}) == goal.end())
950  AddGoal(x, y);
951  }
952  std::regex regConstraints("\"constraints\":\\s*\\{\"regionConstraints\":\\s*\\[(.*)\\],\\s*\"pathConstraints\":\\[(.*)\\]\\}");
953  if (!std::regex_search(input, match, regConstraints))
954  {
955  std::cerr << "incorrect string" << std::endl;
956  return is;
957  }
958  std::string rc = match[1].str();
959  std::string pc = match[2].str();
960  std::regex regRegionConstraint("\\{\"x\":\\s*(\\d+),\\s*\"y\":\\s*(\\d+),\\s*\"constraint\":\\s*\\{\"type\":\\s*(\\d),\\s*\"param\":\\s*(\\d),\\s*\"color\":\\s*\"(#[a-fA-F0-9]{6})\"\\}");
961  auto begin = std::sregex_iterator(input.begin(), input.end(), regRegionConstraint);
962  auto end = std::sregex_iterator();
963  for (auto i = begin; i != end; ++i)
964  {
965  match = *i;
966  int x = std::stoi(match[1]);
967  int y = std::stoi(match[2]);
968  if (x >= width || y >= height)
969  {
970  std::cerr << "incorrect location type" << std::endl;
971  return is;
972  }
973  int type = std::stoi(match[3]);
974  if (type >= kRegionConstraintCount)
975  {
976  std::cerr << "incorrect region constraint type" << std::endl;
977  return is;
978  }
979  int param = std::stoi(match[4]);
980  rgbColor color;
981  color.hex(match[5].str().c_str());
983  c.t = static_cast<WitnessRegionConstraintType>(type);
984  c.parameter = param;
985  c.c = color;
986  AddRegionConstraint(x, y, c);
987  }
988  std::regex regPathConstraint("\\{\"locationType\":\\s*(\\d),\\s*\"x\":\\s*(\\d),\\s*\"y\":\\s*(\\d),\\s*\"constraint\":\\s*(\\d)\\}");
989  begin = std::sregex_iterator(input.begin(), input.end(), regPathConstraint);
990  for (auto i = begin; i != end; ++i)
991  {
992  match = *i;
993  int locationType = std::stoi(match[1]);
994  if (locationType != 0 && locationType != 1 && locationType != 2)
995  {
996  std::cerr << "incorrect location type" << std::endl;
997  return is;
998  }
999  int x = std::stoi(match[2]);
1000  int y = std::stoi(match[3]);
1001  if (x > width || y > height)
1002  {
1003  std::cerr << "incorrect location" << std::endl;
1004  return is;
1005  }
1006  int c = std::stoi(match[4]);
1007  if (c >= kPathConstraintCount)
1008  {
1009  std::cerr << "incorrect path constraint type" << std::endl;
1010  return is;
1011  }
1012  int p = (locationType == 0) ? (x + y * width) :
1013  ((locationType == 1) ? (width * (height + 1) + x * height + y) :
1014  (width * (height + 1) + (width + 1) * height + (width + 1) * y + x));
1015  if (c == 1)
1017  if (c == 2)
1019  }
1020  return is;
1021  }
1022 
1023  std::string SaveToHashString() const
1024  {
1025  // JSON string { "name":"value" }
1026  // JSON number { "name":number }
1027  // JSON array { "name":{ "object", "object", "object"} }
1028  std::string quote = "\"";
1029  std::string hash = "{";
1030 
1031  {
1032  hash += quote + "dim" + quote + ":" + quote + std::to_string(width) + "x" + std::to_string(height) + quote;
1033  hash += ",";
1034  }
1035 
1036  {
1037  hash += quote + "cc" + quote + ":{";
1038  for (int x = 0; x < width; x++)
1039  {
1040  for (int y = 0; y < height; y++)
1041  {
1042  if (x != 0 || y != 0) hash += ",";
1043  hash += quote;
1044  hash += std::to_string(regionConstraints[x][y].t) + ";";
1045  // no point writing garbage
1046  if (regionConstraints[x][y].t == kNoRegionConstraint)
1047  hash += "0;";
1048  else
1049  hash += std::to_string(regionConstraints[x][y].parameter) + ";";
1050  if (regionConstraints[x][y].t == kNoRegionConstraint)
1051  hash += "#DADFAD";
1052  else
1053  hash += regionConstraints[x][y].c.hex();
1054  hash += quote;
1055  }
1056  }
1057  hash += "},";
1058  }
1059 
1060  {
1061  hash += quote + "mc" + quote + ":" + quote;
1062  // add must-cross constraints
1063  for (int x = 0; x < GetNumPathConstraints(); x++)
1064  hash += GetMustCrossConstraint(x) ? "1" : (GetCannotCrossConstraint(x) ? "2" : "0");
1065  hash += quote;
1066  }
1067  hash += "}";
1068  return hash;
1069  }
1070 
1071  void GetDimensionsFromHashString(const std::string &s, int &w, int &h) const
1072  {
1073  const char *loc = strstr(s.c_str(), "dim");
1074  if (loc == nullptr)
1075  {
1076  w = -1;
1077  h = -1;
1078  return;
1079  }
1080  char a, b;
1081  sscanf(loc, "%*[^0-9]%cx%c", &a, &b);
1082  w = a - '0';
1083  h = b - '0';
1084  printf("Width: %d; height: %d\n", w, h);
1085  }
1086 
1087  // TODO: Code assumes input is well-formed! Fix this.
1088  void LoadFromHashString(std::string s)
1089  {
1090  Reset();
1091  // looking for dim, cc & mc
1092  int w, h;
1093  GetDimensionsFromHashString(s, w, h);
1094  if (w != width || h != height)
1095  {
1096  printf("Dimensions do not match, aborting load!\n");
1097  return;
1098  }
1099 
1100  // get crossing constraints
1101  {
1102  const char *loc = strstr(s.c_str(), "mc");
1103  if (loc == nullptr)
1104  {
1105  printf("Failed loading MC constraints\n");
1106  return;
1107  }
1108  // get end of mc variable
1109  while (loc[0] != ':')
1110  loc++;
1111  // get start of mc constraints
1112  while (loc[0] != '"')
1113  loc++;
1114  loc++;
1115  for (int x = 0; x < GetNumPathConstraints(); x++)
1116  {
1117  if (loc[0] == '1')
1119  else if (loc[0] == '2')
1121  loc++;
1122  }
1123  }
1124 
1125  // get regular constraints
1126  {
1127  const char *loc = strstr(s.c_str(), "cc");
1128  if (loc == nullptr)
1129  {
1130  printf("Failed loading CC constraints\n");
1131  return;
1132  }
1133  // get end of mc variable
1134  while (loc[0] != '{')
1135  loc++;
1136 
1137  for (int x = 0; x < width; x++)
1138  {
1139  for (int y = 0; y < height; y++)
1140  {
1141  if (loc[0] == '}')
1142  {
1143  printf("Unexpected '}', aborting\n");
1144  return;
1145  }
1146  while (loc[0] != '"')
1147  loc++;
1148 
1149  loc++; // skip open quote
1150  int cType = atoi(loc);
1151  while (loc[0] != ';')
1152  loc++;
1153  loc++;
1154  int param = atoi(loc);
1155  while (loc[0] != ';')
1156  loc++;
1157  loc++;
1158  rgbColor c;
1159  c.hex(loc);
1160 
1162  regionConstraints[x][y].t = static_cast<WitnessRegionConstraintType>(cType);
1164  regionConstraints[x][y].c = c;
1165  regionConstraints[x][y].parameter = param;
1166 
1167  while (loc[0] != ',')
1168  loc++;
1169  }
1170  }
1171  }
1172  }
1173 
1174  const rgbColor tetrisYellow = {0.862745098f, 0.6549019608f, 0.0f};
1175  const rgbColor tetrisBlue = {0.2196078431f, 0.3607843137f, 0.8705882353f};
1176  const rgbColor drawColor = Colors::darkbluegray; // Colors::lightblue;
1178  const rgbColor backColor = Colors::white; // Colors::gray;
1181 
1182  float scale = 0.75f;
1183  float gapOffset = scale * 2.0f / (width > height ? width : height); // size of each square
1184  float lineWidth = gapOffset * 0.1f;
1185  float xGap = (((width > height) ? (width) : (height)) - width) * gapOffset / 2.0f;
1186  float yGap = -(((width > height) ? (width) : (height)) - height) * gapOffset / 2.0f;
1187 
1188  int GetPathIndex(int x, int y) const { return y * (width + 1) + x; }
1189 
1191  {
1192  unsigned t;
1193  int x;
1194  int y;
1195  };
1196 
1198  {
1199  for (int x = 0; x < width; x++)
1200  for (int y = 0; y <= height; y++)
1201  if (index == (x + y * width))
1202  return {0, x, y};
1203  for (int x = 0; x <= width; x++)
1204  for (int y = 0; y < height; y++)
1205  if (index == (width * (height + 1) + x * height + y))
1206  return {1, x, y};
1207  for (int x = 0; x < width + 1; x++)
1208  for (int y = 0; y < height + 1; y++)
1209  if (index == (width * (height + 1) + (width + 1) * height + (width + 1) * y + x))
1210  return {2, x, y};
1211  return {};
1212  }
1213 
1214  int GetRegionIndex(int x, int y) const { return y * width + x; }
1215 
1216  int GetRegionFromX(int index) const { return index % width; }
1217 
1218  int GetRegionFromY(int index) const { return index / width; }
1219 
1220  void LabelRegions(const WitnessState<width, height> &s) const;
1221 
1222  // this is mapped to a 2d map which has the region number for any x/y location
1223  // mutable std::vector<int> regions;
1224  mutable std::array<int, width * height> regions;
1225  // for each region, this is a list of the cells in the region
1226  // the size of the vector tells us the size of the region
1227  mutable std::vector<std::vector < int> *>
1230 
1231  mutable std::vector<int> tetrisBlockCount;
1232  mutable std::vector<int> tetrisBlocksInRegion;
1233 
1235  int curr, uint64_t board, uint64_t oob, uint64_t posFootprint, uint64_t negFootprint) const;
1236 
1237  void GetMouseActions(const WitnessState<width, height> &nodeID, std::vector <WitnessAction> &actions) const;
1238 
1239  void DoLine(
1240  Graphics::Display &display, const Graphics::point &p1, const Graphics::point &p2, const rgbColor &c) const
1241  {
1242  if (p1.x == p2.x) // vertical line
1243  {
1244  display.FillRect({(p1.x - lineWidth), std::min(p1.y, p2.y), (p1.x + lineWidth), std::max(p1.y, p2.y)}, c);
1245  }
1246  else if (p1.y == p2.y) // horizontal line
1247  {
1248  display.FillRect({std::min(p1.x, p2.x), (p1.y - lineWidth), std::max(p1.x, p2.x), (p1.y + lineWidth)}, c);
1249  }
1250  else
1251  { // other line
1252  display.DrawLine(p1, p2, 2 * lineWidth, c);
1253  }
1254  }
1255 
1256  Graphics::point GetScreenCoord(int x, int y) const
1257  {
1258  float xMargin = 0;
1259  float yMargin = 0;
1260  if (x > width && y > height) // upper right corner
1261  {
1262  x = width;
1263  y = height;
1264  xMargin = 2 * lineWidth;
1265  yMargin = -2 * lineWidth;
1266  }
1267  if (y > height)
1268  {
1269  y = height;
1270  yMargin = -2 * lineWidth;
1271  if (x > width) x = width;
1272  if (x < 0) x = 0;
1273  }
1274  else if (x > width)
1275  {
1276  xMargin = 2 * lineWidth;
1277  x = width;
1278  if (y < 0) y = 0;
1279  }
1280  if (x < 0)
1281  {
1282  xMargin = -2 * lineWidth;
1283  x = 0;
1284  if (y < 0) y = 0;
1285  }
1286  else if (y < 0)
1287  {
1288  yMargin = 2 * lineWidth;
1289  y = 0;
1290  }
1291 
1292  // if (x > width || y > height)
1293  // return {(-scale+x*gapOffset+xGap), (scale-y*gapOffset+yGap)};
1294  // return {(-scale+width*gapOffset+xGap), (scale-height*gapOffset+yGap-2*lineWidth)};
1295  // return {(-scale+width*gapOffset+xGap), (scale-(height+4*lineWidth)*gapOffset+yGap)};
1296 
1297  return Graphics::point{(-scale + x * gapOffset + xGap + xMargin), (scale - y * gapOffset + yGap + yMargin)};
1298  }
1299 
1300  void DebugPrint(uint64_t val, int offset = 0) const
1301  {
1302  for (int y = 7; y >= 0; y--)
1303  {
1304  for (int x = 0; x < offset; x++)
1305  std::cout << " ";
1306  for (int x = 0; x < 8; x++)
1307  {
1308  std::cout << ((val >> (7 - x)) >> ((7 - y) * 8) & 0x1);
1309  }
1310  std::cout << std::endl;
1311  }
1312  }
1313 };
1314 
1315 template<int width, int height>
1317  const WitnessState<width, height> &nodeID, std::vector <WitnessState<width, height>> &neighbors) const
1318 {
1319 }
1320 
1321 template<int width, int height>
1323  const WitnessState<width, height> &nodeID, std::vector<WitnessAction> &actions) const
1324 {
1325  actions.resize(0);
1326  if (nodeID.path.size() == 0)
1327  {
1328  actions.push_back(kStart);
1329  return;
1330  }
1331 
1332  int currX = nodeID.path.back().first;
1333  int currY = nodeID.path.back().second;
1334 
1335  if (currX > width || currY > height) return;
1336 
1337  // TODO: Only works with one exit going from lower left to upper right
1338  if (goalMap[GetPathIndex(currX, currY)] != 0) actions.push_back(kEnd);
1339  // for (const auto &ends : goal)
1340  // {
1341  // if (currX == ends.first && currY == ends.second)
1342  // {
1343  // actions.push_back(kEnd);
1344  // break;
1345  // }
1346  // }
1347  // if (currX == width && currY == height)
1348  // {
1349  // actions.push_back(kEnd);
1350  // return;
1351  // }
1352 
1353  if (currX > 0 && !nodeID.Occupied(currX - 1, currY)) actions.push_back(kLeft);
1354  if (currX < width && !nodeID.Occupied(currX + 1, currY)) actions.push_back(kRight);
1355  if (currY > 0 && !nodeID.Occupied(currX, currY - 1)) actions.push_back(kDown);
1356  if (currY < height && !nodeID.Occupied(currX, currY + 1)) actions.push_back(kUp);
1357 }
1358 
1359 template<int width, int height>
1361  const WitnessState<width, height> &nodeID, std::vector<WitnessAction> &actions) const
1362 {
1363  actions.resize(0);
1364  if (nodeID.path.size() == 0)
1365  {
1366  actions.push_back(kStart);
1367  return;
1368  }
1369 
1370  int currX = nodeID.path.back().first;
1371  int currY = nodeID.path.back().second;
1372 
1373  if (!nodeID.InGoal())
1374  {
1375  // could be next to a goal
1376  if (goalMap[(GetPathIndex(currX, currY))] != 0)
1377  {
1378  actions.push_back(kEnd);
1379  }
1380  }
1381  // if (currX == width && currY == height)
1382  // actions.push_back(kEnd);
1383  // if (currX > width || currY > height)
1384  // {
1385  // actions.push_back(kDown);
1386  // actions.push_back(kEnd);
1387  // return;
1388  // }
1389 
1390  // bool noLeft = false, noRight = false, noUp = false, noDown = false;
1391  // for (auto &i : cannotCrossConstraints)
1392  // {
1393  // if (i.first == currX-1 && i.second == currY)
1394  // noLeft = true;
1395  // if (i.first == currX+1 && i.second == currY)
1396  // noRight = true;
1397  // if (i.second == currY-1 && i.first == currX)
1398  // noDown = true;
1399  // if (i.second == currY+1 && i.first == currX)
1400  // noUp = true;
1401  // }
1402  // if (currX > 0 && !noLeft)
1403  // actions.push_back(kLeft);
1404  // if (currX < width && !noRight)
1405  // actions.push_back(kRight);
1406  // if (currY > 0 && !noDown)
1407  // actions.push_back(kDown);
1408  // if (currY < height && !noUp)
1409  // actions.push_back(kUp);
1410  if (currY >= 0 && currY <= height)
1411  {
1412  if (currX > 0 && !GetCannotCrossConstraint(currX - 1, currY)) actions.push_back(kLeft);
1413  if (currX < width && !GetCannotCrossConstraint(currX + 1, currY)) actions.push_back(kRight);
1414  }
1415  if (currX >= 0 && currX <= width)
1416  {
1417  if (currY > 0 && !GetCannotCrossConstraint(currX, currY - 1)) actions.push_back(kDown);
1418  if (currY < height && !GetCannotCrossConstraint(currX, currY + 1)) actions.push_back(kUp);
1419  }
1420 }
1421 
1422 template<int width, int height>
1423 void Witness<width, height>::ApplyAction(std::pair<int, int> &s, WitnessAction a) const
1424 {
1425  switch (a)
1426  {
1427  case kEnd:
1428  {
1429  int whichGoal = goalMap[GetPathIndex(s.first, s.second)];
1430  assert(whichGoal != 0);
1431  s = goal[whichGoal - 1];
1432  }
1433  // //s.first++;
1434  // if (s.first == width)
1435  // s.first++;
1436  // else if (s.first == 0)
1437  // s.first--;
1438  // if (s.second == height)
1439  // s.second++;
1440  // else if (s.second == 0)
1441  // s.second--;
1442  break;
1443  case kStart:
1444  break;
1445  case kLeft:
1446  s.first--;
1447  break;
1448  case kRight:
1449  s.first++;
1450  break;
1451  case kUp:
1452  s.second++;
1453  break;
1454  case kDown:
1455  s.second--;
1456  break;
1457  }
1458 }
1459 
1460 template<int width, int height>
1462 {
1463  auto len = s.path.size() + 1;
1464  switch (a)
1465  {
1466  case kEnd:
1467  {
1468  int whichGoal = goalMap[GetPathIndex(s.path.back().first, s.path.back().second)];
1469  assert(whichGoal != 0);
1470  s.path.push_back(goal[whichGoal - 1]);
1471  }
1472  // if (s.path.back().first >= width)
1473  // s.path.push_back({width+1, s.path.back().second});
1475  // else if (s.path.back().first <= 0)
1476  // s.path.push_back({-1, s.path.back().second});
1477  // // s.first--;
1478  // else if (s.path.back().second >= height)
1479  // s.path.push_back({s.path.back().first, height+1});
1481  // else if (s.path.back().second <= 0)
1482  // s.path.push_back({s.path.back().first, -1});
1484  // else {
1485  // assert(false);
1486  // //s.path.push_back({width, height+1});
1487  // }
1488  return; // don't occupy on end action
1489  case kStart:
1490  s.Reset();
1491  s.path.push_back(start[0]);
1492  s.Occupy(s.path.back().first, s.path.back().second);
1493  break;
1494  case kLeft:
1495  s.path.push_back(s.path.back());
1496  s.path.back().first--;
1497  s.Occupy(s.path.back().first, s.path.back().second);
1498  s.OccupyEdge(s.path[len - 1].first, s.path[len - 1].second, s.path[len - 2].first, s.path[len - 2].second);
1499  break;
1500  case kRight:
1501  s.path.push_back(s.path.back());
1502  s.path.back().first++;
1503  s.Occupy(s.path.back().first, s.path.back().second);
1504  s.OccupyEdge(s.path[len - 1].first, s.path[len - 1].second, s.path[len - 2].first, s.path[len - 2].second);
1505  break;
1506  case kUp:
1507  s.path.push_back(s.path.back());
1508  s.path.back().second++;
1509  s.Occupy(s.path.back().first, s.path.back().second);
1510  s.OccupyEdge(s.path[len - 1].first, s.path[len - 1].second, s.path[len - 2].first, s.path[len - 2].second);
1511  break;
1512  case kDown:
1513  s.path.push_back(s.path.back());
1514  s.path.back().second--;
1515  s.Occupy(s.path.back().first, s.path.back().second);
1516  s.OccupyEdge(s.path[len - 1].first, s.path[len - 1].second, s.path[len - 2].first, s.path[len - 2].second);
1517  break;
1518  }
1519 
1520  // s.occupiedCorners.set(s.path.back().second*width+s.path.back().first); // y*width+x;
1521 }
1522 
1523 template<int width, int height>
1525 {
1526  auto len = s.path.size();
1527  if (s.path[len - 1].first <= width && s.path[len - 1].second <= height)
1528  {
1529  if (len > 1)
1530  s.UnoccupyEdge(
1531  s.path[len - 1].first, s.path[len - 1].second, s.path[len - 2].first, s.path[len - 2].second);
1532  s.Unoccupy(s.path.back().first, s.path.back().second);
1533  }
1534  s.path.pop_back();
1535 }
1536 
1537 template<int width, int height>
1539 {
1540  int currX = s.path.back().first;
1541  int currY = s.path.back().second;
1542  switch (a)
1543  {
1544  case kEnd:
1545  if (goalMap[GetPathIndex(currX, currY)] != 0)
1546  {
1547  l = kLegal;
1548  return true;
1549  }
1550  l = kNotAtEnd;
1551  return false;
1552  // for (const auto &i : goal)
1553  // if (i.first == currX && i.second == currY)
1554  // {
1555  // l = kLegal;
1556  // return true;
1557  // }
1563  // l = kNotAtEnd;
1564  // return false;
1565  case kStart:
1566  if (s.path.size() == 0)
1567  {
1568  l = kLegal;
1569  return true;
1570  }
1571  l = kNotAtStart;
1572  return false;
1573  case kLeft:
1574  // if (currX > 0 && !s.Occupied(currX-1, currY) && !GetCannotCrossConstraint(true, currX-1, currY))
1575  if (currX <= 0)
1576  {
1577  l = kNotValidAction;
1578  return false;
1579  }
1580  else if (GetCannotCrossConstraint(true, currX - 1, currY))
1581  {
1582  l = kHitCannotCross;
1583  return false;
1584  }
1585  else if (s.Occupied(currX - 1, currY))
1586  {
1587  l = kHitLine;
1588  return false;
1589  }
1590  l = kLegal;
1591  return true;
1592  case kRight:
1593  if (currX >= width)
1594  {
1595  l = kNotValidAction;
1596  return false;
1597  }
1598  else if (GetCannotCrossConstraint(true, currX, currY))
1599  {
1600  l = kHitCannotCross;
1601  return false;
1602  }
1603  else if (s.Occupied(currX + 1, currY))
1604  {
1605  l = kHitLine;
1606  return false;
1607  }
1608  l = kLegal;
1609  return true;
1610  // return (currX < width && !s.Occupied(currX+1, currY) && !GetCannotCrossConstraint(true, currX,
1611  // currY));
1612  case kDown:
1613  // return (currY > 0 && !s.Occupied(currX, currY-1) && !GetCannotCrossConstraint(false, currX, currY-1));
1614  if (currY <= 0)
1615  {
1616  l = kNotValidAction;
1617  return false;
1618  }
1619  else if (GetCannotCrossConstraint(false, currX, currY - 1))
1620  {
1621  l = kHitCannotCross;
1622  return false;
1623  }
1624  else if (s.Occupied(currX, currY - 1))
1625  {
1626  l = kHitLine;
1627  return false;
1628  }
1629  l = kLegal;
1630  return true;
1631  case kUp:
1632  // return (currY < height && !s.Occupied(currX, currY+1) && !GetCannotCrossConstraint(false, currX,
1633  // currY));
1634  if (currY >= height)
1635  {
1636  l = kNotValidAction;
1637  return false;
1638  }
1639  else if (GetCannotCrossConstraint(false, currX, currY))
1640  {
1641  l = kHitCannotCross;
1642  return false;
1643  }
1644  else if (s.Occupied(currX, currY + 1))
1645  {
1646  l = kHitLine;
1647  return false;
1648  }
1649  l = kLegal;
1650  return true;
1651  }
1652  return false;
1653 }
1654 
1655 template<int width, int height>
1657 {
1658  int currX = s.path.back().first;
1659  int currY = s.path.back().second;
1660  switch (a)
1661  {
1662  case kEnd:
1663  if (goalMap[GetPathIndex(currX, currY)] != 0)
1664  {
1665  return true;
1666  }
1667  return false;
1668  // for (const auto &i : goal)
1669  // if (i.first == currX && i.second == currY)
1670  // {
1671  // return true;
1672  // }
1673  // return false;
1674  case kStart:
1675  return s.path.size() == 0;
1676  case kLeft:
1677  return (currX > 0 && !s.Occupied(currX - 1, currY) && !GetCannotCrossConstraint(true, currX - 1, currY));
1678  case kRight:
1679  return (currX < width && !s.Occupied(currX + 1, currY) && !GetCannotCrossConstraint(true, currX, currY));
1680  case kDown:
1681  return (currY > 0 && !s.Occupied(currX, currY - 1) && !GetCannotCrossConstraint(false, currX, currY - 1));
1682  case kUp:
1683  return (currY < height && !s.Occupied(currX, currY + 1) && !GetCannotCrossConstraint(false, currX, currY));
1684  }
1685  return false;
1686 }
1687 
1688 template<int width, int height>
1690 {
1691  switch (a)
1692  {
1693  case kStart:
1694  return false;
1695  case kEnd:
1696  return false;
1697  case kUp:
1698  a = kDown;
1699  break;
1700  case kDown:
1701  a = kUp;
1702  break;
1703  case kLeft:
1704  a = kRight;
1705  break;
1706  case kRight:
1707  a = kLeft;
1708  break;
1709  }
1710  return true;
1711 }
1712 
1714 template<int width, int height>
1716  const WitnessState<width, height> &node1, const WitnessState<width, height> &node2) const
1717 {
1718  return 0;
1719 }
1720 
1721 template<int width, int height>
1723  const WitnessState<width, height> &node1, const WitnessState<width, height> &node2) const
1724 {
1725  return 1;
1726 }
1727 
1728 template<int width, int height>
1730 {
1731  return 1;
1732 }
1733 
1734 template<int width, int height>
1737 {
1738  // Check constraints
1739  return GoalTest(node);
1740 }
1741 
1742 template<int width, int height>
1744 {
1745  // TODO: make this more efficient
1746  for (int x = 0; x < width + 1; x++)
1747  {
1748  for (int y = 0; y < height + 1; y++)
1749  {
1750  if (GetMustCrossConstraint(x, y) && (!node.Occupied(x, y))) return false;
1751  if (GetCannotCrossConstraint(x, y) && (node.Occupied(x, y))) return false;
1752  }
1753  }
1754  for (int x = 0; x < width; x++)
1755  {
1756  for (int y = 0; y <= height; y++)
1757  {
1758  if (GetMustCrossConstraint(true, x, y) && !node.OccupiedEdge(x, y, x + 1, y)) return false;
1759  if (GetCannotCrossConstraint(true, x, y) && node.OccupiedEdge(x, y, x + 1, y)) return false;
1760  }
1761  }
1762  for (int x = 0; x <= width; x++)
1763  {
1764  for (int y = 0; y < height; y++)
1765  {
1766  if (GetMustCrossConstraint(false, x, y) && !node.OccupiedEdge(x, y, x, y + 1)) return false;
1767  if (GetCannotCrossConstraint(false, x, y) && node.OccupiedEdge(x, y, x, y + 1)) return false;
1768  }
1769  }
1770  // for (auto &c : mustCrossConstraints)
1771  // {
1772  // if (!node.Occupied(c.first, c.second))
1773  // return false;
1774  // }
1775  // // First pass - mustCross
1776  // for (auto &c : mustCrossEdgeConstraints)
1777  // {
1780  // if (!node.OccupiedEdge(c.location.first, c.location.second, c.location.first+(c.horiz?1:0),
1781  // c.location.second+(c.horiz?0:1)))
1782  // {
1784  // return false;
1785  // }
1787  // }
1788  //
1789  // for (auto &c : cannotCrossConstraints)
1790  // {
1791  // if (node.Occupied(c.first, c.second))
1792  // return false;
1793  // }
1794  // // First pass - mustCross
1795  // for (auto &c : cannotCrossEdgeConstraints)
1796  // {
1797  // // printf("Checking (%d, %d) to (%d, %d) - ", c.location.first, c.location.second,
1798  // c.location.first+(c.horiz?1:0), c.location.second+(c.horiz?0:1)); if (node.OccupiedEdge(c.location.first,
1799  // c.location.second, c.location.first+(c.horiz?1:0), c.location.second+(c.horiz?0:1)))
1800  // {
1801  // // printf("Failure\n");
1802  // return false;
1803  // }
1804  // // printf("Success\n");
1805  // }
1806 
1807  // Didn't hit end of puzzle
1808  if (node.path.size() == 0) return false;
1809  // have to be off
1810  // if (!
1811  // (node.path.back().second > height || node.path.back().first > width ||
1812  // node.path.back().second < 0 || node.path.back().first < 0))
1813  // return false;
1814  if (node.path.back().second <= height && node.path.back().first <= width && node.path.back().second >= 0 &&
1815  node.path.back().first >= 0)
1816  return false;
1817 
1818  if (constraintCount[kTriangle] > 0)
1819  // if (triangleCount > 0)
1820  {
1821  for (int x = 0; x < width; x++)
1822  {
1823  for (int y = 0; y < height; y++)
1824  {
1825  if (regionConstraints[x][y].t == kTriangle) // if (triangleConstraints[y*width+x] > 0)
1826  {
1827  int count = node.OccupiedEdge(x, y, x, y + 1);
1828  count += node.OccupiedEdge(x, y, x + 1, y);
1829  count += node.OccupiedEdge(x + 1, y, x + 1, y + 1);
1830  count += node.OccupiedEdge(x, y + 1, x + 1, y + 1);
1831  // if (count != triangleConstraints[y*width+x])
1832  if (count != regionConstraints[x][y].parameter) return false;
1833  }
1834  }
1835  }
1836  }
1837 
1838  if (constraintCount[kSeparation] == 0 && constraintCount[kTetris] == 0 && constraintCount[kStar] == 0 &&
1839  constraintCount[kEraser] == 0)
1840  // if (separationCount == 0 && tetrisCount == 0)
1841  return true;
1842 
1843  LabelRegions(node);
1844 
1845  // TODO: Verify matched constraints by region.
1846  // TODO: Count the total number of unmatched constraints for checking eraser constraints and for displaying failed
1847  // constraints
1848 
1849  if (constraintCount[kSeparation] > 0)
1850  {
1851  for (auto &v: regionList) // vector of locations
1852  {
1853  bool found = false;
1854  rgbColor c;
1855  for (auto &i: *v)
1856  {
1857  int x = GetRegionFromX(i); // l%width;
1858  int y = GetRegionFromY(i); // l/width;
1859 
1860  // if (separationConstraints[i].valid)
1861  if (regionConstraints[x][y].t == kSeparation)
1862  {
1863  if (!found)
1864  {
1865  c = regionConstraints[x][y].c; // separationConstraints[i].color;
1866  found = true;
1867  }
1868  else if (c != regionConstraints[x][y].c) // separationConstraints[i].color)
1869  {
1870  return false;
1871  }
1872  }
1873  }
1874  }
1875  }
1876 
1877  // TODO: After this is working, see if we can merge the tetris constraints into the separation code
1878  if (constraintCount[kTetris] == 0 && constraintCount[kNegativeTetris] > 0) return false;
1879 
1880  if (constraintCount[kStar] > 0)
1881  {
1882  for (auto &v: regionList) // vector of locations
1883  {
1884  for (auto &i: *v)
1885  {
1886  int x = GetRegionFromX(i); // l%width;
1887  int y = GetRegionFromY(i); // l/width;
1888  rgbColor finishedColor(1.0 / 512.0, 1.0 / 512.0, 1.0 / 512.0);
1889  // if (separationConstraints[i].valid)
1890  if (regionConstraints[x][y].t == kStar)
1891  {
1892  if (regionConstraints[x][y].c == finishedColor) continue;
1893 
1894  finishedColor = regionConstraints[x][y].c; // separationConstraints[i].color;
1895  int count = 0;
1896  for (auto &r: *v)
1897  {
1898  int xx = GetRegionFromX(r); // l%width;
1899  int yy = GetRegionFromY(r); // l/width;
1900 
1901  if (regionConstraints[xx][yy].t != kNoRegionConstraint &&
1902  regionConstraints[x][y].c == regionConstraints[xx][yy].c)
1903  {
1904  count++;
1905  if (count > 2) return false;
1906  }
1907  }
1908  if (count != 2) return false;
1909  }
1910  }
1911  }
1912  }
1913 
1914  if (constraintCount[kTetris] > 0)
1915  // if (tetrisCount > 0)
1916  {
1917  tetrisBlockCount.resize(regionList.size());
1918 
1919  // 1. Collect the tetris constraints for each region
1920  for (int x = 0; x < regionList.size(); x++)
1921  {
1922  const auto &v = *regionList[x]; // v is vector of locations in this region
1923  tetrisBlockCount[x] = 0;
1924  for (auto l: v) // individual location
1925  {
1926  if (regionConstraints[GetRegionFromX(l)][GetRegionFromY(l)].t == kTetris)
1927  {
1928  int whichConstraint = regionConstraints[GetRegionFromX(l)][GetRegionFromY(l)].parameter;
1929  int numPieces = tetrisSize[whichConstraint];
1930  tetrisBlockCount[x] += numPieces;
1931  }
1932  else if (regionConstraints[GetRegionFromX(l)][GetRegionFromY(l)].t == kNegativeTetris)
1933  {
1934  int whichConstraint = regionConstraints[GetRegionFromX(l)][GetRegionFromY(l)].parameter;
1935  int numPieces = tetrisSize[whichConstraint];
1936  tetrisBlockCount[x] -= numPieces;
1937  }
1938  }
1939  // 2. Make sure the counts of tetris blocks matches the region size
1940  if (tetrisBlockCount[x] > 0 && tetrisBlockCount[x] != regionList[x]->size())
1941  {
1942  // printf("Region %d has %d tetris blocks and size %lu\n", x, tetrisBlockCount[x],
1943  // regionList[x].size());
1944  return false;
1945  }
1946  }
1947 
1948  // 3. Do the full layout
1949  for (int x = 0; x < regionList.size(); x++)
1950  {
1951  bool hasNegations = false;
1952  const auto &v = *regionList[x]; // v is vector of locations in this region
1953  if (v.size() == 0) continue;
1954 
1955  tetrisBlocksInRegion.resize(0);
1956  // Get bit map of board
1957  uint64_t board = 0;
1958 
1959  for (auto l: v) // individual location
1960  {
1961  uint64_t xx = GetRegionFromX(l); // l%width;
1962  uint64_t yy = GetRegionFromY(l); // l/width;
1963  // x and y are offset from bottom left (screen space)
1964  // need to convert to 8x8 bitmaps space
1965  board |= ((1ull << (7 - xx)) << ((7 - yy) * 8));
1966 
1967  if (regionConstraints[GetRegionFromX(l)][GetRegionFromY(l)].t == kTetris)
1968  {
1969  int whichConstraint = regionConstraints[xx][yy].parameter; // tetrisConstraints[l];
1970  tetrisBlocksInRegion.push_back(whichConstraint);
1971  }
1972  if (regionConstraints[GetRegionFromX(l)][GetRegionFromY(l)].t == kNegativeTetris)
1973  {
1974  int whichConstraint = regionConstraints[xx][yy].parameter; // tetrisConstraints[l];
1975  tetrisBlocksInRegion.push_back(-whichConstraint);
1976  hasNegations = true;
1977  }
1978 
1979  // int whichConstraint = constraints[xx][yy].parameter;//tetrisConstraints[l];
1980  // if (whichConstraint > 0)
1981  // {
1982  // tetrisBlocksInRegion.push_back(whichConstraint);
1983  // }
1984  // else if (whichConstraint < 0)
1985  // { // negative constraints are just another xor
1986  // tetrisBlocksInRegion.push_back(whichConstraint);
1987  // hasNegations = true;
1988  // }
1989  }
1990 
1991  if (tetrisBlocksInRegion.size() == 0) continue;
1992 
1993  // Get out of bounds map -- places pieces can't go
1994  uint64_t oob = ~board;
1995  if (hasNegations) oob = 0;
1996  // printf("Region %d\n", x);
1997  // DebugPrint(board);
1998  // DebugPrint(oob);
1999 
2000  // 4. Now we have all pieces, recursively try to place them
2001  if (!RecursivelyPlacePieces(0, board, oob, 0, 0))
2002  return false; // No way to place them
2003  // printf("-%d-\n", 0);
2004  // DebugPrint(board, 0);
2005  // printf("Region %d successful\n", x);
2006  }
2007  return true; // didn't find a way to place them
2008  }
2009 
2010  return true;
2011 }
2012 
2013 template<int width, int height>
2015  int curr, uint64_t board, uint64_t oob, uint64_t posFootprint, uint64_t negFootprint) const
2016 {
2017  // DebugPrint(board, curr*2);
2018  if (curr == tetrisBlocksInRegion.size()) return (board == 0) && ((negFootprint & posFootprint) == negFootprint);
2019 
2020  bool neg = false;
2021  int whichBlock = tetrisBlocksInRegion[curr];
2022  if (whichBlock < 0)
2023  {
2024  neg = true;
2025  whichBlock = -whichBlock;
2026  }
2027 
2028  // In theory we should just check where pieces are placed, instead of the whole grid.
2029  // But, this optimization currently requires that the upper/left corner of the piece bitmap always
2030  // contains a piece, which it doesn't. Adding a reference point offset for each piece type would
2031  // solve this, but we are first worried about writing correct code
2032  for (int x = 0; x < width - tetrisWH[whichBlock][0] + 1; x++)
2033  {
2034  for (int y = 0; y < height - tetrisWH[whichBlock][1] + 1; y++)
2035  {
2036  // printf("%d in %d,%d\n", whichBlock, x, y);
2037  uint64_t block = ((tetrisBits64[whichBlock] >> x) >> (8 * y));
2038  board ^= block;
2039  if ((board & oob) == 0) // piece not out of bounds
2040  {
2041  if (RecursivelyPlacePieces(curr + 1, board, oob, neg ? posFootprint : (posFootprint | block),
2042  neg ? (negFootprint | block) : negFootprint))
2043  {
2044  // printf("-%d-\n", curr+1);
2045  // DebugPrint(board, 0);
2046  return true;
2047  }
2048  }
2049  else
2050  {
2051  // DebugPrint(board, curr*2+4);
2052  }
2053  board ^= block; //(tetrisBits64[whichBlock]>>x)>>(8*y);
2054  }
2055  }
2056  return false;
2057 }
2058 
2059 template<int width, int height>
2060 uint64_t Witness<width, height>::GetMaxHash() const { assert(false); }
2061 
2062 template<int width, int height>
2064 {
2065  assert(false);
2066 }
2067 
2068 template<int width, int height>
2070 {
2071  assert(false);
2072 }
2073 
2074 template<int width, int height>
2075 uint64_t Witness<width, height>::GetActionHash(WitnessAction act) const { return act; }
2076 
2077 template<int width, int height>
2079 {
2080  return width * (height + 1) + (width + 1) * height + (width + 1) * (height + 1);
2081 }
2082 
2083 #pragma mark -
2084 #pragma mark Path Constraints
2085 #pragma mark -
2086 
2087 template<int width, int height>
2089 {
2090  pathConstraints[which] = kMustCross;
2091 }
2092 
2093 template<int width, int height>
2095 {
2096  return (pathConstraints[which] == kMustCross);
2097  // if (which < width*(height+1))
2098  // {
2099  // int x = which%(width);
2100  // int y = which/(width);
2101  // mustCrossEdgeConstraint e = {true, {x, y}};
2102  // for (const auto &c : mustCrossEdgeConstraints)
2103  // if (e == c)
2104  // return true;
2105  // return false;
2106  // }
2107  // which -= width*(height+1);
2108  // if (which < (width+1)*height)
2109  // {
2110  // int x = which%(width+1);
2111  // int y = which/(width+1);
2112  // mustCrossEdgeConstraint e = {false, {x, y}};
2113  // for (const auto &c : mustCrossEdgeConstraints)
2114  // if (e == c)
2115  // return true;
2116  // return false;
2117  // }
2118  // which -= (width+1)*height;
2119  // // constraint on corner
2120  // int x = which%(width+1);
2121  // int y = which/(width+1);
2122  // std::pair<int, int> e = {x, y};
2123  // for (const auto &c : mustCrossConstraints)
2124  // if (e == c)
2125  // return true;
2126  // return false;
2127 }
2128 
2129 template<int width, int height>
2131 {
2132  pathConstraints[which] = kNoPathConstraint;
2133 }
2134 
2135 template<int width, int height>
2137  bool horiz, int x, int y) const // { mustCrossEdgeConstraints.push_back({horiz, {x, y}});}
2138 {
2139  if (horiz)
2140  return GetMustCrossConstraint(y * width + x);
2141  else
2142  return GetMustCrossConstraint(width * (height + 1) + x * height + y);
2143 }
2144 
2145 template<int width, int height>
2147  int x, int y) const // { mustCrossEdgeConstraints.push_back({horiz, {x, y}});}
2148 {
2149  return GetMustCrossConstraint(width * (height + 1) + (width + 1) * height + (width + 1) * y + x);
2150 }
2151 
2152 template<int width, int height>
2154  int y) // { mustCrossEdgeConstraints.push_back({horiz, {x, y}});}
2155 {
2156  if (horiz)
2157  SetMustCrossConstraint(y * width + x);
2158  else
2159  SetMustCrossConstraint(width * (height + 1) + x * height + y);
2160 }
2161 
2162 template<int width, int height>
2163 void Witness<width, height>::AddMustCrossConstraint(int x, int y) // { mustCrossConstraints.push_back({x, y});}
2164 {
2165  // if (which < width*(height+1))
2166  // {
2167  // int x = which%(width);
2168  // int y = which/(width);
2169  // AddMustCrossConstraint(true, x, y);
2170  // return;
2171  // }
2172  // which -= width*(height+1);
2173  // if (which < (width+1)*height)
2174  // {
2175  // int x = which%(width+1);
2176  // int y = which/(width+1);
2177  // AddMustCrossConstraint(false, x, y);
2178  // return;
2179  // }
2180  // which -= (width+1)*height;
2181  // // constraint on corner
2182  // int x = which%(width+1);
2183  // int y = which/(width+1);
2184  SetMustCrossConstraint(width * (height + 1) + (width + 1) * height + (width + 1) * y + x);
2185  // AddMustCrossConstraint(x, y);
2186 }
2187 
2188 template<int width, int height>
2189 void Witness<width, height>::AddMustCrossConstraint(int which) // { mustCrossConstraints.push_back({x, y});}
2190 {
2191  pathConstraints[which] = kMustCross;
2192 }
2193 
2194 template<int width, int height>
2196  int y) // { mustCrossEdgeConstraints.pop_back();}
2197 {
2198  if (horiz)
2199  RemoveMustCrossConstraint(y * width + x);
2200  else
2201  RemoveMustCrossConstraint(width * (height + 1) + x * height + y);
2202 
2203  // if (which < width*(height+1))
2204  // {
2205  // int x = which%(width);
2206  // int y = which/(width);
2207  // RemoveMustCrossConstraint(true, x, y);
2208  // return;
2209  // }
2210  // which -= width*(height+1);
2211  // if (which < (width+1)*height)
2212  // {
2213  // int x = which%(width+1);
2214  // int y = which/(width+1);
2215  // RemoveMustCrossConstraint(false, x, y);
2216  // return;
2217  // }
2218  // which -= (width+1)*height;
2219  // // constraint on corner
2220  // int x = which%(width+1);
2221  // int y = which/(width+1);
2222  // RemoveMustCrossConstraint(x, y);
2223 }
2224 
2225 template<int width, int height>
2226 void Witness<width, height>::RemoveMustCrossConstraint(int x, int y) // { mustCrossConstraints.pop_back();}
2227 {
2228  ClearMustCrossConstraint(width * (height + 1) + (width + 1) * height + (width + 1) * y + x);
2229 }
2230 
2231 template<int width, int height>
2233 {
2234  return width * (height + 1) + (width + 1) * height + (width + 1) * (height + 1);
2235 }
2236 
2237 template<int width, int height>
2239 {
2240  pathConstraints[which] = kCannotCross;
2241  // if (which < width*(height+1))
2242  // {
2243  // int x = which%(width);
2244  // int y = which/(width);
2245  // AddCannotCrossConstraint(true, x, y);
2246  // return;
2247  // }
2248  // which -= width*(height+1);
2249  // if (which < (width+1)*height)
2250  // {
2251  // int x = which%(width+1);
2252  // int y = which/(width+1);
2253  // AddCannotCrossConstraint(false, x, y);
2254  // return;
2255  // }
2256  // which -= (width+1)*height;
2257  // // constraint on corner
2258  // int x = which%(width+1);
2259  // int y = which/(width+1);
2260  // AddCannotCrossConstraint(x, y);
2261 }
2262 
2263 template<int width, int height>
2265 {
2266  return (pathConstraints[which] == kCannotCross);
2267  // if (which < width*(height+1))
2268  // {
2269  // int x = which%(width);
2270  // int y = which/(width);
2271  // mustCrossEdgeConstraint e = {true, {x, y}};
2272  // for (const auto &c : cannotCrossEdgeConstraints)
2273  // if (e == c)
2274  // return true;
2275  // return false;
2276  // }
2277  // which -= width*(height+1);
2278  // if (which < (width+1)*height)
2279  // {
2280  // int x = which%(width+1);
2281  // int y = which/(width+1);
2282  // mustCrossEdgeConstraint e = {false, {x, y}};
2283  // for (const auto &c : cannotCrossEdgeConstraints)
2284  // if (e == c)
2285  // return true;
2286  // return false;
2287  // }
2288  // which -= (width+1)*height;
2289  // // constraint on corner
2290  // int x = which%(width+1);
2291  // int y = which/(width+1);
2292  // std::pair<int, int> e = {x, y};
2293  // for (const auto &c : cannotCrossConstraints)
2294  // if (e == c)
2295  // return true;
2296  // return false;
2297 }
2298 
2299 template<int width, int height>
2301 {
2302  pathConstraints[which] = kNoPathConstraint;
2303  // if (which < width*(height+1))
2304  // {
2305  // int x = which%(width);
2306  // int y = which/(width);
2307  // RemoveCannotCrossConstraint(true, x, y);
2308  // return;
2309  // }
2310  // which -= width*(height+1);
2311  // if (which < (width+1)*height)
2312  // {
2313  // int x = which%(width+1);
2314  // int y = which/(width+1);
2315  // RemoveCannotCrossConstraint(false, x, y);
2316  // return;
2317  // }
2318  // which -= (width+1)*height;
2319  // // constraint on corner
2320  // int x = which%(width+1);
2321  // int y = which/(width+1);
2322  // RemoveCannotCrossConstraint(x, y);
2323 }
2324 
2325 template<int width, int height>
2327  int x, int y) const // { mustCrossEdgeConstraints.push_back({horiz, {x, y}});}
2328 {
2329  return GetCannotCrossConstraint(width * (height + 1) + (width + 1) * height + (width + 1) * y + x);
2330 }
2331 
2332 template<int width, int height>
2334  bool horiz, int x, int y) const // { mustCrossEdgeConstraints.push_back({horiz, {x, y}});}
2335 {
2336  if (horiz)
2337  return GetCannotCrossConstraint(y * width + x);
2338  else
2339  return GetCannotCrossConstraint(width * (height + 1) + x * height + y);
2340 }
2341 
2342 template<int width, int height>
2344  bool horiz, int x, int y) // { cannotCrossEdgeConstraints.push_back({horiz, {x, y}});}
2345 {
2346  if (horiz)
2347  AddCannotCrossConstraint(y * width + x);
2348  else
2349  AddCannotCrossConstraint(width * (height + 1) + x * height + y);
2350 }
2351 
2352 template<int width, int height>
2353 void Witness<width, height>::AddCannotCrossConstraint(int x, int y) // { cannotCrossConstraints.push_back({x, y});}
2354 {
2355  SetCannotCrossConstraint(width * (height + 1) + (width + 1) * height + (width + 1) * y + x);
2356 }
2357 
2358 template<int width, int height>
2359 void Witness<width, height>::AddCannotCrossConstraint(int which) // { cannotCrossConstraints.push_back({x, y});}
2360 {
2361  pathConstraints[which] = kCannotCross;
2362 }
2363 
2364 template<int width, int height>
2366  int y) // { cannotCrossEdgeConstraints.pop_back();}
2367 {
2368  if (horiz)
2369  RemoveCannotCrossConstraint(y * width + x);
2370  else
2371  RemoveCannotCrossConstraint(width * (height + 1) + x * height + y);
2372 }
2373 
2374 template<int width, int height>
2375 void Witness<width, height>::RemoveCannotCrossConstraint(int x, int y) // { cannotCrossConstraints.pop_back();}
2376 {
2377  RemoveCannotCrossConstraint(width * (height + 1) + (width + 1) * height + (width + 1) * y + x);
2378 }
2379 
2380 #pragma mark -
2381 #pragma mark Solver Helper Functions
2382 #pragma mark -
2383 
2384 template<int width, int height>
2386 {
2387  regions.fill(0);
2388  // regions.clear();
2389  // regions.resize(width*height);
2390  for (std::vector<int> *i: regionList)
2391  {
2392  // printf("Returned %p; ", i);
2393  regionCache.returnItem(i);
2394  }
2395  regionList.resize(0);
2396  // printf("Size to %lu\n", regionList.size());
2397 
2398  // static
2399  std::vector<int> queue;
2400  queue.clear();
2401 
2402  int index = 0;
2403  for (int y = 0; y < height; y++)
2404  {
2405  for (int x = 0; x < width; x++)
2406  {
2407  if (regions[GetRegionIndex(x, y) /*y*width+x*/] == 0)
2408  {
2409  queue.push_back(GetRegionIndex(x, y));
2410  index++;
2411  while (regionList.size() < index)
2412  {
2413  regionList.push_back(regionCache.getItem());
2414  // printf("Got %p; ", regionList.back());
2415  // printf("size to %lu\n", regionList.size());
2416  }
2417  // regionList.resize(index);
2418  }
2419  while (queue.size() > 0)
2420  {
2421  int next = queue.back();
2422  queue.pop_back();
2423 
2424  if (regions[next] == 0)
2425  {
2426  regions[next] = index;
2427  regionList[index - 1]->push_back(next);
2428  // check 4 directions
2429  int xx = GetRegionFromX(next);
2430  int yy = GetRegionFromY(next);
2431  if (xx > 0 && !s.OccupiedEdge(xx, yy, xx, yy + 1) && regions[GetRegionIndex(xx - 1, yy)] == 0)
2432  queue.push_back(GetRegionIndex(xx - 1, yy));
2433  if (xx < width - 1 && !s.OccupiedEdge(xx + 1, yy, xx + 1, yy + 1) &&
2434  regions[GetRegionIndex(xx + 1, yy)] == 0)
2435  queue.push_back(GetRegionIndex(xx + 1, yy));
2436  if (yy > 0 && !s.OccupiedEdge(xx, yy, xx + 1, yy) && regions[GetRegionIndex(xx, yy - 1)] == 0)
2437  queue.push_back(GetRegionIndex(xx, yy - 1));
2438  if (yy < height - 1 && !s.OccupiedEdge(xx, yy + 1, xx + 1, yy + 1) &&
2439  regions[GetRegionIndex(xx, yy + 1)] == 0)
2440  queue.push_back(GetRegionIndex(xx, yy + 1));
2441  }
2442  }
2443  }
2444  }
2445 
2446  // for (auto i : s.path)
2447  // std::cout << "(" << i.first << ", " << i.second << ") ";
2448  // std::cout << "\n";
2449  //
2450  // printf(" ");
2451  // for (int x = 0; x < width; x++)
2452  // {
2453  // if (s.OccupiedEdge(x, 0, x+1, 0))
2454  // printf("- ");
2455  // else
2456  // printf(" ");
2457  // }
2458  // printf("\n");
2459  //
2460  // for (int y = 0; y < height; y++)
2461  // {
2462  // if (s.OccupiedEdge(0, y, 0, y+1))
2463  // printf("|");
2464  // else
2465  // printf(" ");
2466  // for (int x = 0; x < width; x++)
2467  // {
2468  // printf("%d", regions[GetIndex(x, y)]);
2469  // if (s.OccupiedEdge(x+1, y, x+1, y+1))
2470  // printf("|");
2471  // else
2472  // printf(" ");
2473  // }
2474  // printf("\n");
2475  // printf(" ");
2476  // for (int x = 0; x < width; x++)
2477  // {
2478  // if (s.OccupiedEdge(x, y+1, x+1, y+1))
2479  // printf("- ");
2480  // else
2481  // printf(" ");
2482  // }
2483  // printf("\n");
2484  // }
2485  // printf("\n\n");
2486 }
2487 
2488 #pragma mark -
2489 #pragma mark GUI
2490 #pragma mark -
2491 
2492 template<int width, int height>
2494 {
2495  // in start area
2496  // std::cout << mouseLoc-GetScreenCoord(0, 0) << " size " << (mouseLoc-GetScreenCoord(0, 0)).length() << " vs " <<
2497  // 3*lineWidth << "\n";
2500  (mouseLoc - GetScreenCoord(start[0].first, start[0].second)).length() < 3 * lineWidth)
2501  {
2502  // printf("Switched from watiting to start to kInPoint\n");
2503  ApplyAction(iws.ws, kStart);
2505  return false;
2506  }
2507 
2508  if (iws.ws.path.size() > 0 &&
2509  (iws.ws.path.back().second > height || iws.ws.path.back().second < 0 || iws.ws.path.back().first > width ||
2510  iws.ws.path.back().first < 0)) // at goal, may not be solution
2511  {
2513  return true;
2514  }
2515 
2516  if (iws.target.first < 0 || iws.target.first > width || iws.target.second < 0 || iws.target.second > height)
2517  {
2518  // mouse is off screen; might be trying to exit with mouse out of the goal
2519  if (Legal(iws.ws, kEnd))
2520  {
2521  ApplyAction(iws.ws, kEnd);
2523  return true;
2524  }
2525  }
2526 
2527  // quit path
2528  iws.Reset();
2529  return false;
2530 }
2531 
2532 template<int width, int height>
2534 {
2537  {
2538  return;
2539  }
2540 
2542  {
2543  Graphics::point end = GetScreenCoord(iws.ws.path.back().first, iws.ws.path.back().second);
2544 
2545  float factor = 3;
2546  if (iws.ws.path.size() > 1) factor = 1;
2547 
2548  // check if we left the point
2549  if (!Graphics::PointInRect(mouseLoc, Graphics::rect(end, factor * lineWidth)))
2550  {
2551  // 1. Find closest successor to mouse
2552  // find where to add to path
2553  std::vector <WitnessAction> moves;
2554  GetMouseActions(iws.ws, moves);
2555 
2556  iws.target = iws.ws.path.back();
2557  WitnessAction a = moves[0];
2558  float dist = 1000;
2559  for (auto m: moves)
2560  {
2561  iws.target = iws.ws.path.back();
2562  ApplyAction(iws.target, m);
2563  Graphics::point p = GetScreenCoord(iws.target.first, iws.target.second);
2564  // std::cout << "Dist from " << mouseLoc << " to " << p << " is " << ((mouseLoc-p).length()) << " act: "
2565  // << m << "\n";
2566  if ((mouseLoc - p).length() < dist)
2567  {
2568  dist = (mouseLoc - p).length();
2569  a = m;
2570  }
2571  }
2572 
2573  // 2. Add to target location
2574  iws.target = iws.ws.path.back();
2575  ApplyAction(iws.target, a);
2576  iws.targetAct = a;
2577 
2578  // 3. Change state
2579  // printf("Switched from kInPoint to kBetweenPoints\n");
2581  iws.frac = 0;
2582 
2583  int len = static_cast<int>(iws.ws.path.size());
2584 
2585  if (len >= 2 && iws.target == iws.ws.path[len - 2]) // going backwards
2586  {
2587  iws.target = iws.ws.path.back();
2588  InvertAction(iws.targetAct);
2589  iws.frac = 1.0;
2590  UndoAction(iws.ws, a);
2591  // printf("Switched from kInPoint to kBetweenPoints [backwards]\n");
2593  }
2594  }
2595 
2596  return;
2597  }
2598 
2600  {
2601  Graphics::point from = GetScreenCoord(iws.ws.path.back().first, iws.ws.path.back().second);
2602  Graphics::point to = GetScreenCoord(iws.target.first, iws.target.second);
2603 
2604  // check if we entered the end (legally)
2605  if (Graphics::PointInRect(mouseLoc, Graphics::rect(to, lineWidth)) && Legal(iws.ws, iws.targetAct))
2606  {
2608  ApplyAction(iws.ws, iws.targetAct);
2609  // printf("Switched from kBetweenPoints to kInPoint [1]\n");
2610  }
2611  else if (from.x == to.x && (mouseLoc.y - from.y) / (to.y - from.y) > 0.9 &&
2612  Legal(iws.ws, iws.targetAct)) // tracking in y
2613  {
2615  ApplyAction(iws.ws, iws.targetAct);
2616  // printf("Switched from kBetweenPoints to kInPoint [2]\n");
2617  }
2618  else if (from.y == to.y && (mouseLoc.x - from.x) / (to.x - from.x) > 0.9 &&
2619  Legal(iws.ws, iws.targetAct)) // tracking in x
2620  {
2622  ApplyAction(iws.ws, iws.targetAct);
2623  // printf("Switched from kBetweenPoints to kInPoint [3]\n");
2624  }
2625  // entered start
2626  else if (Graphics::PointInRect(mouseLoc, Graphics::rect(from, lineWidth)))
2627  {
2629  // printf("Switched from kBetweenPoints to kInPoint [backtrack:1]\n");
2630  }
2631  else if (from.x == to.x && (mouseLoc.y - from.y) / (to.y - from.y) < 0.1) // tracking in y
2632  {
2634  // printf("Switched from kBetweenPoints to kInPoint [backtrack:2]\n");
2635  }
2636  else if (from.y == to.y && (mouseLoc.x - from.x) / (to.x - from.x) < 0.1) // tracking in x
2637  {
2639  // printf("Switched from kBetweenPoints to kInPoint [backtrack:3]\n");
2640  }
2641 
2642  // If still tracking, update track distance
2644  {
2645  double gapSize;
2646  if (from.x == to.x) // tracking in y
2647  {
2648  iws.frac = (mouseLoc.y - from.y) / (to.y - from.y);
2649  gapSize = lineWidth / fabs(to.y - from.y);
2650  }
2651  else
2652  {
2653  iws.frac = (mouseLoc.x - from.x) / (to.x - from.x);
2654  gapSize = lineWidth / fabs(to.x - from.x);
2655  }
2656 
2657  if (iws.frac > 1) iws.frac = 1;
2658  legality l;
2659  if (!Legal(iws.ws, iws.targetAct, l))
2660  {
2661  // hitting start circle
2662  if ((iws.target == std::pair<int, int>(0, 0)) && iws.frac > 0.6f)
2663  iws.frac = 0.6f;
2664  else if (iws.frac > 0.5 - 2 * gapSize && l == kHitCannotCross) // hitting cannot cross constraint
2665  iws.frac = 0.5 - 2 * gapSize;
2666  else if (iws.frac > 0.8f && l == kHitLine) // hitting line
2667  iws.frac = 1.f - 2 * gapSize; // 0.8f;
2668  }
2669  // if (!Legal(iws.ws, iws.targetAct) && iws.frac > 0.8)
2670  // iws.frac = 0.8;
2671  if (iws.frac < 0) iws.frac = 0;
2672  }
2673  }
2674 }
2675 
2676 #pragma mark -
2677 #pragma mark Visualization
2678 #pragma mark -
2679 
2680 template<int width, int height>
2682  Graphics::Display &display, const WitnessRegionConstraint &constraint, const Graphics::point &p3) const
2683 {
2684  switch (constraint.t)
2685  {
2686  case kNoRegionConstraint:
2687  break;
2688  case kSeparation:
2689  {
2690  Graphics::point delta = Graphics::point{lineWidth, lineWidth};
2691  display.FillCircle(p3 + delta, lineWidth, constraint.c);
2692  display.FillCircle(p3 - delta, lineWidth, constraint.c);
2693  delta.x = -delta.x;
2694  display.FillCircle(p3 + delta, lineWidth, constraint.c);
2695  display.FillCircle(p3 - delta, lineWidth, constraint.c);
2696  display.FillRect(
2697  {p3.x - 1.0f * lineWidth, p3.y - 2.0f * lineWidth, p3.x + 1.0f * lineWidth,
2698  p3.y + 2.0f * lineWidth},
2699  constraint.c);
2700  display.FillRect(
2701  {p3.x - 2.0f * lineWidth, p3.y - 1.0f * lineWidth, p3.x + 2.0f * lineWidth,
2702  p3.y + 1.0f * lineWidth},
2703  constraint.c);
2704  break;
2705  }
2706  case kStar:
2707  {
2708  display.FillNGon(p3, gapOffset / 5.0f, 4, 0, constraint.c);
2709  display.FillNGon(p3, gapOffset / 5.0f, 4, 45, constraint.c);
2710  break;
2711  }
2712  case kTetris:
2713  case kNegativeTetris:
2714  {
2715  int whichPiece = abs(constraint.parameter);
2716  bool negative = constraint.t == kNegativeTetris; // constraint.parameter<0;
2717  if (whichPiece != 0)
2718  {
2719  float xOff = 0;
2720  float yOff = 0;
2721  switch (whichPiece)
2722  {
2723  case 1:
2724  xOff = 1.5;
2725  yOff = 1.5;
2726  break;
2727  case 2:
2728  xOff = 1;
2729  yOff = 1.5;
2730  break;
2731  case 3:
2732  xOff = 1.5;
2733  yOff = 1;
2734  break;
2735  case 4:
2736  case 5:
2737  case 6:
2738  case 7:
2739  case 8:
2740  xOff = 0.5;
2741  yOff = 1.5;
2742  break;
2743  case 9:
2744  xOff = 1.5;
2745  yOff = 0.5;
2746  break;
2747  case 10:
2748  xOff = 1;
2749  yOff = 1;
2750  break;
2751  case 11:
2752  case 12:
2753  case 13:
2754  case 14:
2755  xOff = 0.5;
2756  yOff = 1;
2757  break;
2758  case 15:
2759  case 16:
2760  case 17:
2761  case 18:
2762  xOff = 1;
2763  yOff = 0.5;
2764  break;
2765  case 19:
2766  xOff = 0;
2767  yOff = 1.5;
2768  break;
2769  case 20:
2770  xOff = 1.5;
2771  yOff = 0;
2772  break;
2773  case 21:
2774  case 22:
2775  xOff = 0.5;
2776  yOff = 1;
2777  break;
2778  case 23:
2779  case 24:
2780  xOff = 1.0;
2781  yOff = 0.5;
2782  break;
2783  }
2784  float blockSize = gapOffset / 8.0f;
2785  for (int yy = 0; yy < 4; yy++)
2786  {
2787  for (int xx = 0; xx < 4; xx++)
2788  {
2789  if ((tetrisBits[whichPiece] >> (yy * 4 + xx)) & 1)
2790  {
2791  Graphics::point p4(-2 * blockSize + xx * blockSize + 0.5f * blockSize - xOff * blockSize,
2792  -2 * blockSize + yy * blockSize + 0.5f * blockSize - yOff * blockSize);
2793  Graphics::rect r((p3 - p4), blockSize * 0.35f);
2794  if (negative)
2795  {
2796  display.FillRect(r, tetrisBlue);
2797  Graphics::rect inner((p3 - p4), blockSize * 0.35f * 0.55f);
2798  display.FillRect(inner, backColor);
2799  }
2800  else
2801  display.FillRect(r, tetrisYellow);
2802  }
2803  }
2804  }
2805  }
2806  break;
2807  }
2808  case kTriangle:
2809  {
2810  switch (constraint.parameter)
2811  {
2812  case 1:
2813  {
2814  display.FillNGon(p3, lineWidth * 0.9f, 3, 60, Colors::orange);
2815  break;
2816  }
2817  case 2:
2818  {
2819  Graphics::point p = p3;
2820  p.x -= lineWidth;
2821  display.FillNGon(p, lineWidth * 0.9f, 3, 60, Colors::orange);
2822  p.x += 2 * lineWidth;
2823  display.FillNGon(p, lineWidth * 0.9f, 3, 60, Colors::orange);
2824  break;
2825  }
2826  case 3:
2827  {
2828  Graphics::point p = p3;
2829  display.FillNGon(p, lineWidth * 0.9f, 3, 60, Colors::orange);
2830  p.x -= 2 * lineWidth;
2831  display.FillNGon(p, lineWidth * 0.9f, 3, 60, Colors::orange);
2832  p.x += 4 * lineWidth;
2833  display.FillNGon(p, lineWidth * 0.9f, 3, 60, Colors::orange);
2834  break;
2835  }
2836  }
2837  break;
2838  }
2839  case kEraser:
2840  break;
2842  break;
2843  }
2844 }
2845 
2846 template<int width, int height>
2848 {
2849  // Background drawing
2850  {
2851  Graphics::point p1 = GetScreenCoord(0, 0);
2852  Graphics::point p2 = GetScreenCoord(width, height);
2853 
2854  display.FillRect({-1, -1, 1, 1}, outerBackColor);
2855  display.FillRect({p1.x, p2.y, p2.x, p1.y}, backColor);
2856  }
2857 
2858  for (int x = 0; x <= width; x++)
2859  {
2860  DoLine(display, GetScreenCoord(x, 0), GetScreenCoord(x, height), lineColor);
2861  // display.FillRect({(-1+gapOffset*x-lineWidth)*scale, -1*scale, (-1+gapOffset*x+lineWidth)*scale, 1*scale},
2862  // Colors::lightgray);
2863  }
2864  for (int y = 0; y <= height; y++)
2865  {
2866  DoLine(display, GetScreenCoord(0, y), GetScreenCoord(width, y), lineColor);
2867  // display.FillRect({-1*scale, (-1+gapOffset*y-lineWidth)*scale, 1*scale, (-1+gapOffset*y+lineWidth)*scale},
2868  // Colors::lightgray);
2869  }
2870 
2871  // corners -- all in case we move the start/goal
2872  display.FillCircle(GetScreenCoord(0, height), lineWidth, lineColor);
2873  display.FillCircle(GetScreenCoord(width, 0), lineWidth, lineColor);
2874  display.FillCircle(GetScreenCoord(0, 0), lineWidth, lineColor);
2875  display.FillCircle(GetScreenCoord(width, height), lineWidth, lineColor);
2876 
2877  // start
2878  assert(start.size() > 0);
2879  for (const auto &i: start)
2880  display.FillCircle(GetScreenCoord(i.first, i.second), lineWidth * 3.f, lineColor);
2881 
2882  // Draw end points. Would be more efficient to iterate goals, but then we have to
2883  // remap them onto edges. Loss of efficiency is negligible
2884  for (int x = 0; x <= width; x++)
2885  {
2886  for (int y = 0; y <= width; y++)
2887  {
2888  int val;
2889  if ((val = goalMap[GetPathIndex(x, y)]) != 0)
2890  {
2891  auto endLoc = GetScreenCoord(goal[val - 1].first, goal[val - 1].second);
2892  DoLine(display, GetScreenCoord(x, y), endLoc, lineColor);
2893  display.FillCircle(endLoc, lineWidth, lineColor);
2894  }
2895  }
2896  }
2897  // for (const auto &i : goal)
2898  // {
2899  // auto endLoc = GetScreenCoord((i.first == width)?(width+1):(i.first==0?-1:i.first),
2900  // (i.second==height)?height+1:(i.second==0?-1:i.second));
2901  // auto gridLoc = GetScreenCoord(i.first, i.second);
2902  // DoLine(display, gridLoc, endLoc, lineColor);
2903  // display.FillCircle(endLoc, lineWidth, lineColor);
2904  // }
2905 
2906  for (int x = 0; x < width + 1; x++)
2907  {
2908  for (int y = 0; y < height + 1; y++)
2909  {
2910  if (GetMustCrossConstraint(x, y))
2911  {
2912  Graphics::point pt = GetScreenCoord(x, y);
2913  display.FillNGon(pt, lineWidth * 0.9f, 6, 30, Colors::black);
2914  }
2915  else if (GetCannotCrossConstraint(x, y))
2916  {
2917  Graphics::point pt = GetScreenCoord(x, y);
2918  Graphics::rect r(pt, lineWidth);
2919  display.FillSquare(pt, lineWidth, backColor);
2920  if (x > 0)
2921  {
2922  Graphics::point pt2 = GetScreenCoord(x - 1, y);
2923  // pt2 = (pt+pt2)*0.5;
2924  pt2.x += lineWidth;
2925  Graphics::rect r2(pt2, 0);
2926  r2 |= r;
2927  display.FillRect(r2, backColor);
2928  }
2929  if (x + 1 <= width)
2930  {
2931  Graphics::point pt2 = GetScreenCoord(x + 1, y);
2932  // pt2 = (pt+pt2)*0.5;
2933  pt2.x -= lineWidth;
2934  Graphics::rect r2(pt2, 0);
2935  r2 |= r;
2936  display.FillRect(r2, backColor);
2937  }
2938  if (y > 0)
2939  {
2940  Graphics::point pt2 = GetScreenCoord(x, y - 1);
2941  // pt2 = (pt+pt2)*0.5;
2942  pt2.y -= lineWidth;
2943  Graphics::rect r2(pt2, 0);
2944  r2 |= r;
2945  display.FillRect(r2, backColor);
2946  }
2947  if (y + 1 <= width)
2948  {
2949  Graphics::point pt2 = GetScreenCoord(x, y + 1);
2950  // pt2 = (pt+pt2)*0.5;
2951  pt2.y += lineWidth;
2952 
2953  Graphics::rect r2(pt2, 0);
2954  r2 |= r;
2955  display.FillRect(r2, backColor);
2956  }
2957  }
2958  }
2959  }
2960  for (int x = 0; x < width; x++)
2961  {
2962  for (int y = 0; y <= height; y++)
2963  {
2964  if (GetMustCrossConstraint(true, x, y))
2965  {
2966  Graphics::point p1 = GetScreenCoord(x, y);
2967  Graphics::point p2 = GetScreenCoord(x + 1, y);
2968  Graphics::point pt = (p1 + p2) * 0.5;
2969  display.FillNGon(pt, lineWidth * 0.9f, 6, 30, Colors::black);
2970  }
2971  else if (GetCannotCrossConstraint(true, x, y))
2972  {
2973  Graphics::point p1 = GetScreenCoord(x, y);
2974  Graphics::point p2 = GetScreenCoord(x + 1, y);
2975  Graphics::point pt = (p1 + p2) * 0.5;
2976  display.FillSquare(pt, lineWidth, backColor);
2977  }
2978  }
2979  }
2980  for (int x = 0; x <= width; x++)
2981  {
2982  for (int y = 0; y < height; y++)
2983  {
2984  if (GetMustCrossConstraint(false, x, y))
2985  {
2986  Graphics::point p1 = GetScreenCoord(x, y);
2987  Graphics::point p2 = GetScreenCoord(x, y + 1);
2988  Graphics::point pt = (p1 + p2) * 0.5;
2989  display.FillNGon(pt, lineWidth * 0.9f, 6, 30, Colors::black);
2990  }
2991  else if (GetCannotCrossConstraint(false, x, y))
2992  {
2993  Graphics::point p1 = GetScreenCoord(x, y);
2994  Graphics::point p2 = GetScreenCoord(x, y + 1);
2995  Graphics::point pt = (p1 + p2) * 0.5;
2996  display.FillSquare(pt, lineWidth, backColor);
2997  }
2998  }
2999  }
3000 
3001  // // must-cross constraints (polygons)
3002  // for (auto &c : mustCrossEdgeConstraints)
3003  // {
3004  // Graphics::point p1 = GetScreenCoord(c.location.first, c.location.second);
3005  // Graphics::point p2 = GetScreenCoord(c.location.first+(c.horiz?1:0), c.location.second+(c.horiz?0:1));
3006  // Graphics::point pt = (p1+p2)*0.5;
3007  // display.FillNGon(pt, lineWidth*0.9f, 6, 30, Colors::black);
3008  // }
3009  // for (auto &c : mustCrossConstraints)
3010  // {
3011  // Graphics::point pt = GetScreenCoord(c.first, c.second);
3012  // display.FillNGon(pt, lineWidth*0.9f, 6, 30, Colors::black);
3013  // }
3014  //
3015  // // must-cross constraints (polygons)
3016  // for (auto &c : cannotCrossEdgeConstraints)
3017  // {
3018  // Graphics::point p1 = GetScreenCoord(c.location.first, c.location.second);
3019  // Graphics::point p2 = GetScreenCoord(c.location.first+(c.horiz?1:0), c.location.second+(c.horiz?0:1));
3020  // Graphics::point pt = (p1+p2)*0.5;
3021  // display.FillSquare(pt, lineWidth, backColor);
3022  // }
3023  // for (auto &c : cannotCrossConstraints)
3024  // {
3025  // Graphics::point pt = GetScreenCoord(c.first, c.second);
3026  // Graphics::rect r(pt, lineWidth);
3027  // display.FillSquare(pt, lineWidth, backColor);
3028  // if (c.first > 0)
3029  // {
3030  // Graphics::point pt2 = GetScreenCoord(c.first-1, c.second);
3032  // pt2.x += lineWidth;
3033  // Graphics::rect r2(pt2, 0);
3034  // r2 |= r;
3035  // display.FillRect(r2, backColor);
3036  // }
3037  // if (c.first+1 <= width)
3038  // {
3039  // Graphics::point pt2 = GetScreenCoord(c.first+1, c.second);
3040  // //pt2 = (pt+pt2)*0.5;
3041  // pt2.x -= lineWidth;
3042  // Graphics::rect r2(pt2, 0);
3043  // r2 |= r;
3044  // display.FillRect(r2, backColor);
3045  // }
3046  // if (c.second > 0)
3047  // {
3048  // Graphics::point pt2 = GetScreenCoord(c.first, c.second-1);
3049  // //pt2 = (pt+pt2)*0.5;
3050  // pt2.y -= lineWidth;
3051  // Graphics::rect r2(pt2, 0);
3052  // r2 |= r;
3053  // display.FillRect(r2, backColor);
3054  // }
3055  // if (c.second+1 <= width)
3056  // {
3057  // Graphics::point pt2 = GetScreenCoord(c.first, c.second+1);
3058  // //pt2 = (pt+pt2)*0.5;
3059  // pt2.y += lineWidth;
3060  //
3061  // Graphics::rect r2(pt2, 0);
3062  // r2 |= r;
3063  // display.FillRect(r2, backColor);
3064  // }
3065  // }
3066 
3067  for (int x = 0; x < width; x++)
3068  {
3069  for (int y = 0; y < height; y++)
3070  {
3071  Graphics::point p1 = GetScreenCoord(x, y);
3072  Graphics::point p2 = GetScreenCoord(x + 1, y + 1);
3073  Graphics::point pt = (p1 + p2) * 0.5;
3074  DrawRegionConstraint(display, regionConstraints[x][y], pt);
3075  }
3076  }
3077 }
3078 
3079 template<int width, int height>
3081 {
3082  if (s.path.size() == 0)
3083  {
3084  return;
3085  }
3086  display.FillCircle(GetScreenCoord(start[0].first, start[0].second), lineWidth * 3.f, drawColor);
3087  for (int x = 1; x < s.path.size(); x++)
3088  {
3089  Graphics::point p1 = GetScreenCoord(s.path[x - 1].first, s.path[x - 1].second);
3090  Graphics::point p2 = GetScreenCoord(s.path[x].first, s.path[x].second);
3091 
3092  DoLine(display, p1, p2, drawColor);
3093 
3094  if (x > 1)
3095  {
3096  display.FillCircle(p1, lineWidth, drawColor);
3097  }
3098  display.FillCircle(p2, lineWidth, drawColor);
3099  // if (x == s.path.size()-1)
3100  // display.FillCircle(p2, lineWidth*0.75f, lineColor);
3101  }
3102 }
3103 
3104 template<int width, int height>
3106 {
3107  // float scale = 0.8f;
3108 
3109  // draw animated start marker
3111  {
3112  assert((iws.ws.path.size() == 0));
3113  if (iws.frac <= 1)
3114  display.FrameCircle(GetScreenCoord(start[0].first, start[0].second), lineWidth * 3.f * iws.frac, drawColor,
3115  lineWidth * 0.5f);
3116  return;
3117  }
3118 
3119  // draw main state
3120  Draw(display, iws.ws);
3121 
3123  {
3124  // draw last fraction
3125  Graphics::point p1 = GetScreenCoord(iws.ws.path.back().first, iws.ws.path.back().second);
3126  Graphics::point p2 = GetScreenCoord(iws.target.first, iws.target.second);
3127  p2 = p1 + (p2 - p1) * iws.frac;
3128  DoLine(display, p1, p2, drawColor);
3129  display.FillCircle(p2, lineWidth, drawColor);
3130  display.FillCircle(p2, lineWidth * 0.5f, lineColor);
3131  }
3132  else
3133  {
3134  Graphics::point p2 = GetScreenCoord(iws.ws.path.back().first, iws.ws.path.back().second);
3135  display.FillCircle(p2, lineWidth * 0.5f, lineColor);
3136  }
3137 }
3138 
3139 template<int width, int height>
3140 inline std::ostream& operator<<(std::ostream &os, const Witness<width, height> &witness)
3141 {
3142  return witness.Serialize(os);
3143 }
3144 
3145 template<int width, int height>
3146 inline std::istream& operator>>(std::istream &is, Witness<width, height> &witness)
3147 {
3148  return witness.Deserialize(is);
3149 }
3150 
3151 #endif // HOG2_ENVIRONMENTS_WITNESS_H
Graphics::Display::DrawLine
void DrawLine(point start, point end, float lineWidth, rgbColor c)
Definition: Graphics.cpp:184
Witness::GetMustCrossConstraint
bool GetMustCrossConstraint(int) const
Definition: Witness.h:2094
WitnessState::InGoal
bool InGoal() const
Definition: Witness.h:127
Witness::goalMap
std::array< int,(width+1) *(height+1)> goalMap
Definition: Witness.h:832
Witness::Legal
bool Legal(WitnessState< width, height > &s, WitnessAction a) const
Definition: Witness.h:1656
Graphics::point
Definition: Graphics.h:32
Witness::AddTetrisConstraint
void AddTetrisConstraint(int loc, int which)
Definition: Witness.h:724
Witness::constraintCount
std::array< int,(int) kRegionConstraintCount > constraintCount
Definition: Witness.h:266
Graphics::point::y
float y
Definition: Graphics.h:36
InteractiveWitnessState::kInPoint
@ kInPoint
Definition: Witness.h:174
Witness::GetActionHash
uint64_t GetActionHash(WitnessAction act) const
Definition: Witness.h:2075
Witness::pathConstraints
std::array< WitnessPathConstraintType, Witness< width, height >::GetNumPathConstraints()> pathConstraints
Definition: Witness.h:247
Witness::mustCrossEdgeConstraint::operator==
bool operator==(const mustCrossEdgeConstraint &a)
Definition: Witness.h:238
Witness::AddSeparationConstraint
void AddSeparationConstraint(int x, int y, rgbColor c)
Definition: Witness.h:597
Witness::GetSuccessors
void GetSuccessors(const WitnessState< width, height > &nodeID, std::vector< WitnessState< width, height >> &neighbors) const
Definition: Witness.h:1316
Witness::Witness
Witness()
Definition: Witness.h:279
rgbColor
A color; r/g/b are between 0...1.
Definition: Colors.h:17
Witness::PathLocation::x
int x
Definition: Witness.h:1193
Witness::tetrisWH
const uint16_t tetrisWH[25][2]
Definition: Witness.h:748
Graphics::Display::FillSquare
void FillSquare(point p, float radius, rgbColor c)
Definition: Graphics.cpp:92
min
double min(double a, double b)
Definition: FPUtil.h:35
Witness::GLDrawLine
void GLDrawLine(const WitnessState< width, height > &x, const WitnessState< width, height > &y) const
Definition: Witness.h:428
Witness::Click
bool Click(Graphics::point, InteractiveWitnessState< width, height > &ws)
Definition: Witness.h:2493
WitnessRegionConstraint::parameter
int parameter
Definition: Witness.h:194
Witness::ClearMustCrossConstraint
void ClearMustCrossConstraint(int)
Definition: Witness.h:2130
Witness::AddCannotCrossConstraint
void AddCannotCrossConstraint(bool horiz, int x, int y)
Definition: Witness.h:2343
InteractiveWitnessState::IncrementTime
void IncrementTime()
Definition: Witness.h:159
Witness::OpenGLDraw
void OpenGLDraw(const WitnessState< width, height > &, const WitnessState< width, height > &, float) const
Draw the transition at some percentage 0...1 between two states.
Definition: Witness.h:423
Colors::pink
const rgbColor pink
Definition: Colors.h:156
InteractiveWitnessState::controlState
controlState
Definition: Witness.h:172
Witness::SetMustCrossConstraint
void SetMustCrossConstraint(int)
Definition: Witness.h:2088
numPieces
const int numPieces
Definition: Hexagon.h:38
Witness::kHitLine
@ kHitLine
Definition: Witness.h:230
Witness::Reset
void Reset()
Definition: Witness.h:318
kEraser
@ kEraser
Definition: Witness.h:188
Witness::tetrisBlocksInRegion
std::vector< int > tetrisBlocksInRegion
Definition: Witness.h:1232
Witness::kHitCannotCross
@ kHitCannotCross
Definition: Witness.h:228
Witness::SetGoal
void SetGoal(int x, int y)
Definition: Witness.h:457
Witness::RemoveMustCrossConstraint
void RemoveMustCrossConstraint(bool horiz, int x, int y)
Definition: Witness.h:2195
WitnessRegionConstraintType
WitnessRegionConstraintType
Definition: Witness.h:181
WitnessState::Reset
void Reset()
Definition: Witness.h:57
Witness::separationObject::separationObject
separationObject()
Definition: Witness.h:258
Witness::separationObject
Definition: Witness.h:257
Witness::GetActions
void GetActions(const WitnessState< width, height > &nodeID, std::vector< WitnessAction > &actions) const
Definition: Witness.h:1322
Witness::GetMouseActions
void GetMouseActions(const WitnessState< width, height > &nodeID, std::vector< WitnessAction > &actions) const
Definition: Witness.h:1360
Graphics::rect
Definition: Graphics.h:94
InteractiveWitnessState::kBetweenPoints
@ kBetweenPoints
Definition: Witness.h:175
WitnessRegionConstraint::operator==
bool operator==(const WitnessRegionConstraint &a) const
Definition: Witness.h:197
WitnessState::occupiedEdges
std::bitset<(width+1) *(height)+(width) *(height+1)> occupiedEdges
Definition: Witness.h:46
Witness::GetStateHash
uint64_t GetStateHash(const WitnessState< width, height > &node) const
Definition: Witness.h:2063
InteractiveWitnessState::ws
WitnessState< width, height > ws
Definition: Witness.h:166
Witness::ClearTriangleConstraints
void ClearTriangleConstraints()
Definition: Witness.h:562
kUp
@ kUp
Definition: Witness.h:135
kEnd
@ kEnd
Definition: Witness.h:140
Witness::regionConstraints
std::array< std::array< WitnessRegionConstraint, height >, width > regionConstraints
Definition: Witness.h:264
Witness::AddEraserConstraint
void AddEraserConstraint(int x, int y)
Definition: Witness.h:620
width
int width
Definition: SFML_HOG.cpp:54
Witness::pathConstraintLocations
std::array< std::pair< Graphics::point, Graphics::rect >, Witness< width, height >::GetNumPathConstraints()> pathConstraintLocations
Definition: Witness.h:249
Witness::LoadFromHashString
void LoadFromHashString(std::string s)
Definition: Witness.h:1088
WitnessState::Occupied
bool Occupied(int x, int y) const
Definition: Witness.h:106
vectorCache.h
Witness::InvertAction
bool InvertAction(WitnessAction &a) const
Definition: Witness.h:1689
WitnessState::OccupyEdge
void OccupyEdge(int x1, int y1, int x2, int y2)
Definition: Witness.h:120
Colors::darkbluegray
const rgbColor darkbluegray
Definition: Colors.h:124
Graphics::Display::FillNGon
void FillNGon(point p, float radius, int sides, float rotation, rgbColor c)
Definition: Graphics.cpp:164
Witness::ClearConstraint
void ClearConstraint(WitnessRegionConstraintType t)
Definition: Witness.h:536
Witness::ApplyAction
void ApplyAction(WitnessState< width, height > &s, WitnessAction a) const
Definition: Witness.h:1461
Witness::GetNumTetrisConstraints
static constexpr int GetNumTetrisConstraints()
Definition: Witness.h:729
InteractiveWitnessState::target
std::pair< int, int > target
Definition: Witness.h:169
Witness::GetRegionIndex
int GetRegionIndex(int x, int y) const
Definition: Witness.h:1214
Witness::regionList
std::vector< std::vector< int > * > regionList
Definition: Witness.h:1228
Colors
Definition: Colors.cpp:21
kCannotCross
@ kCannotCross
Definition: Witness.h:216
Witness::AddRegionConstraint
void AddRegionConstraint(int x, int y, const WitnessRegionConstraint &constraint)
Definition: Witness.h:796
WitnessState::WitnessState
WitnessState(const WitnessState< width, height > &state)
Definition: Witness.h:50
Witness::kNotAtEnd
@ kNotAtEnd
Definition: Witness.h:225
kStart
@ kStart
Definition: Witness.h:139
Witness::backColor
const rgbColor backColor
Definition: Witness.h:1178
Witness::GetMaxHash
uint64_t GetMaxHash() const
Definition: Witness.h:2060
Witness::AddTriangleConstraint
void AddTriangleConstraint(int x, int y, int count)
Definition: Witness.h:568
Witness::DoLine
void DoLine(Graphics::Display &display, const Graphics::point &p1, const Graphics::point &p2, const rgbColor &c) const
Definition: Witness.h:1239
WitnessState
Definition: Witness.h:42
Graphics::PointInRect
bool PointInRect(const point &p, const rect &r)
Definition: Graphics.cpp:17
operator==
static bool operator==(const WitnessState< width, height > &a, const WitnessState< width, height > &b)
Definition: Witness.h:144
WitnessState::WitnessState
WitnessState()
Definition: Witness.h:48
constraint
Definition: Map2DConstrainedEnvironment.h:23
Witness::kHitStart
@ kHitStart
Definition: Witness.h:229
Witness::GetNumPathConstraints
static constexpr int GetNumPathConstraints()
Definition: Witness.h:2078
kMustCross
@ kMustCross
Definition: Witness.h:215
Witness::xGap
float xGap
Definition: Witness.h:1185
Witness::GetNumEraserConstraints
constexpr int GetNumEraserConstraints() const
Definition: Witness.h:618
Witness::RemoveRegionConstraint
void RemoveRegionConstraint(int x, int y)
Definition: Witness.h:552
Witness::Move
void Move(Graphics::point, InteractiveWitnessState< width, height > &ws)
Definition: Witness.h:2533
Witness::Serialize
std::ostream & Serialize(std::ostream &os) const
Definition: Witness.h:897
Witness::AddEraserConstraint
void AddEraserConstraint(int which)
Definition: Witness.h:629
Witness::RemoveCannotCrossConstraint
void RemoveCannotCrossConstraint(bool horiz, int x, int y)
Definition: Witness.h:2365
loc
Definition: MapGenerators.cpp:296
kNoPathConstraint
@ kNoPathConstraint
Definition: Witness.h:214
Witness::kNotValidAction
@ kNotValidAction
Definition: Witness.h:227
Witness::gapOffset
float gapOffset
Definition: Witness.h:1183
SearchEnvironment< WitnessState< width, height >, WitnessAction >::color
rgbColor color
Definition: SearchEnvironment.h:114
Colors::black
const rgbColor black
Definition: Colors.h:119
Witness::Draw
void Draw(Graphics::Display &display) const
Definition: Witness.h:2847
WitnessState::isAlongTheWall
bool isAlongTheWall() const
Definition: Witness.h:87
kNegativeTetris
@ kNegativeTetris
Definition: Witness.h:186
Witness::tetrisBits64
const uint64_t tetrisBits64[25]
Definition: Witness.h:735
Witness::GetCannotCrossConstraint
bool GetCannotCrossConstraint(int) const
Definition: Witness.h:2264
Witness::AddStart
void AddStart(int x, int y)
Definition: Witness.h:455
Witness::GetRegionFromY
int GetRegionFromY(int index) const
Definition: Witness.h:1218
InteractiveWitnessState::Reset
void Reset()
Definition: Witness.h:152
Graphics::Display
Definition: Graphics.h:146
kSeparation
@ kSeparation
Definition: Witness.h:183
kRegionConstraintCount
@ kRegionConstraintCount
Definition: Witness.h:189
Witness::Deserialize
std::istream & Deserialize(std::istream &is)
Definition: Witness.h:902
Witness::operator=
Witness< width, height > & operator=(const Witness< width, height > &w)
Definition: Witness.h:303
Witness::GetDimensionsFromHashString
void GetDimensionsFromHashString(const std::string &s, int &w, int &h) const
Definition: Witness.h:1071
Witness::HCost
double HCost(const WitnessState< width, height > &node1, const WitnessState< width, height > &node2) const
Heuristic value between two arbitrary nodes.
Definition: Witness.h:1715
Witness::tetrisBits
const uint16_t tetrisBits[25]
Definition: Witness.h:732
WitnessRegionConstraint::t
WitnessRegionConstraintType t
Definition: Witness.h:193
Witness::AddGoal
bool AddGoal(int x, int y)
Definition: Witness.h:464
Witness::UndoAction
void UndoAction(WitnessState< width, height > &s, WitnessAction a) const
Definition: Witness.h:1524
InteractiveWitnessState::kWaitingStart
@ kWaitingStart
Definition: Witness.h:173
Witness::SaveToHashString
std::string SaveToHashString() const
Definition: Witness.h:1023
WitnessRegionConstraint::operator!=
bool operator!=(const WitnessRegionConstraint &a) const
Definition: Witness.h:201
Witness::separationObject::color
rgbColor color
Definition: Witness.h:261
Witness::AddRegionConstraint
void AddRegionConstraint(int which, const WitnessRegionConstraint &constraint)
Definition: Witness.h:823
Witness::Witness
Witness(const Witness< width, height > &w)
Definition: Witness.h:288
Witness::GetStateFromHash
void GetStateFromHash(uint64_t parent, WitnessState< width, height > &s) const
Definition: Witness.h:2069
Witness::ClearTetrisConstraints
void ClearTetrisConstraints()
Definition: Witness.h:692
height
int height
Definition: SFML_HOG.cpp:54
Witness::GetRegionConstraint
const WitnessRegionConstraint & GetRegionConstraint(int x, int y) const
Definition: Witness.h:444
WitnessState::path
std::vector< std::pair< int, int > > path
Definition: Witness.h:44
kStar
@ kStar
Definition: Witness.h:184
Witness::ClearEraserConstraints
void ClearEraserConstraints()
Definition: Witness.h:615
kPathConstraintCount
@ kPathConstraintCount
Definition: Witness.h:217
Graphics::Display::FrameCircle
void FrameCircle(rect r, rgbColor c, float lineWidth)
Definition: Graphics.cpp:110
Witness::PathLocation
Definition: Witness.h:1190
InteractiveWitnessState::kWaitingRestart
@ kWaitingRestart
Definition: Witness.h:176
WitnessAction
WitnessAction
Definition: Witness.h:134
Witness::AddStarConstraint
void AddStarConstraint(int x, int y, rgbColor c)
Definition: Witness.h:778
Witness::GetPathIndex
int GetPathIndex(int x, int y) const
Definition: Witness.h:1188
max
#define max(a, b)
Definition: MinimalSectorAbstraction.cpp:40
Witness::OpenGLDraw
void OpenGLDraw() const
Definition: Witness.h:418
kDown
@ kDown
Definition: Witness.h:136
vectorCache< int >
InteractiveWitnessState
Definition: Witness.h:150
Witness::regionCache
vectorCache< int > regionCache
Definition: Witness.h:1229
WitnessState::OccupiedEdge
bool OccupiedEdge(int x1, int y1, int x2, int y2) const
Definition: Witness.h:115
Witness::GetNumTriangleConstraints
static constexpr int GetNumTriangleConstraints()
Definition: Witness.h:560
WitnessState::Unoccupy
void Unoccupy(int x, int y)
Definition: Witness.h:110
Witness::AddTriangleConstraint
void AddTriangleConstraint(int which, int count)
Definition: Witness.h:584
WitnessState::Occupy
void Occupy(int x, int y)
Definition: Witness.h:108
Witness::legality
legality
Definition: Witness.h:223
Witness::mustCrossEdgeConstraint::location
std::pair< int, int > location
Definition: Witness.h:236
Witness::mustCrossEdgeConstraint
Definition: Witness.h:234
Witness
Definition: Witness.h:221
Witness::ClearStarConstraints
void ClearStarConstraints()
Definition: Witness.h:774
Witness::ClearSeparationConstraints
void ClearSeparationConstraints()
Definition: Witness.h:591
Witness::regionConstraintLocations
std::array< std::pair< Graphics::point, Graphics::rect >, width *height > regionConstraintLocations
Definition: Witness.h:277
Witness::GetPathLocation
PathLocation GetPathLocation(int index) const
Definition: Witness.h:1197
Witness::PathLocation::y
int y
Definition: Witness.h:1194
Witness::ClearInnerConstraints
void ClearInnerConstraints()
Definition: Witness.h:522
Witness::PathLocation::t
unsigned t
Definition: Witness.h:1192
Witness::GetRegionFromX
int GetRegionFromX(int index) const
Definition: Witness.h:1216
Witness::goal
std::vector< std::pair< int, int > > goal
Definition: Witness.h:829
Graphics::point::x
float x
Definition: Graphics.h:36
Witness::GetNumStarConstraints
static constexpr int GetNumStarConstraints()
Definition: Witness.h:776
Witness::AddMustCrossConstraint
void AddMustCrossConstraint(bool horiz, int x, int y)
Definition: Witness.h:2153
Witness::ClearPathConstraints
void ClearPathConstraints()
Definition: Witness.h:484
Witness::outerBackColor
const rgbColor outerBackColor
Definition: Witness.h:1179
Colors::orange
const rgbColor orange
Definition: Colors.h:155
Graphics::Display::FillCircle
void FillCircle(rect r, rgbColor c)
Definition: Graphics.cpp:128
Witness::DrawRegionConstraint
void DrawRegionConstraint(Graphics::Display &display, const WitnessRegionConstraint &constraint, const Graphics::point &p3) const
Definition: Witness.h:2681
Witness::regions
std::array< int, width *height > regions
Definition: Witness.h:1224
WitnessRegionConstraint
Definition: Witness.h:192
Witness::triangleColor
const rgbColor triangleColor
Definition: Witness.h:1180
operator>>
std::istream & operator>>(std::istream &is, Witness< width, height > &witness)
Definition: Witness.h:3146
WitnessState::Occupied
bool Occupied(int which)
Definition: Witness.h:64
Witness::GetNumCannotCrossConstraints
constexpr int GetNumCannotCrossConstraints() const
Definition: Witness.h:2232
Witness::GCost
double GCost(const WitnessState< width, height > &node1, const WitnessState< width, height > &node2) const
Definition: Witness.h:1722
Witness::DebugPrint
void DebugPrint(uint64_t val, int offset=0) const
Definition: Witness.h:1300
Witness::start
std::vector< std::pair< int, int > > start
Definition: Witness.h:828
WitnessRegionConstraint::c
rgbColor c
Definition: Witness.h:195
Witness::AddNegativeTetrisConstraint
void AddNegativeTetrisConstraint(int x, int y, int which)
Definition: Witness.h:699
kTriangle
@ kTriangle
Definition: Witness.h:187
Witness::GoalTest
bool GoalTest(const WitnessState< width, height > &node, const WitnessState< width, height > &goal) const
Definition: Witness.h:1735
Witness::LabelRegions
void LabelRegions(const WitnessState< width, height > &s) const
Definition: Witness.h:2385
Colors::white
const rgbColor white
Definition: Colors.h:120
operator<<
std::ostream & operator<<(std::ostream &os, const Witness< width, height > &witness)
Definition: Witness.h:3140
Witness::tetrisBlue
const rgbColor tetrisBlue
Definition: Witness.h:1175
Witness::ClearCannotCrossConstraint
void ClearCannotCrossConstraint(int)
Definition: Witness.h:2300
Witness::tetrisSize
const uint16_t tetrisSize[25]
Definition: Witness.h:747
Witness::scale
float scale
Definition: Witness.h:1182
kRight
@ kRight
Definition: Witness.h:138
Witness::kNotAtStart
@ kNotAtStart
Definition: Witness.h:226
WitnessState::UnoccupyEdge
void UnoccupyEdge(int x1, int y1, int x2, int y2)
Definition: Witness.h:122
Witness::drawColor
const rgbColor drawColor
Definition: Witness.h:1176
Witness::tetrisYellow
const rgbColor tetrisYellow
Definition: Witness.h:1174
rgbColor::hex
std::string hex() const
Definition: Colors.h:52
InteractiveWitnessState::targetAct
WitnessAction targetAct
Definition: Witness.h:170
Witness::yGap
float yGap
Definition: Witness.h:1186
path
A linked list of nodes which form a continuous path.
Definition: Path.h:20
Witness::AddStarConstraint
void AddStarConstraint(int which, rgbColor c)
Definition: Witness.h:791
kTetris
@ kTetris
Definition: Witness.h:185
Witness::RecursivelyPlacePieces
bool RecursivelyPlacePieces(int curr, uint64_t board, uint64_t oob, uint64_t posFootprint, uint64_t negFootprint) const
Definition: Witness.h:2014
WitnessPathConstraintType
WitnessPathConstraintType
Definition: Witness.h:213
WitnessState::hitTheWall
bool hitTheWall() const
Definition: Witness.h:97
Colors::lightgray
const rgbColor lightgray
Definition: Colors.h:125
Witness::OpenGLDraw
void OpenGLDraw(const WitnessState< width, height > &) const
Definition: Witness.h:420
Witness::tetrisBlockCount
std::vector< int > tetrisBlockCount
Definition: Witness.h:1231
Witness::SetCannotCrossConstraint
void SetCannotCrossConstraint(int)
Definition: Witness.h:2238
Witness::lineWidth
float lineWidth
Definition: Witness.h:1184
GetEdgeHash
int GetEdgeHash(bool horizontal, int x, int y)
Definition: Witness.h:26
Witness::GetNumSeparationConstraints
static constexpr int GetNumSeparationConstraints()
Definition: Witness.h:594
Graphics::Display::FillRect
void FillRect(rect r, rgbColor c)
Definition: Graphics.cpp:101
Witness::lineColor
const rgbColor lineColor
Definition: Witness.h:1177
Witness::separationObject::valid
bool valid
Definition: Witness.h:260
Witness::mustCrossEdgeConstraint::horiz
bool horiz
Definition: Witness.h:235
Witness::AddSeparationConstraint
void AddSeparationConstraint(int which, rgbColor c)
Definition: Witness.h:606
Witness::AddTetrisConstraint
void AddTetrisConstraint(int x, int y, int which)
Definition: Witness.h:709
InteractiveWitnessState::frac
float frac
Definition: Witness.h:168
WitnessState::occupiedCorners
std::bitset<(width+1) *(height+1)> occupiedCorners
Definition: Witness.h:45
Witness::GLLabelState
void GLLabelState(const WitnessState< width, height > &, const char *) const
Definition: Witness.h:427
SearchEnvironment
Definition: SearchEnvironment.h:30
Witness::kLegal
@ kLegal
Definition: Witness.h:224
Witness::OpenGLDraw
void OpenGLDraw(const WitnessState< width, height > &, const WitnessAction &) const
Definition: Witness.h:425
Witness::SetStart
void SetStart(int x, int y)
Definition: Witness.h:449
node
Nodes to be stored within a Graph.
Definition: Graph.h:170
SearchEnvironment.h
kNoRegionConstraint
@ kNoRegionConstraint
Definition: Witness.h:182
Witness::AddNegativeTetrisConstraint
void AddNegativeTetrisConstraint(int loc, int which)
Definition: Witness.h:719
Witness::GetScreenCoord
Graphics::point GetScreenCoord(int x, int y) const
Definition: Witness.h:1256
kLeft
@ kLeft
Definition: Witness.h:137
InteractiveWitnessState::currState
controlState currState
Definition: Witness.h:178