#include "Panel.h"
#include <fstream>
#include <sstream>
#include "Serializer.h"
template <class T>
int find(const std::vector<T>& data, T search, size_t startIndex = 0) {
for (size_t i = startIndex; i < data.size(); i++) {
if (data[i] == search) return static_cast<int>(i);
}
return -1;
}
void Panel::SetSymbol(int x, int y, Decoration::Shape symbol,
Decoration::Color color) {
int gridx = x * 2 + (symbol & IntersectionFlags::COLUMN ? 0 : 1);
int gridy = y * 2 + (symbol & IntersectionFlags::ROW ? 0 : 1);
if (symbol & IntersectionFlags::DOT) {
if (color == Decoration::Color::Blue || color == Decoration::Color::Cyan)
color = static_cast<Decoration::Color>(IntersectionFlags::DOT_IS_BLUE);
else if (color == Decoration::Color::Orange ||
color == Decoration::Color::Yellow)
color = static_cast<Decoration::Color>(IntersectionFlags::DOT_IS_ORANGE);
else
color = Decoration::Color::None;
if (symmetry) {
Point sp = get_sym_point(gridx, gridy);
SetGridSymbol(sp.first, sp.second,
static_cast<Decoration::Shape>(symbol & ~Decoration::Dot),
Decoration::Color::None);
}
} else if (symbol & IntersectionFlags::ROW ||
symbol & IntersectionFlags::COLUMN)
color = Decoration::Color::None;
SetGridSymbol(gridx, gridy, symbol, color);
}
void Panel::SetShape(int x, int y, int shape, bool rotate, bool negative,
Decoration::Color color) {
if (!shape) return;
int symbol = Decoration::Shape::Poly;
while (!(shape & 0xf)) shape >>= 4;
while (!(shape & 0x1111)) shape >>= 1;
shape <<= 16;
if (rotate)
shape |= Decoration::Shape::Can_Rotate;
else
shape &= ~Decoration::Shape::Can_Rotate;
if (negative)
shape |= Decoration::Shape::Negative;
else
shape &= ~Decoration::Shape::Negative;
_grid[x * 2 + 1][y * 2 + 1] = symbol | shape | color;
}
void Panel::ClearSymbol(int x, int y) { ClearGridSymbol(x * 2 + 1, y * 2 + 1); }
void Panel::SetGridSymbol(int x, int y, Decoration::Shape symbol,
Decoration::Color color) {
if (symbol == Decoration::Start) _startpoints.push_back({x, y});
if (symbol == Decoration::Exit) {
Endpoint::Direction dir;
if (y == 0)
dir = Endpoint::Direction::UP;
else if (y == _height - 1)
dir = Endpoint::Direction::DOWN;
else if (x == 0)
dir = Endpoint::Direction::LEFT;
else
dir = Endpoint::Direction::RIGHT;
/*if (id == 0x033D4 || id == 0x0A3B5) {
if (x == 0)
dir = Endpoint::Direction::LEFT;
else
dir = Endpoint::Direction::RIGHT;
}*/
if (symmetry == Symmetry::ParallelH ||
symmetry == Symmetry::ParallelHFlip) {
if (x == 0) dir = Endpoint::Direction::LEFT;
if (x == _width - 1) dir = Endpoint::Direction::RIGHT;
}
_endpoints.emplace_back(Endpoint(
x, y, dir,
IntersectionFlags::ENDPOINT |
(dir == Endpoint::Direction::UP || dir == Endpoint::Direction::DOWN
? IntersectionFlags::COLUMN
: IntersectionFlags::ROW)));
} else
_grid[x][y] = symbol | color;
}
void Panel::ClearGridSymbol(int x, int y) { _grid[x][y] = 0; }
void Panel::Resize(int width, int height) {
for (Point& s : _startpoints) {
if (s.first == _width - 1) s.first = width - 1;
if (s.second == _height - 1) s.second = height - 1;
}
for (Endpoint& e : _endpoints) {
if (e.GetX() == _width - 1) e.SetX(width - 1);
if (e.GetY() == _height - 1) e.SetY(height - 1);
}
if (_width != _height || width != height) {
float maxDim = std::max(maxx - minx, maxy - miny);
float unitSize = maxDim / std::max(width - 1, height - 1);
minx = 0.5f - unitSize * (width - 1) / 2;
maxx = 0.5f + unitSize * (width - 1) / 2;
miny = 0.5f - unitSize * (height - 1) / 2;
maxy = 0.5f + unitSize * (height - 1) / 2;
}
_width = width;
_height = height;
_grid.resize(width);
for (auto& row : _grid) row.resize(height);
_resized = true;
}
std::string Panel::Write() {
Serializer serializer;
serializer.writeInt(SERIALIZER_VERSION);
serializer.writeByte(_width);
serializer.writeByte(_height);
serializer.writeString("Generated");
int genericFlags = 0;
if (symmetry != Symmetry::None) {
genericFlags |= Serializer::Symmetrical;
if (symmetry == Symmetry::Vertical || symmetry == Symmetry::Rotational) {
genericFlags |= Serializer::SymmetryX;
}
if (symmetry == Symmetry::Horizontal || symmetry == Symmetry::Rotational) {
genericFlags |= Serializer::SymmetryY;
}
}
serializer.writeByte(genericFlags);
for (int x = 0; x < _width; x++) {
for (int y = 0; y < _height; y++) {
int val = _grid[x][y];
if (x % 2 == 1 && y % 2 == 1) {
// This is a grid cell.
int symbol = val & 0xF00;
if (symbol == Decoration::Triangle) {
serializer.writeByte(Serializer::Triangle);
serializer.writeColor(val & 0xF);
serializer.writeByte((val & 0xF0000) >> 16);
} else if (symbol == Decoration::Star) {
serializer.writeByte(Serializer::Star);
serializer.writeColor(val & 0xF);
} else if (symbol == Decoration::Stone) {
serializer.writeByte(Serializer::Square);
serializer.writeColor(val & 0xF);
} else if (symbol == Decoration::Eraser) {
serializer.writeByte(Serializer::Nega);
serializer.writeColor(val & 0xF);
} else if (symbol == Decoration::Poly) {
if (val & Decoration::Negative) {
serializer.writeByte(Serializer::Ylop);
} else {
serializer.writeByte(Serializer::Poly);
}
serializer.writeColor(val & 0xF);
long polyshape = (val & 0xFFFF0000) >> 16;
if (val & Decoration::Can_Rotate) {
polyshape |= (1 << 20);
}
serializer.writeLong(polyshape);
} else {
serializer.writeByte(Serializer::Nonce);
}
} else {
serializer.writeByte(Serializer::Line);
// line, dot, gap
serializer.writeByte(Serializer::LineNone);
if (val & Decoration::Dot) {
if (val & IntersectionFlags::DOT_IS_BLUE) {
serializer.writeByte(Serializer::DotBlue);
} else if (val & IntersectionFlags::DOT_IS_ORANGE) {
serializer.writeByte(Serializer::DotYellow);
} else if (val & IntersectionFlags::DOT_IS_INVISIBLE) {
serializer.writeByte(Serializer::DotInvisible);
} else {
serializer.writeByte(Serializer::DotBlack);
}
} else {
serializer.writeByte(Serializer::DotNone);
}
if (val == OPEN) {
serializer.writeByte(Serializer::GapFull);
} else if (val & Decoration::Gap) {
serializer.writeByte(Serializer::GapBreak);
} else {
serializer.writeByte(Serializer::GapNone);
}
}
char startEnd = 0;
for (const Point& pos : _startpoints) {
if (pos.first == x && pos.second == y) {
startEnd |= Serializer::Start;
}
}
for (const Endpoint& endpoint : _endpoints) {
if (endpoint.GetX() == x && endpoint.GetY() == y) {
if (endpoint.GetDir() & Endpoint::LEFT) {
startEnd |= Serializer::EndLeft;
}
if (endpoint.GetDir() & Endpoint::RIGHT) {
startEnd |= Serializer::EndRight;
}
if (endpoint.GetDir() & Endpoint::UP) {
startEnd |= Serializer::EndTop;
}
if (endpoint.GetDir() & Endpoint::DOWN) {
startEnd |= Serializer::EndBottom;
}
}
}
serializer.writeByte(startEnd);
}
}
serializer.writeInt(0);
serializer.writeByte(Serializer::NegationsCancelNegations |
Serializer::PrecisePolyominos |
Serializer::FlashForErrors);
return serializer.str();
}