#ifndef PANEL_H_FC471D68
#define PANEL_H_FC471D68
#include <stdint.h>
#include <tuple>
#include <vector>
struct Point {
int first;
int second;
Point() {
first = 0;
second = 0;
};
Point(int x, int y) {
first = x;
second = y;
}
Point operator+(const Point& p) {
return {first + p.first, second + p.second};
}
Point operator*(int d) { return {first * d, second * d}; }
Point operator/(int d) { return {first / d, second / d}; }
bool operator==(const Point& p) const {
return first == p.first && second == p.second;
};
bool operator!=(const Point& p) const {
return first != p.first || second != p.second;
};
friend bool operator<(const Point& p1, const Point& p2) {
if (p1.first == p2.first) return p1.second < p2.second;
return p1.first < p2.first;
};
};
class Decoration {
public:
enum Shape : int {
Exit = 0x600001,
Start = 0x600002,
Stone = 0x100,
Star = 0x200,
Poly = 0x400,
Eraser = 0x500,
Triangle = 0x600,
Triangle1 = 0x10600,
Triangle2 = 0x20600,
Triangle3 = 0x30600,
Triangle4 = 0x40600,
Arrow = 0x700,
Arrow1 = 0x1700,
Arrow2 = 0x2700,
Arrow3 = 0x3700,
Can_Rotate = 0x1000,
Negative = 0x2000,
Gap = 0x100000,
Gap_Row = 0x300000,
Gap_Column = 0x500000,
Dot = 0x20,
Dot_Row = 0x240020,
Dot_Column = 0x440020,
Dot_Intersection = 0x600020,
Empty = 0xA00,
};
enum Color : int {
None = 0,
Black = 0x1,
White = 0x2,
Red = 0x3, // Doesn't work sadly
Purple = 0x4,
Green = 0x5,
Cyan = 0x6,
Magenta = 0x7,
Yellow = 0x8,
Blue = 0x9,
Orange = 0xA,
X = 0xF,
};
};
enum IntersectionFlags : int {
ROW = 0x200000,
COLUMN = 0x400000,
INTERSECTION = 0x600000,
ENDPOINT = 0x1,
STARTPOINT = 0x2,
OPEN = 0x3, // Puzzle loader flag - not to be written out
PATH = 0x4, // Generator use only
NO_POINT = 0x8, // Points that nothing connects to
GAP = 0x100000,
DOT = 0x20,
DOT_IS_BLUE = 0x100,
DOT_IS_ORANGE = 0x200,
DOT_IS_INVISIBLE = 0x1000,
DOT_SMALL = 0x2000,
DOT_MEDIUM = 0x4000,
DOT_LARGE = 0x8000,
};
class Endpoint {
public:
enum Direction {
NONE = 0,
LEFT = 1,
RIGHT = 2,
UP = 4,
DOWN = 8,
UP_LEFT = 5,
UP_RIGHT = 6,
DOWN_LEFT = 9,
DOWN_RIGHT = 10
};
Endpoint(int x, int y, Direction dir, int flags) {
_x = x;
_y = y;
_dir = dir;
_flags = flags;
}
int GetX() const { return _x; }
void SetX(int x) { _x = x; }
int GetY() const { return _y; }
void SetY(int y) { _y = y; }
Direction GetDir() const { return _dir; }
int GetFlags() const { return _flags; }
void SetDir(Direction dir) { _dir = dir; }
private:
int _x, _y, _flags;
Direction _dir;
};
struct Color {
float r;
float g;
float b;
float a;
friend bool operator<(const Color& lhs, const Color& rhs) {
return lhs.r * 8 + lhs.g * 4 + lhs.b * 2 + lhs.a >
rhs.r * 8 + rhs.g * 4 + rhs.b * 2 + rhs.a;
}
};
struct SolutionPoint {
int pointA, pointB, pointC, pointD;
float f1x, f1y, f2x, f2y, f3x, f3y, f4x, f4y;
int endnum;
};
class Panel {
public:
void SetSymbol(int x, int y, Decoration::Shape symbol,
Decoration::Color color);
void SetShape(int x, int y, int shape, bool rotate, bool negative,
Decoration::Color color);
void ClearSymbol(int x, int y);
void SetGridSymbol(int x, int y, Decoration::Shape symbol,
Decoration::Color color = Decoration::Color::None);
void ClearGridSymbol(int x, int y);
void Resize(int width, int height);
void ClearStartpoints() { _startpoints.clear(); }
void ClearExits() { _endpoints.clear(); }
int width() const { return _width; }
int height() const { return _height; }
int get(int x, int y) { return _grid[x][y]; }
void set(int x, int y, int val) { _grid[x][y] = val; }
void SetInvisibleSymmetry(bool val) { _invisible_symmetry = val; }
std::string Write();
enum Style {
SYMMETRICAL = 0x2, // Not on the town symmetry puzzles? IDK why.
NO_BLINK = 0x4,
HAS_DOTS = 0x8,
IS_2COLOR = 0x10,
HAS_STARS = 0x40,
HAS_TRIANGLES = 0x80,
HAS_STONES = 0x100,
HAS_ERASERS = 0x1000,
HAS_SHAPERS = 0x2000,
IS_PIVOTABLE = 0x8000,
};
enum Symmetry { // NOTE - Not all of these are valid symmetries for certain
// puzzles
None = 0,
Horizontal = 1,
Vertical = 2,
Rotational = 3,
RotateLeft = 4,
RotateRight = 5,
FlipXY = 6,
FlipNegXY = 7,
ParallelH = 8,
ParallelV = 9,
ParallelHFlip = 10,
ParallelVFlip = 11,
PillarParallel = 12,
PillarHorizontal = 13,
PillarVertical = 14,
PillarRotational = 15,
};
Symmetry symmetry;
float pathWidth;
enum ColorMode {
Default,
Reset,
Alternate,
WriteColors,
Treehouse,
TreehouseAlternate
};
ColorMode colorMode;
bool decorationsOnly;
bool enableFlash;
Point get_sym_point(int x, int y, Symmetry symmetry) {
switch (symmetry) {
case None:
return Point(x, y);
case Symmetry::Horizontal:
return Point(x, _height - 1 - y);
case Symmetry::Vertical:
return Point(_width - 1 - x, y);
case Symmetry::Rotational:
return Point(_width - 1 - x, _height - 1 - y);
case Symmetry::RotateLeft:
return Point(y, _width - 1 - x);
case Symmetry::RotateRight:
return Point(_height - 1 - y, x);
case Symmetry::FlipXY:
return Point(y, x);
case Symmetry::FlipNegXY:
return Point(_height - 1 - y, _width - 1 - x);
case Symmetry::ParallelH:
return Point(x, y == _height / 2
? _height / 2
: (y + (_height + 1) / 2) % (_height + 1));
case Symmetry::ParallelV:
return Point(x == _width / 2 ? _width / 2
: (x + (_width + 1) / 2) % (_width + 1),
y);
case Symmetry::ParallelHFlip:
return Point(_width - 1 - x,
y == _height / 2
? _height / 2
: (y + (_height + 1) / 2) % (_height + 1));
case Symmetry::ParallelVFlip:
return Point(x == _width / 2 ? _width / 2
: (x + (_width + 1) / 2) % (_width + 1),
_height - 1 - y);
case Symmetry::PillarParallel:
return Point(x + _width / 2, y);
case Symmetry::PillarHorizontal:
return Point(x + _width / 2, _height - 1 - y);
case Symmetry::PillarVertical:
return Point(_width / 2 - x, y);
case Symmetry::PillarRotational:
return Point(_width / 2 - x, _height - 1 - y);
}
return Point(x, y);
}
Point get_sym_point(int x, int y) { return get_sym_point(x, y, symmetry); }
Point get_sym_point(Point p) {
return get_sym_point(p.first, p.second, symmetry);
}
Point get_sym_point(Point p, Symmetry symmetry) {
return get_sym_point(p.first, p.second, symmetry);
}
Endpoint::Direction get_sym_dir(Endpoint::Direction direction,
Symmetry symmetry) {
int dirIndex;
if (direction == Endpoint::Direction::LEFT) dirIndex = 0;
if (direction == Endpoint::Direction::RIGHT) dirIndex = 1;
if (direction == Endpoint::Direction::UP) dirIndex = 2;
if (direction == Endpoint::Direction::DOWN) dirIndex = 3;
std::vector<Endpoint::Direction> mapping;
switch (symmetry) {
case Symmetry::Horizontal:
mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
Endpoint::Direction::DOWN, Endpoint::Direction::UP};
break;
case Symmetry::Vertical:
mapping = {Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT,
Endpoint::Direction::UP, Endpoint::Direction::DOWN};
break;
case Symmetry::Rotational:
mapping = {Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT,
Endpoint::Direction::DOWN, Endpoint::Direction::UP};
break;
case Symmetry::RotateLeft:
mapping = {Endpoint::Direction::DOWN, Endpoint::Direction::UP,
Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT};
break;
case Symmetry::RotateRight:
mapping = {Endpoint::Direction::UP, Endpoint::Direction::DOWN,
Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT};
break;
case Symmetry::FlipXY:
mapping = {Endpoint::Direction::UP, Endpoint::Direction::DOWN,
Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT};
break;
case Symmetry::FlipNegXY:
mapping = {Endpoint::Direction::DOWN, Endpoint::Direction::UP,
Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT};
break;
case Symmetry::ParallelH:
mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
Endpoint::Direction::UP, Endpoint::Direction::DOWN};
break;
case Symmetry::ParallelV:
mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
Endpoint::Direction::UP, Endpoint::Direction::DOWN};
break;
case Symmetry::ParallelHFlip:
mapping = {Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT,
Endpoint::Direction::UP, Endpoint::Direction::DOWN};
break;
case Symmetry::ParallelVFlip:
mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
Endpoint::Direction::DOWN, Endpoint::Direction::UP};
break;
default:
mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
Endpoint::Direction::UP, Endpoint::Direction::DOWN};
break;
}
return mapping[dirIndex];
}
int get_num_grid_points() { return ((_width + 1) / 2) * ((_height + 1) / 2); }
int get_num_grid_blocks() { return (_width / 2) * (_height / 2); }
int get_parity() { return (get_num_grid_points() + 1) % 2; }
private:
int _width, _height;
std::vector<std::vector<int>> _grid;
std::vector<Point> _startpoints;
std::vector<Endpoint> _endpoints;
float minx, miny, maxx, maxy, unitWidth, unitHeight;
int _style;
bool _resized;
bool _invisible_symmetry = false;
};
#endif /* end of include guard: PANEL_H_FC471D68 */