twisty_puzzles 0.0.1 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +6 -1
- data/ext/twisty_puzzles/native/cube_algorithm.c +267 -0
- data/ext/twisty_puzzles/native/cube_algorithm.h +5 -0
- data/ext/twisty_puzzles/native/cube_average.c +184 -0
- data/ext/twisty_puzzles/native/cube_average.h +5 -0
- data/ext/twisty_puzzles/native/cube_coordinate.c +207 -0
- data/ext/twisty_puzzles/native/cube_coordinate.h +34 -0
- data/ext/twisty_puzzles/native/cube_state.c +264 -0
- data/ext/twisty_puzzles/native/cube_state.h +31 -0
- data/ext/twisty_puzzles/native/extconf.rb +1 -1
- data/ext/twisty_puzzles/native/face_symbols.c +67 -0
- data/ext/twisty_puzzles/native/face_symbols.h +34 -0
- data/ext/twisty_puzzles/native/native.c +28 -0
- data/ext/twisty_puzzles/native/skewb_algorithm.c +331 -0
- data/ext/twisty_puzzles/native/skewb_algorithm.h +5 -0
- data/ext/twisty_puzzles/native/skewb_coordinate.c +237 -0
- data/ext/twisty_puzzles/native/skewb_coordinate.h +36 -0
- data/ext/twisty_puzzles/native/skewb_layer_fingerprint.c +271 -0
- data/ext/twisty_puzzles/native/skewb_layer_fingerprint.h +5 -0
- data/ext/twisty_puzzles/native/skewb_state.c +214 -0
- data/ext/twisty_puzzles/native/skewb_state.h +23 -0
- data/ext/twisty_puzzles/native/utils.c +76 -0
- data/ext/twisty_puzzles/native/utils.h +31 -0
- data/lib/twisty_puzzles.rb +38 -0
- data/lib/twisty_puzzles/abstract_direction.rb +38 -39
- data/lib/twisty_puzzles/abstract_move.rb +1 -2
- data/lib/twisty_puzzles/abstract_move_parser.rb +32 -33
- data/lib/twisty_puzzles/algorithm.rb +112 -113
- data/lib/twisty_puzzles/algorithm_transformation.rb +19 -21
- data/lib/twisty_puzzles/axis_face_and_direction_move.rb +56 -56
- data/lib/twisty_puzzles/cancellation_helper.rb +124 -125
- data/lib/twisty_puzzles/color_scheme.rb +1 -1
- data/lib/twisty_puzzles/commutator.rb +82 -80
- data/lib/twisty_puzzles/compiled_algorithm.rb +31 -32
- data/lib/twisty_puzzles/compiled_cube_algorithm.rb +49 -50
- data/lib/twisty_puzzles/compiled_skewb_algorithm.rb +18 -19
- data/lib/twisty_puzzles/coordinate.rb +243 -246
- data/lib/twisty_puzzles/cube.rb +494 -495
- data/lib/twisty_puzzles/cube_constants.rb +40 -41
- data/lib/twisty_puzzles/cube_direction.rb +15 -18
- data/lib/twisty_puzzles/cube_move.rb +285 -290
- data/lib/twisty_puzzles/cube_move_parser.rb +75 -76
- data/lib/twisty_puzzles/cube_print_helper.rb +133 -133
- data/lib/twisty_puzzles/cube_state.rb +80 -81
- data/lib/twisty_puzzles/move_type_creator.rb +17 -18
- data/lib/twisty_puzzles/parser.rb +176 -179
- data/lib/twisty_puzzles/part_cycle_factory.rb +39 -42
- data/lib/twisty_puzzles/puzzle.rb +16 -17
- data/lib/twisty_puzzles/reversible_applyable.rb +24 -25
- data/lib/twisty_puzzles/rotation.rb +76 -75
- data/lib/twisty_puzzles/skewb_direction.rb +14 -15
- data/lib/twisty_puzzles/skewb_move.rb +49 -49
- data/lib/twisty_puzzles/skewb_move_parser.rb +51 -51
- data/lib/twisty_puzzles/skewb_notation.rb +121 -118
- data/lib/twisty_puzzles/skewb_state.rb +120 -121
- data/lib/twisty_puzzles/state_helper.rb +20 -21
- data/lib/twisty_puzzles/sticker_cycle.rb +43 -44
- data/lib/twisty_puzzles/utils.rb +3 -0
- data/lib/twisty_puzzles/version.rb +3 -1
- metadata +30 -10
@@ -0,0 +1,214 @@
|
|
1
|
+
#include "skewb_state.h"
|
2
|
+
|
3
|
+
#include "face_symbols.h"
|
4
|
+
|
5
|
+
static VALUE SkewbStateClass = Qnil;
|
6
|
+
|
7
|
+
static void SkewbStateData_mark(void* const ptr) {
|
8
|
+
const SkewbStateData* data = ptr;
|
9
|
+
for (size_t i = 0; i < total_skewb_stickers; ++i) {
|
10
|
+
rb_gc_mark(data->stickers[i]);
|
11
|
+
}
|
12
|
+
}
|
13
|
+
|
14
|
+
static size_t SkewbStateData_size(const void* const ptr) {
|
15
|
+
return sizeof(SkewbStateData);
|
16
|
+
}
|
17
|
+
|
18
|
+
const rb_data_type_t SkewbStateData_type = {
|
19
|
+
"SkewbTrainer::Native::SkewbStateData",
|
20
|
+
{SkewbStateData_mark, NULL, SkewbStateData_size, NULL},
|
21
|
+
NULL, NULL,
|
22
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
23
|
+
};
|
24
|
+
|
25
|
+
static VALUE SkewbState_alloc(const VALUE klass) {
|
26
|
+
SkewbStateData* data;
|
27
|
+
const VALUE object = TypedData_Make_Struct(klass, SkewbStateData, &SkewbStateData_type, data);
|
28
|
+
for (size_t i = 0; i < total_skewb_stickers; ++i) {
|
29
|
+
data->stickers[i] = Qnil;
|
30
|
+
}
|
31
|
+
return object;
|
32
|
+
}
|
33
|
+
|
34
|
+
static int SkewbState_replace_face(const VALUE key, const VALUE value, const VALUE self) {
|
35
|
+
SkewbStateData* data;
|
36
|
+
GetSkewbStateData(self, data);
|
37
|
+
const face_index_t on_face_index = face_index(key);
|
38
|
+
for (size_t i = 0; i < skewb_stickers_per_face; ++i) {
|
39
|
+
data->stickers[on_face_index * skewb_stickers_per_face + i] = value;
|
40
|
+
}
|
41
|
+
return ST_CONTINUE;
|
42
|
+
}
|
43
|
+
|
44
|
+
static VALUE SkewbState_initialize(const VALUE self, const VALUE stickers) {
|
45
|
+
Check_Type(stickers, T_HASH);
|
46
|
+
SkewbStateData* data;
|
47
|
+
GetSkewbStateData(self, data);
|
48
|
+
if (RHASH_SIZE(stickers) != skewb_faces) {
|
49
|
+
rb_raise(rb_eTypeError, "Skewbs must have %d faces. Got %ld.", skewb_faces, RHASH_SIZE(stickers));
|
50
|
+
}
|
51
|
+
rb_hash_foreach(stickers, SkewbState_replace_face, self);
|
52
|
+
return self;
|
53
|
+
}
|
54
|
+
|
55
|
+
static VALUE SkewbState_hash(const VALUE self) {
|
56
|
+
const SkewbStateData* data;
|
57
|
+
GetSkewbStateData(self, data);
|
58
|
+
|
59
|
+
st_index_t hash = rb_hash_start((st_index_t)SkewbState_hash);
|
60
|
+
for (size_t i = 0; i < total_skewb_stickers; i++) {
|
61
|
+
const VALUE sub_hash = rb_hash(data->stickers[i]);
|
62
|
+
hash = rb_hash_uint(hash, NUM2LONG(sub_hash));
|
63
|
+
}
|
64
|
+
return ST2FIX(rb_hash_end(hash));
|
65
|
+
}
|
66
|
+
|
67
|
+
static VALUE SkewbState_eql(const VALUE self, const VALUE other) {
|
68
|
+
if (self == other) {
|
69
|
+
return Qtrue;
|
70
|
+
}
|
71
|
+
if (rb_obj_class(self) != rb_obj_class(other)) {
|
72
|
+
return Qfalse;
|
73
|
+
}
|
74
|
+
const SkewbStateData* self_data;
|
75
|
+
GetSkewbStateData(self, self_data);
|
76
|
+
const SkewbStateData* other_data;
|
77
|
+
GetSkewbStateData(other, other_data);
|
78
|
+
for (size_t i = 0; i < total_skewb_stickers; ++i) {
|
79
|
+
if (!color_eq(self_data->stickers[i], other_data->stickers[i])) {
|
80
|
+
return Qfalse;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
return Qtrue;
|
84
|
+
}
|
85
|
+
|
86
|
+
static VALUE SkewbState_dup(const VALUE self) {
|
87
|
+
const SkewbStateData* data;
|
88
|
+
GetSkewbStateData(self, data);
|
89
|
+
SkewbStateData* dupped_data;
|
90
|
+
const VALUE dupped = TypedData_Make_Struct(rb_obj_class(self), SkewbStateData, &SkewbStateData_type, dupped_data);
|
91
|
+
*dupped_data = *data;
|
92
|
+
return dupped;
|
93
|
+
}
|
94
|
+
|
95
|
+
static VALUE SkewbState_entry(const VALUE self, const VALUE coordinate) {
|
96
|
+
const SkewbStateData* data;
|
97
|
+
GetSkewbStateData(self, data);
|
98
|
+
return data->stickers[SkewbCoordinate_sticker_index(coordinate)];
|
99
|
+
}
|
100
|
+
|
101
|
+
static VALUE SkewbState_store(const VALUE self, const VALUE coordinate, const VALUE value) {
|
102
|
+
SkewbStateData* data;
|
103
|
+
GetSkewbStateData(self, data);
|
104
|
+
return data->stickers[SkewbCoordinate_sticker_index(coordinate)] = value;
|
105
|
+
}
|
106
|
+
|
107
|
+
static void apply_twisted_corner_cycle(VALUE* const stickers, const Corner corner, const bool invert) {
|
108
|
+
size_t twisted_corner_cycle[3];
|
109
|
+
for (size_t i = 0; i < 3; ++i) {
|
110
|
+
const Corner corner_variant = rotated_corner(corner, i);
|
111
|
+
twisted_corner_cycle[i] = corner_sticker_index(corner_variant);
|
112
|
+
}
|
113
|
+
apply_sticker_cycle(stickers, twisted_corner_cycle, 3, invert);
|
114
|
+
}
|
115
|
+
|
116
|
+
static void apply_center_cycle(VALUE* const stickers, const Corner corner, const bool invert) {
|
117
|
+
size_t center_cycle[3];
|
118
|
+
for (size_t i = 0; i < 3; ++i) {
|
119
|
+
center_cycle[i] = center_sticker_index(corner.face_indices[i]);
|
120
|
+
}
|
121
|
+
apply_sticker_cycle(stickers, center_cycle, 3, invert);
|
122
|
+
}
|
123
|
+
|
124
|
+
static void apply_moved_corner_cycles(VALUE* const stickers, const Corner corner, const bool invert) {
|
125
|
+
Corner adjacent_corners[3];
|
126
|
+
for (size_t corner_index = 0; corner_index < 3; ++corner_index) {
|
127
|
+
adjacent_corners[corner_index].face_indices[0] = opposite_face_index(corner.face_indices[corner_index]);
|
128
|
+
adjacent_corners[corner_index].face_indices[1] = corner.face_indices[(corner_index + 2) % 3];
|
129
|
+
adjacent_corners[corner_index].face_indices[2] = corner.face_indices[(corner_index + 1) % 3];
|
130
|
+
}
|
131
|
+
// We have 3 different cycles, one for the outside stickers and one two for the remaining stickers of the
|
132
|
+
// corners that contain the outside stickers.
|
133
|
+
for (size_t cycle_index = 0; cycle_index < 3; ++cycle_index) {
|
134
|
+
size_t sticker_cycle[3];
|
135
|
+
for (size_t corner_index = 0; corner_index < 3; ++corner_index) {
|
136
|
+
// The current corner, but twisted such that the sticker we care about in the current cycle faces up.
|
137
|
+
const Corner current_corner_for_current_cycle = rotated_corner(adjacent_corners[corner_index], cycle_index);
|
138
|
+
sticker_cycle[corner_index] = corner_sticker_index(current_corner_for_current_cycle);
|
139
|
+
}
|
140
|
+
apply_sticker_cycle(stickers, sticker_cycle, 3, invert);
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
void rotate_corner_for_skewb_state(const Corner corner, direction_t direction, SkewbStateData* const skewb_state) {
|
145
|
+
direction = CROP_MOD(direction, 3);
|
146
|
+
if (direction == 0) {
|
147
|
+
return;
|
148
|
+
}
|
149
|
+
const bool invert = direction == 2;
|
150
|
+
|
151
|
+
apply_twisted_corner_cycle(skewb_state->stickers, corner, invert);
|
152
|
+
apply_center_cycle(skewb_state->stickers, corner, invert);
|
153
|
+
apply_moved_corner_cycles(skewb_state->stickers, corner, invert);
|
154
|
+
}
|
155
|
+
|
156
|
+
static void apply_center_rotation(VALUE* const stickers, const face_index_t axis_face_index, const direction_t direction) {
|
157
|
+
Sticker4Cycle center_cycle;
|
158
|
+
for (size_t i = 0; i < 4; ++i) {
|
159
|
+
center_cycle.indices[i] = center_sticker_index(neighbor_face_index(axis_face_index, i));
|
160
|
+
}
|
161
|
+
apply_sticker_4cycle(stickers, center_cycle, direction);
|
162
|
+
}
|
163
|
+
|
164
|
+
static void apply_corner_rotations(VALUE* const stickers, const face_index_t axis_face_index, const direction_t direction) {
|
165
|
+
Corner corner;
|
166
|
+
corner.face_indices[2] = axis_face_index;
|
167
|
+
for (size_t cycle_index = 0; cycle_index < 3; ++cycle_index) {
|
168
|
+
Sticker4Cycle corner_cycle;
|
169
|
+
for (size_t corner_index = 0; corner_index < 4; ++corner_index) {
|
170
|
+
for (size_t i = 0; i < 2; ++i) {
|
171
|
+
corner.face_indices[i] = neighbor_face_index(axis_face_index, corner_index + i);
|
172
|
+
}
|
173
|
+
corner_cycle.indices[corner_index] = corner_sticker_index(rotated_corner(corner, cycle_index));
|
174
|
+
}
|
175
|
+
apply_sticker_4cycle(stickers, corner_cycle, direction);
|
176
|
+
}
|
177
|
+
}
|
178
|
+
|
179
|
+
void rotate_skewb_state(const face_index_t axis_face_index, direction_t direction, SkewbStateData* const skewb_state) {
|
180
|
+
direction = CROP_MOD(direction, 4);
|
181
|
+
if (direction == 0) {
|
182
|
+
return;
|
183
|
+
}
|
184
|
+
apply_center_rotation(skewb_state->stickers, axis_face_index, direction);
|
185
|
+
apply_corner_rotations(skewb_state->stickers, axis_face_index, direction);
|
186
|
+
apply_corner_rotations(skewb_state->stickers, opposite_face_index(axis_face_index), invert_cube_direction(direction));
|
187
|
+
}
|
188
|
+
|
189
|
+
static VALUE SkewbState_face_solved(const VALUE self, const VALUE face_symbol) {
|
190
|
+
const SkewbStateData* data;
|
191
|
+
GetSkewbStateData(self, data);
|
192
|
+
const face_index_t solved_face_index = face_index(face_symbol);
|
193
|
+
const size_t center_index = center_sticker_index(solved_face_index);
|
194
|
+
const VALUE color = data->stickers[center_index];
|
195
|
+
for (int i = 1; i < 5; ++i) {
|
196
|
+
if (!color_eq(data->stickers[center_index + i], color)) {
|
197
|
+
return Qfalse;
|
198
|
+
}
|
199
|
+
}
|
200
|
+
return Qtrue;
|
201
|
+
}
|
202
|
+
|
203
|
+
void init_skewb_state_class_under(const VALUE module) {
|
204
|
+
SkewbStateClass = rb_define_class_under(module, "SkewbState", rb_cObject);
|
205
|
+
rb_define_alloc_func(SkewbStateClass, SkewbState_alloc);
|
206
|
+
rb_define_method(SkewbStateClass, "initialize", SkewbState_initialize, 1);
|
207
|
+
rb_define_method(SkewbStateClass, "hash", SkewbState_hash, 0);
|
208
|
+
rb_define_method(SkewbStateClass, "eql?", SkewbState_eql, 1);
|
209
|
+
rb_define_alias(SkewbStateClass, "==", "eql?");
|
210
|
+
rb_define_method(SkewbStateClass, "dup", SkewbState_dup, 0);
|
211
|
+
rb_define_method(SkewbStateClass, "[]", SkewbState_entry, 1);
|
212
|
+
rb_define_method(SkewbStateClass, "[]=", SkewbState_store, 2);
|
213
|
+
rb_define_method(SkewbStateClass, "face_solved?", SkewbState_face_solved, 1);
|
214
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
|
5
|
+
#include "skewb_coordinate.h"
|
6
|
+
#include "utils.h"
|
7
|
+
|
8
|
+
typedef struct {
|
9
|
+
VALUE stickers[total_skewb_stickers];
|
10
|
+
} SkewbStateData;
|
11
|
+
|
12
|
+
extern const rb_data_type_t SkewbStateData_type;
|
13
|
+
|
14
|
+
#define GetSkewbStateData(obj, data) \
|
15
|
+
do { \
|
16
|
+
TypedData_Get_Struct((obj), SkewbStateData, &SkewbStateData_type, (data)); \
|
17
|
+
} while (0)
|
18
|
+
|
19
|
+
void rotate_corner_for_skewb_state(Corner corner, direction_t direction, SkewbStateData* skewb_state);
|
20
|
+
|
21
|
+
void rotate_skewb_state(face_index_t axis_face_index, direction_t direction, SkewbStateData* skewb_state);
|
22
|
+
|
23
|
+
void init_skewb_state_class_under(VALUE module);
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#include "utils.h"
|
2
|
+
|
3
|
+
static void swap(VALUE* const stickers, size_t i, size_t j) {
|
4
|
+
VALUE buffer;
|
5
|
+
buffer = stickers[i];
|
6
|
+
stickers[i] = stickers[j];
|
7
|
+
stickers[j] = buffer;
|
8
|
+
}
|
9
|
+
|
10
|
+
direction_t invert_cube_direction(direction_t direction) {
|
11
|
+
return (4 - direction) % 4;
|
12
|
+
}
|
13
|
+
|
14
|
+
direction_t invert_skewb_direction(direction_t direction) {
|
15
|
+
return (3 - direction) % 3;
|
16
|
+
}
|
17
|
+
|
18
|
+
void apply_sticker_cycle(VALUE* const stickers, const size_t* const indices, const size_t size, const bool invert) {
|
19
|
+
const size_t direction = invert ? size - 1 : 1;
|
20
|
+
const size_t last_index = (direction * (size - 1)) % size;
|
21
|
+
const VALUE buffer = stickers[indices[last_index]];
|
22
|
+
for (size_t i = size - 1; i >= 1; --i) {
|
23
|
+
const size_t target_index = (direction * i) % size;
|
24
|
+
const size_t source_index = (direction * (i - 1)) % size;
|
25
|
+
stickers[indices[target_index]] = stickers[indices[source_index]];
|
26
|
+
}
|
27
|
+
stickers[indices[0]] = buffer;
|
28
|
+
}
|
29
|
+
|
30
|
+
void apply_sticker_4cycle(VALUE* const stickers, const Sticker4Cycle cycle, const direction_t direction) {
|
31
|
+
const direction_t d = (direction % 4 + 4) % 4;
|
32
|
+
if (d == 0) {
|
33
|
+
return;
|
34
|
+
} else if (d == 2) {
|
35
|
+
swap(stickers, cycle.indices[0], cycle.indices[2]);
|
36
|
+
swap(stickers, cycle.indices[1], cycle.indices[3]);
|
37
|
+
} else {
|
38
|
+
apply_sticker_cycle(stickers, cycle.indices, 4, d == 3);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
int color_eq(const VALUE left, const VALUE right) {
|
43
|
+
return RTEST(rb_equal(left, right));
|
44
|
+
}
|
45
|
+
|
46
|
+
// Magic table of values that we use for computing the log2.
|
47
|
+
static const int tab64[64] = {
|
48
|
+
63, 0, 58, 1, 59, 47, 53, 2,
|
49
|
+
60, 39, 48, 27, 54, 33, 42, 3,
|
50
|
+
61, 51, 37, 40, 49, 18, 28, 20,
|
51
|
+
55, 30, 34, 11, 43, 14, 22, 4,
|
52
|
+
62, 57, 46, 52, 38, 26, 32, 41,
|
53
|
+
50, 36, 17, 19, 29, 10, 13, 21,
|
54
|
+
56, 45, 25, 31, 35, 16, 9, 12,
|
55
|
+
44, 24, 15, 8, 23, 7, 6, 5};
|
56
|
+
|
57
|
+
int log2_64_floor(uint64_t value) {
|
58
|
+
value |= value >> 1;
|
59
|
+
value |= value >> 2;
|
60
|
+
value |= value >> 4;
|
61
|
+
value |= value >> 8;
|
62
|
+
value |= value >> 16;
|
63
|
+
value |= value >> 32;
|
64
|
+
return tab64[((uint64_t)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58];
|
65
|
+
}
|
66
|
+
|
67
|
+
uint64_t iexp(const uint64_t base, uint32_t exp) {
|
68
|
+
uint64_t result = 1;
|
69
|
+
for (uint32_t m = 1 << 31; m; m >>= 1) {
|
70
|
+
result = result * result;
|
71
|
+
if (m & exp) {
|
72
|
+
result *= base;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
return result;
|
76
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <stdint.h>
|
5
|
+
|
6
|
+
#define MIN(a, b) ((a) > (b) ? (b) : (a))
|
7
|
+
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
8
|
+
#define FALSE 0
|
9
|
+
#define TRUE 1
|
10
|
+
#define CROP_MOD(a, b) (((a) % (b) + (b)) % (b))
|
11
|
+
|
12
|
+
typedef char bool;
|
13
|
+
typedef char direction_t;
|
14
|
+
|
15
|
+
typedef struct {
|
16
|
+
size_t indices[4];
|
17
|
+
} Sticker4Cycle;
|
18
|
+
|
19
|
+
direction_t invert_cube_direction(direction_t direction);
|
20
|
+
|
21
|
+
direction_t invert_skewb_direction(direction_t direction);
|
22
|
+
|
23
|
+
void apply_sticker_cycle(VALUE* stickers, const size_t* indices, size_t size, bool invert);
|
24
|
+
|
25
|
+
void apply_sticker_4cycle(VALUE* stickers, Sticker4Cycle cycle, direction_t direction);
|
26
|
+
|
27
|
+
int color_eq(VALUE left, VALUE right);
|
28
|
+
|
29
|
+
int log2_64_floor(uint64_t value);
|
30
|
+
|
31
|
+
uint64_t iexp(uint64_t base, uint32_t exp);
|
data/lib/twisty_puzzles.rb
CHANGED
@@ -1,5 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'twisty_puzzles/abstract_direction'
|
4
|
+
require 'twisty_puzzles/abstract_move'
|
5
|
+
require 'twisty_puzzles/abstract_move_parser'
|
6
|
+
require 'twisty_puzzles/algorithm'
|
7
|
+
require 'twisty_puzzles/algorithm_transformation'
|
8
|
+
require 'twisty_puzzles/axis_face_and_direction_move'
|
9
|
+
require 'twisty_puzzles/cancellation_helper'
|
10
|
+
require 'twisty_puzzles/color_scheme'
|
11
|
+
require 'twisty_puzzles/commutator'
|
12
|
+
require 'twisty_puzzles/compiled_algorithm'
|
13
|
+
require 'twisty_puzzles/compiled_cube_algorithm'
|
14
|
+
require 'twisty_puzzles/compiled_skewb_algorithm'
|
15
|
+
require 'twisty_puzzles/coordinate'
|
16
|
+
require 'twisty_puzzles/cube'
|
17
|
+
require 'twisty_puzzles/cube_constants'
|
18
|
+
require 'twisty_puzzles/cube_direction'
|
19
|
+
require 'twisty_puzzles/cube_move'
|
20
|
+
require 'twisty_puzzles/cube_move_parser'
|
21
|
+
require 'twisty_puzzles/cube_print_helper'
|
22
|
+
require 'twisty_puzzles/cube_state'
|
23
|
+
require 'twisty_puzzles/letter_scheme'
|
24
|
+
require 'twisty_puzzles/move_type_creator'
|
25
|
+
require 'twisty_puzzles/native'
|
26
|
+
require 'twisty_puzzles/parser'
|
27
|
+
require 'twisty_puzzles/part_cycle_factory'
|
28
|
+
require 'twisty_puzzles/puzzle'
|
29
|
+
require 'twisty_puzzles/reversible_applyable'
|
30
|
+
require 'twisty_puzzles/rotation'
|
31
|
+
require 'twisty_puzzles/skewb_direction'
|
32
|
+
require 'twisty_puzzles/skewb_move'
|
33
|
+
require 'twisty_puzzles/skewb_move_parser'
|
34
|
+
require 'twisty_puzzles/skewb_notation'
|
35
|
+
require 'twisty_puzzles/skewb_state'
|
36
|
+
require 'twisty_puzzles/state_helper'
|
37
|
+
require 'twisty_puzzles/sticker_cycle'
|
38
|
+
require 'twisty_puzzles/twisty_puzzles_error'
|
39
|
+
require 'twisty_puzzles/version'
|
40
|
+
|
3
41
|
# Libraries for the twisty puzzles.
|
4
42
|
module TwistyPuzzles
|
5
43
|
end
|
@@ -1,54 +1,53 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TwistyPuzzles
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
raise ArgumentError, "Invalid direction value #{value}."
|
17
|
-
end
|
18
|
-
|
19
|
-
@value = value
|
4
|
+
# Base class for directions.
|
5
|
+
class AbstractDirection
|
6
|
+
include Comparable
|
7
|
+
POSSIBLE_DIRECTION_NAMES = [[''], ['2', '2\''], ['\'', '3']].freeze
|
8
|
+
SIMPLE_DIRECTION_NAMES = (['0'] + POSSIBLE_DIRECTION_NAMES.map(&:first)).freeze
|
9
|
+
POSSIBLE_SKEWB_DIRECTION_NAMES = [['', '2\''], ['\'', '2']].freeze
|
10
|
+
SIMPLE_SKEWB_DIRECTION_NAMES = (['0'] + POSSIBLE_SKEWB_DIRECTION_NAMES.map(&:first)).freeze
|
11
|
+
|
12
|
+
def initialize(value)
|
13
|
+
raise TypeError, "Direction value #{value} isn't an integer." unless value.is_a?(Integer)
|
14
|
+
unless value >= 0 && value < self.class::NUM_DIRECTIONS
|
15
|
+
raise ArgumentError, "Invalid direction value #{value}."
|
20
16
|
end
|
21
17
|
|
22
|
-
|
18
|
+
@value = value
|
19
|
+
end
|
23
20
|
|
24
|
-
|
25
|
-
@value <=> other.value
|
26
|
-
end
|
21
|
+
attr_reader :value
|
27
22
|
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
def <=>(other)
|
24
|
+
@value <=> other.value
|
25
|
+
end
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
27
|
+
def zero?
|
28
|
+
@value.zero?
|
29
|
+
end
|
35
30
|
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
def non_zero?
|
32
|
+
@value.positive?
|
33
|
+
end
|
39
34
|
|
40
|
-
|
41
|
-
|
42
|
-
|
35
|
+
def inverse
|
36
|
+
self.class.new((self.class::NUM_DIRECTIONS - @value) % self.class::NUM_DIRECTIONS)
|
37
|
+
end
|
43
38
|
|
44
|
-
|
45
|
-
|
46
|
-
|
39
|
+
def +(other)
|
40
|
+
self.class.new((@value + other.value) % self.class::NUM_DIRECTIONS)
|
41
|
+
end
|
42
|
+
|
43
|
+
def eql?(other)
|
44
|
+
self.class.equal?(other.class) && @value == other.value
|
45
|
+
end
|
47
46
|
|
48
|
-
|
47
|
+
alias == eql?
|
49
48
|
|
50
|
-
|
51
|
-
|
52
|
-
end
|
49
|
+
def hash
|
50
|
+
@value.hash
|
53
51
|
end
|
52
|
+
end
|
54
53
|
end
|