build/ generated/ .vscode/ apworld/generated/ __pycache__ .vs/ ^out/ client/Archipelago/generated/ css'/>
about summary refs log blame commit diff stats
path: root/ext/wittle_generator/Panel.cpp
blob: 892d4cc211a721fb98d1dce915984b0769fc774c (plain) (tree)
1
2
3
4
5
6
7




                  

                       














































































































                                                                                










                                            
                                                                             

                                            
                                                                               

























                                                      



                                                   
           
                                           





                                                    



















                                                                 


                                                    






































                                                             
#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();
}