about summary refs log tree commit diff stats
path: root/ext/wittle_generator/Generate.h
blob: 9969998a54d3e7ca386c6f2c28bc5cbf2eca1055 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#ifndef GENERATE_H_0582FCEA
#define GENERATE_H_0582FCEA

#include <stdlib.h>
#include <time.h>

#include <algorithm>
#include <memory>
#include <set>
#include <string>

#include "Panel.h"
#include "PuzzleSymbols.h"
#include "Random.h"

typedef std::set<Point> Shape;

// The main class for generating puzzles.
class Generate {
 public:
  Generate() {
    _width = _height = 0;
    _areaTotal = _genTotal = _totalPuzzles = _areaPuzzles = _stoneTypes = 0;
    _fullGaps = _bisect = _allowNonMatch = false;
    _panel = NULL;
    _parity = -1;
    colorblind = false;
    _seed = Random::rand();
    arrowColor = backgroundColor = successColor = {0, 0, 0, 0};
    resetConfig();
  }
  enum Config {  // See configinfo.txt for explanations of config flags.
    None = 0,
    FullGaps = 0x1,
    StartEdgeOnly = 0x2,
    DisableWrite = 0x4,
    PreserveStructure = 0x8,
    MakeStonesUnsolvable = 0x10,
    SmallShapes = 0x20,
    DisconnectShapes = 0x40,
    ResetColors = 0x80,
    DisableCancelShapes = 0x100,
    RequireCancelShapes = 0x200,
    BigShapes = 0x400,
    SplitShapes = 0x800,
    RequireCombineShapes = 0x1000,
    TreehouseLayout = 0x2000,
    TreehouseColors = 0x4000,
    AlternateColors = 0x8000,
    WriteColors = 0x10000,
    RegularStartEnd = 0x20000,
    FixBackground = 0x40000,
    CombineErasers = 0x80000,
    LongPath = 0x100000,
    ShortPath = 0x200000,
    EnableFlash = 0x400000,
    DecorationsOnly = 0x800000,
    FalseParity = 0x1000000,
    DisableDotIntersection = 0x2000000,
    WriteDotColor = 0x4000000,
    WriteDotColor2 = 0x8000000,
    LongestPath = 0x10000000,
    WriteInvisible = 0x20000000,
    DisableReset = 0x40000000,
    MountainFloorH = 0x80000000
  };

  void generate(int width, int height, PuzzleSymbols symbols);

  /*void generateMaze(int id);
  void generateMaze(int id, int numStarts, int numExits);*/
  void initPanel();
  void setPath(const std::set<Point>& path) {
    customPath = path;
    for (Point p : path) setSymbol(IntersectionFlags::PATH, p.first, p.second);
  }
  void setObstructions(const std::vector<Point>& walls) {
    _obstructions = {walls};
  }
  void setObstructions(const std::vector<std::vector<Point>>& walls) {
    _obstructions = walls;
  }
  void setSymbol(Decoration::Shape symbol, int x, int y);
  void setSymbol(IntersectionFlags symbol, int x, int y) {
    setSymbol(static_cast<Decoration::Shape>(symbol), x, y);
  }
  void setGridSize(int width, int height);
  void setSymmetry(Panel::Symmetry symmetry);
  std::string AsCode();
  void write(int id);
  void setFlag(Config option) { _config |= option; };
  void setFlagOnce(Config option) {
    _config |= option;
    _oneTimeAdd |= option;
  };
  bool hasFlag(Config option) { return _config & option; };
  void removeFlag(Config option) { _config &= ~option; };
  void removeFlagOnce(Config option) {
    _config &= ~option;
    _oneTimeRemove |= option;
  };
  void resetConfig();
  void seed(long seed) {
    Random::seed(seed);
    _seed = Random::rand();
  }

  float pathWidth;               // Controls how thick the line is on the puzzle
  std::vector<Point> hitPoints;  // The generated path will be forced to hit
                                 // these points in order
  std::set<Point>
      openPos;  // Custom set of points that can have symbols placed on
  std::set<Point> blockPos;  // Point that must be left open
  std::set<Point> customPath;
  Color arrowColor, backgroundColor, successColor;  // For the arrow puzzles

  bool place_gaps(int amount);

