-
Notifications
You must be signed in to change notification settings - Fork 0
/
piece.hxx
227 lines (178 loc) · 7.58 KB
/
piece.hxx
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
// yass: Yet Another Soma Solver
// Copyright (C) 2021 Mark R. Rubin aka "thanks4opensource"
//
// This file is part of yass.
//
// The yass program is free software: you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// The yass program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// (LICENSE.txt) along with the yass program. If not, see
// <https://www.gnu.org/licenses/gpl.html>
#ifndef PIECE_H
#define PIECE_H
#include <limits>
#include <map>
#include <unordered_set>
#include <utility>
#include <vector>
#include "position.hxx"
#include "rotators.hxx"
#if SOMA_MATRIX_ROTATION + SOMA_LAMBDA_ROTATION != 1
#error #define one and only one of SOMA_MATRIX_ROTATION or SOMA_LAMBDA_ROTATION
#endif
namespace soma {
class Shape;
class Piece {
public:
// in addition to central cube
static const unsigned MAX_NUMBER_OF_CUBES = 3,
NUMBER_OF_PIECES = 7;
static const std::map<char, Piece*> PIECE_NAMES ;
// Used to set Shape::NUMBER_OF_CUBICLES.
// Architecturally belongs in Shape class, but shape.hxx includes
// piece.hxx and files can't circularly include each other.
// Needed here for _valid_orientations std::array template parameter.
static const unsigned NUMBER_OF_SHAPE_CUBICLES = 27;
static Piece corner,
pos ,
neg ,
zee ,
tee ,
ell ,
three ;
Piece(int number_of_cubes, // other than central cube
const Position &cube_0 , // non-central cube
const Position &cube_1 , // " - " "
const Position &cube_2 , // " - " "
const char name , // client code / user visible
const uint8_t code ); // internal use
// See _orientations and _valid_orientations member variables
void set_valid_orientations(const unsigned cubicle_ndx ,
const unsigned piece_number);
// full reset, for new Shape
void reset()
{
reset_position_orientation();
_pre_placed = false;
}
// partial reset when backtracking failed placement in solution tree
void reset_position_orientation()
{
_current_position = -1;
_current_orientation = 0 ;
}
// Initialize unique-considering-symmetries _orientations
// Can't be done in or called from constructor because
// #ifdef SOMA_LAMBDA_ROTATION version of Rotators::rotations
// needs pre-main static initialization as do static Piece instances
// and former may be done after latter
void generate_orientations();
// See _shape member variable
void register_shape(Shape *shape) {_shape = shape; }
// For user-facing Shape::write()
static char code2name(
const unsigned code)
{
return CODE_TO_NAME[code];
}
constexpr char name() const {return _name ; }
constexpr unsigned code() const {return _code ; }
constexpr unsigned size() const {return _number_of_cubes + 1; }
// See member variables
void pre_place()
{
_current_orientation = 0 ;
_pre_placed = true;
}
bool is_pre_placed () const {return _pre_placed ; }
bool is_placed () const { return _current_position >= 0; }
// Main solver algorithm
// Repeatedly calls Shape::place_piece() using own internal state
// _current_position and _current_orientation.
// If successful, piece has been placed in shape, and returns true.
// Otherwise uses place_next() until no more valid positions/orientations
// and returns false.
bool place(unsigned piece_number ,
bool check_orphans ,
bool check_duplicates);
#ifdef SOMA_STATISTICS
unsigned num_orientations () const { return _orientations.size() ; }
unsigned place_successes () const { return _place_successes ; }
unsigned place_failures () const { return _place_failures ; }
unsigned place_duplicates () const { return _place_duplicates ; }
unsigned place_orphans () const { return _place_orphans ; }
unsigned num_valid_orientations() const { return _total_valid_orients ; }
#endif
protected:
static const char CODE_TO_NAME[NUMBER_OF_PIECES + 1];
// +1 is for generate_orientation() with central cube
using Cubes = std::array<Position, MAX_NUMBER_OF_CUBES + 1>;
// See piece.cxx
bool place_next();
// Rotate piece
//
#ifdef SOMA_MATRIX_ROTATION
static inline void rotate(
Cubes &rotated_cubes ,
const Cubes &original_cubes ,
const int matrix[3][3] ,
const unsigned number_of_cubes)
{
for (unsigned ndx = 0; ndx < number_of_cubes; ndx++)
rotated_cubes[ndx] = original_cubes[ndx] * matrix;
}
#endif
#ifdef SOMA_LAMBDA_ROTATION
static void rotate(
Cubes &rotated_cubes ,
const Cubes &original_cubes ,
Position (*rotator)(const Position),
const unsigned number_of_cubes )
{
for (unsigned ndx = 0; ndx < number_of_cubes; ndx++)
rotated_cubes[ndx] = rotator(original_cubes[ndx]);
}
#endif
// Member variables
//
// Does not include central cube (center of rotations/orientations,
// and location in shape at _current_position
unsigned _number_of_cubes ; // besides central cube
Cubes _cubes ; // other than central cube
const char _name ; // user/client visible
const uint8_t _code ; // internal use
// Unique (non-rotated/mirrored symmetric) rotations
std::vector<Cubes> _orientations;
// Subset of _orientations, per-cubicle in shape (no need to
// repeatedly try other orientations during recursive tree solving
// if piece will not fit in shape regardless of other, previously
// placed pieces).
std::array<std::vector<unsigned>, NUMBER_OF_SHAPE_CUBICLES>
_valid_orientations;
// For communication with Shape
Shape *_shape;
// Piece is in fixed, user-specified position and orientation
bool _pre_placed;
// Current state of piece (if currently) in shape
// int and -1 flag for _current_position instead of unsigned and
// static const int to use fast machine instruction negative test
int _current_position ; // cubicle 0 to 26, or -1
unsigned _current_orientation; // index into _orientations
#ifdef SOMA_STATISTICS
unsigned _place_successes ,
_place_failures ,
_place_duplicates ,
_place_orphans ,
_total_valid_orients;
#endif
}; // class Piece
} // namespace soma
#endif // ifndef PIECE_H