#include "Panel.h" #include #include #include "Serializer.h" template int find(const std::vector& data, T search, size_t startIndex = 0) { for (size_t i = startIndex; i < data.size(); i++) { if (data[i] == search) return static_cast(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(IntersectionFlags::DOT_IS_BLUE); else if (color == Decoration::Color::Orange || color == Decoration::Color::Yellow) color = static_cast(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(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); char settings = Serializer::NegationsCancelNegations | Serializer::PrecisePolyominos | Serializer::FlashForErrors; if (_invisible_symmetry) { settings |= Serializer::InvisibleSymmetry; } serializer.writeByte(settings); return serializer.str(); }