 private:
  int get_symbol_type(int flags) { return flags & 0x700; }
  void set_path(Point pos);
  Point get_sym_point(Point pos) { return _panel->get_sym_point(pos); }
  int get_parity(Point pos) { return (pos.first / 2 + pos.second / 2) % 2; }
  void clear();
  void resetVars();
  void init_treehouse_layout();
  template <class T>
  T pick_random(const std::vector<T>& vec) {
    return vec[Random::rand() % vec.size()];
  }
  template <class T>
  T pick_random(const std::set<T>& set) {
    auto it = set.begin();
    std::advance(it, Random::rand() % set.size());
    return *it;
  }
  template <class T>
  T pop_random(const std::vector<T>& vec) {
    int i = Random::rand() % vec.size();
    T item = vec[i];
    vec.erase(vec.begin() + i);
    return item;
  }
  template <class T>
  T pop_random(const std::set<T>& set) {
    T item = pick_random(set);
    set.erase(item);
    return item;
  }
  bool on_edge(Point p) {
    return (p.first == 0 || p.first + 1 == _panel->width() || p.second == 0 ||
            p.second + 1 == _panel->height());
  }
  bool off_edge(Point p) {
    return (p.first < 0 || p.first >= _panel->width() || p.second < 0 ||
            p.second >= _panel->height());
  }
  static std::vector<Point> _DIRECTIONS1, _8DIRECTIONS1, _DIRECTIONS2,
      _8DIRECTIONS2, _SHAPEDIRECTIONS, _DISCONNECT;
  // bool generate_maze(int id, int numStarts, int numExits);
  bool generateInternal(int width, int height, PuzzleSymbols symbols);
  bool place_all_symbols(PuzzleSymbols& symbols);
  bool generate_path(PuzzleSymbols& symbols);
  bool generate_path_length(int minLength, int maxLength);
  bool generate_path_length(int minLength) {
    return generate_path_length(minLength, 10000);
  };
  bool generate_path_regions(int minRegions);
  bool generate_longest_path();
  bool generate_special_path();
  void erase_path();
  Point adjust_point(Point pos);
  std::set<Point> get_region(Point pos);
  std::vector<int> get_symbols_in_region(Point pos);
  std::vector<int> get_symbols_in_region(const std::set<Point>& region);
  bool place_start(int amount);
  bool place_exit(int amount);
  bool can_place_gap(Point pos);

  bool can_place_dot(Point pos, bool intersectionOnly);
  bool place_dots(int amount, int color, bool intersectionOnly);
  bool can_place_stone(const std::set<Point>& region, int color);
  bool place_stones(int color, int amount);
  Shape generate_shape(std::set<Point>& region, std::set<Point>& bufferRegion,
                       Point pos, int maxSize);
  Shape generate_shape(std::set<Point>& region, Point pos, int maxSize) {
    std::set<Point> buffer;
    return generate_shape(region, buffer, pos, maxSize);
  }
  int make_shape_symbol(Shape shape, bool rotated, bool negative, int rotation,
                        int depth);
  int make_shape_symbol(const Shape& shape, bool rotated, bool negative) {
    return make_shape_symbol(shape, rotated, negative, -1, 0);
  }
  bool place_shapes(const std::vector<int>& colors,
                    const std::vector<int>& negativeColors, int amount,
                    int numRotated, int numNegative);
  int count_color(const std::set<Point>& region, int color);
  bool place_stars(int color, int amount);
  bool has_star(const std::set<Point>& region, int color);
  bool checkStarZigzag();
  bool place_triangles(int color, int amount, int targetCount);
  int count_sides(Point pos);
  bool place_arrows(int color, int amount, int targetCount);
  int count_crossings(Point pos, Point dir);
  bool place_erasers(const std::vector<int>& colors,
                     const std::vector<int>& eraseSymbols);
  bool combine_shapes(std::vector<Shape>& shapes);

  bool hasSymbolOrPath(const Point& pos) {
    return hasSymbolOrPath(pos.first, pos.second);
  }
  bool hasSymbolOrPath(int x, int y);

  std::unique_ptr<Panel> _panel;
  std::vector<std::vector<int>> _custom_grid;
  int _width, _height;
  Panel::Symmetry _symmetry;
  std::set<Point> _starts, _exits;
  std::set<Point> _gridpos, _openpos;
  std::set<Point> _path, _path1, _path2;
  bool _fullGaps, _bisect;
  int _stoneTypes;
  int _config;
  int _oneTimeAdd, _oneTimeRemove;
  long _seed;
  std::vector<Point> _splitPoints;
  bool _allowNonMatch;  // Used for multi-generator
  int _parity;
  std::vector<std::vector<Point>> _obstructions;
  bool colorblind;

  int _areaTotal, _genTotal, _areaPuzzles, _totalPuzzles;
  std::wstring _areaName;

  void set(int x, int y, int val) { _panel->set(x, y, val); }
  void set(const Point& pos, int val) {
    _panel->set(pos.first, pos.second, val);
  }

  int get(int x, int y) { return _panel->get(x, y); }
  int get(const Point& pos) { return _panel->get(pos.first, pos.second); }

  // std::vector<std::vector<int>> _panelData;
  //  std::vector<std::vector<bool>> _drawnPath;

  friend class PuzzleList;
  friend class Special;
};

#endif /* end of include guard: GENERATE_H_0582FCEA */