twisty_puzzles 0.0.2 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -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 +28 -0
- data/lib/twisty_puzzles.rb +1 -0
- data/lib/twisty_puzzles/abstract_move.rb +1 -2
- data/lib/twisty_puzzles/abstract_move_parser.rb +1 -1
- data/lib/twisty_puzzles/algorithm.rb +1 -1
- data/lib/twisty_puzzles/axis_face_and_direction_move.rb +1 -0
- data/lib/twisty_puzzles/cancellation_helper.rb +1 -1
- data/lib/twisty_puzzles/color_scheme.rb +1 -1
- data/lib/twisty_puzzles/commutator.rb +3 -0
- data/lib/twisty_puzzles/compiled_algorithm.rb +4 -4
- data/lib/twisty_puzzles/coordinate.rb +4 -6
- data/lib/twisty_puzzles/cube.rb +3 -3
- data/lib/twisty_puzzles/cube_move.rb +0 -4
- data/lib/twisty_puzzles/cube_move_parser.rb +23 -23
- data/lib/twisty_puzzles/cube_print_helper.rb +4 -3
- data/lib/twisty_puzzles/parser.rb +3 -3
- data/lib/twisty_puzzles/rotation.rb +2 -0
- data/lib/twisty_puzzles/skewb_move.rb +1 -0
- data/lib/twisty_puzzles/skewb_move_parser.rb +1 -0
- data/lib/twisty_puzzles/skewb_notation.rb +7 -1
- data/lib/twisty_puzzles/version.rb +1 -1
- metadata +32 -12
@@ -0,0 +1,31 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
|
5
|
+
#include "face_symbols.h"
|
6
|
+
|
7
|
+
typedef struct {
|
8
|
+
size_t cube_size;
|
9
|
+
VALUE* stickers;
|
10
|
+
} CubeStateData;
|
11
|
+
|
12
|
+
extern const rb_data_type_t CubeStateData_type;
|
13
|
+
|
14
|
+
#define GetCubeStateData(obj, data) \
|
15
|
+
do { \
|
16
|
+
TypedData_Get_Struct((obj), CubeStateData, &CubeStateData_type, (data)); \
|
17
|
+
} while (0)
|
18
|
+
|
19
|
+
#define GetInitializedCubeStateData(obj, data) \
|
20
|
+
do { \
|
21
|
+
GetCubeStateData((obj), (data)); \
|
22
|
+
if (data->stickers == NULL) { \
|
23
|
+
rb_raise(rb_eArgError, "Cube state isn't initialized."); \
|
24
|
+
} \
|
25
|
+
} while(0)
|
26
|
+
|
27
|
+
void rotate_slice_for_cube(face_index_t turned_face_index, size_t slice_index, direction_t direction, const CubeStateData* data);
|
28
|
+
|
29
|
+
void rotate_face_for_cube(face_index_t turned_face_index, direction_t direction, const CubeStateData* data);
|
30
|
+
|
31
|
+
void init_cube_state_class_under(VALUE module);
|
@@ -0,0 +1,67 @@
|
|
1
|
+
#include "face_symbols.h"
|
2
|
+
|
3
|
+
#include <stdlib.h>
|
4
|
+
|
5
|
+
static ID face_ids[cube_faces];
|
6
|
+
|
7
|
+
face_index_t face_index(const VALUE face_symbol) {
|
8
|
+
Check_Type(face_symbol, T_SYMBOL);
|
9
|
+
const ID face_id = SYM2ID(face_symbol);
|
10
|
+
for (size_t i = 0; i < cube_faces; ++i) {
|
11
|
+
if (face_ids[i] == face_id) {
|
12
|
+
return i;
|
13
|
+
}
|
14
|
+
}
|
15
|
+
rb_raise(rb_eArgError, "Invalid face symbol %+"PRIsVALUE"", face_symbol);
|
16
|
+
}
|
17
|
+
|
18
|
+
// TODO This is very unelegant.
|
19
|
+
static const face_index_t U_neighbors[neighbor_faces] = {F, L, B, R};
|
20
|
+
static const face_index_t F_neighbors[neighbor_faces] = {U, R, D, L};
|
21
|
+
static const face_index_t R_neighbors[neighbor_faces] = {U, B, D, F};
|
22
|
+
|
23
|
+
face_index_t neighbor_face_index(const face_index_t face_index, const size_t index) {
|
24
|
+
const size_t adjusted_index = face_index == axis_index(face_index) ? index : -index;
|
25
|
+
const size_t cropped_index = (adjusted_index % 4 + 4) % 4;
|
26
|
+
switch (axis_index(face_index)) {
|
27
|
+
case U: return U_neighbors[cropped_index];
|
28
|
+
case F: return F_neighbors[cropped_index];
|
29
|
+
case R: return R_neighbors[cropped_index];
|
30
|
+
default:
|
31
|
+
rb_raise(rb_eRuntimeError, "invalid axis index");
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
VALUE face_symbol(const face_index_t face_index) {
|
36
|
+
return ID2SYM(face_ids[face_index]);
|
37
|
+
}
|
38
|
+
|
39
|
+
axis_index_t axis_index(const face_index_t face_index) {
|
40
|
+
return MIN(face_index, opposite_face_index(face_index));
|
41
|
+
}
|
42
|
+
|
43
|
+
bool same_axis(const face_index_t left_face_index, const face_index_t right_face_index) {
|
44
|
+
return axis_index(left_face_index) == axis_index(right_face_index);
|
45
|
+
}
|
46
|
+
|
47
|
+
face_index_t opposite_face_index(const face_index_t face_index) {
|
48
|
+
return cube_faces - 1 - face_index;
|
49
|
+
}
|
50
|
+
|
51
|
+
size_t neighbor_index(const face_index_t base_face_index, const face_index_t other_face_index) {
|
52
|
+
for (int i = 0; i < 4; ++i) {
|
53
|
+
if (neighbor_face_index(base_face_index, i) == other_face_index) {
|
54
|
+
return i;
|
55
|
+
}
|
56
|
+
}
|
57
|
+
return -1;
|
58
|
+
}
|
59
|
+
|
60
|
+
void init_face_symbols() {
|
61
|
+
face_ids[U] = rb_intern("U");
|
62
|
+
face_ids[F] = rb_intern("F");
|
63
|
+
face_ids[R] = rb_intern("R");
|
64
|
+
face_ids[L] = rb_intern("L");
|
65
|
+
face_ids[B] = rb_intern("B");
|
66
|
+
face_ids[D] = rb_intern("D");
|
67
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
|
5
|
+
#include "utils.h"
|
6
|
+
|
7
|
+
typedef char face_index_t;
|
8
|
+
typedef char axis_index_t;
|
9
|
+
|
10
|
+
#define cube_faces 6
|
11
|
+
#define neighbor_faces 4
|
12
|
+
|
13
|
+
#define U 0
|
14
|
+
#define F 1
|
15
|
+
#define R 2
|
16
|
+
#define L 3
|
17
|
+
#define B 4
|
18
|
+
#define D 5
|
19
|
+
|
20
|
+
face_index_t face_index(VALUE face_symbol);
|
21
|
+
|
22
|
+
face_index_t neighbor_face_index(face_index_t face_index, size_t index);
|
23
|
+
|
24
|
+
VALUE face_symbol(face_index_t face_index);
|
25
|
+
|
26
|
+
axis_index_t axis_index(face_index_t face_index);
|
27
|
+
|
28
|
+
bool same_axis(face_index_t left_face_index, face_index_t right_face_index);
|
29
|
+
|
30
|
+
face_index_t opposite_face_index(face_index_t face_index);
|
31
|
+
|
32
|
+
size_t neighbor_index(face_index_t base_face_index, face_index_t other_face_index);
|
33
|
+
|
34
|
+
void init_face_symbols();
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
|
3
|
+
#include "cube_algorithm.h"
|
4
|
+
#include "cube_average.h"
|
5
|
+
#include "cube_coordinate.h"
|
6
|
+
#include "cube_state.h"
|
7
|
+
#include "face_symbols.h"
|
8
|
+
#include "skewb_algorithm.h"
|
9
|
+
#include "skewb_coordinate.h"
|
10
|
+
#include "skewb_layer_fingerprint.h"
|
11
|
+
#include "skewb_state.h"
|
12
|
+
|
13
|
+
VALUE TwistyPuzzlesModule = Qnil;
|
14
|
+
VALUE NativeModule = Qnil;
|
15
|
+
|
16
|
+
void Init_native() {
|
17
|
+
TwistyPuzzlesModule = rb_define_module("TwistyPuzzles");
|
18
|
+
NativeModule = rb_define_module_under(TwistyPuzzlesModule, "Native");
|
19
|
+
init_cube_algorithm_class_under(NativeModule);
|
20
|
+
init_cube_average_class_under(NativeModule);
|
21
|
+
init_cube_coordinate_class_under(NativeModule);
|
22
|
+
init_cube_state_class_under(NativeModule);
|
23
|
+
init_face_symbols();
|
24
|
+
init_skewb_algorithm_class_under(NativeModule);
|
25
|
+
init_skewb_coordinate_class_under(NativeModule);
|
26
|
+
init_skewb_layer_fingerprint_method_under(NativeModule);
|
27
|
+
init_skewb_state_class_under(NativeModule);
|
28
|
+
}
|
@@ -0,0 +1,331 @@
|
|
1
|
+
#include "skewb_algorithm.h"
|
2
|
+
|
3
|
+
#include "face_symbols.h"
|
4
|
+
#include "skewb_coordinate.h"
|
5
|
+
#include "skewb_state.h"
|
6
|
+
#include "utils.h"
|
7
|
+
|
8
|
+
static ID move_id;
|
9
|
+
static ID rotation_id;
|
10
|
+
static VALUE SkewbAlgorithmClass = Qnil;
|
11
|
+
|
12
|
+
typedef enum {
|
13
|
+
MOVE,
|
14
|
+
ROTATION,
|
15
|
+
} SkewbMoveType;
|
16
|
+
|
17
|
+
typedef union {
|
18
|
+
Corner corner;
|
19
|
+
face_index_t face_index;
|
20
|
+
} SkewbAxis;
|
21
|
+
|
22
|
+
typedef struct {
|
23
|
+
SkewbMoveType type;
|
24
|
+
SkewbAxis axis;
|
25
|
+
direction_t direction;
|
26
|
+
} SkewbMove;
|
27
|
+
|
28
|
+
typedef struct {
|
29
|
+
size_t size;
|
30
|
+
// We need this because we can't use the usual checking for 0/NULL because and empty algorithm is valid.
|
31
|
+
bool initialized;
|
32
|
+
SkewbMove* moves;
|
33
|
+
} SkewbAlgorithmData;
|
34
|
+
|
35
|
+
static void SkewbAlgorithmData_free(void* const ptr) {
|
36
|
+
const SkewbAlgorithmData* const data = ptr;
|
37
|
+
free(data->moves);
|
38
|
+
free(ptr);
|
39
|
+
}
|
40
|
+
|
41
|
+
static size_t SkewbAlgorithmData_size(const void* const ptr) {
|
42
|
+
const SkewbAlgorithmData* const data = ptr;
|
43
|
+
return sizeof(SkewbAlgorithmData) + data->size * sizeof(SkewbMove);
|
44
|
+
}
|
45
|
+
|
46
|
+
const rb_data_type_t SkewbAlgorithmData_type = {
|
47
|
+
"TwistyPuzzles::Native::SkewbAlgorithmData",
|
48
|
+
{NULL, SkewbAlgorithmData_free, SkewbAlgorithmData_size, NULL},
|
49
|
+
NULL, NULL,
|
50
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
51
|
+
};
|
52
|
+
|
53
|
+
static void check_moves(const SkewbAlgorithmData* const data, const char* const name) {
|
54
|
+
for (size_t i = 0; i < data->size; ++i) {
|
55
|
+
const SkewbMoveType type = data->moves[i].type;
|
56
|
+
if (type != MOVE && type != ROTATION) {
|
57
|
+
rb_raise(rb_eRuntimeError, "invalid move type %d in %s", type, name);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
|
62
|
+
static SkewbMove* malloc_moves(const size_t n) {
|
63
|
+
SkewbMove* const moves = malloc(n * sizeof(SkewbMove));
|
64
|
+
if (moves == NULL) {
|
65
|
+
rb_raise(rb_eNoMemError, "Allocating skewb algorithm failed.");
|
66
|
+
}
|
67
|
+
return moves;
|
68
|
+
}
|
69
|
+
|
70
|
+
static VALUE SkewbAlgorithm_alloc(const VALUE klass) {
|
71
|
+
SkewbAlgorithmData* data;
|
72
|
+
const VALUE object = TypedData_Make_Struct(klass, SkewbAlgorithmData, &SkewbAlgorithmData_type, data);
|
73
|
+
data->size = 0;
|
74
|
+
data->initialized = FALSE;
|
75
|
+
data->moves = NULL;
|
76
|
+
return object;
|
77
|
+
}
|
78
|
+
|
79
|
+
#define GetSkewbAlgorithmData(obj, data) \
|
80
|
+
do { \
|
81
|
+
TypedData_Get_Struct((obj), SkewbAlgorithmData, &SkewbAlgorithmData_type, (data)); \
|
82
|
+
} while (0)
|
83
|
+
|
84
|
+
#define GetInitializedSkewbAlgorithmData(obj, data) \
|
85
|
+
do { \
|
86
|
+
GetSkewbAlgorithmData((obj), (data)); \
|
87
|
+
if (!data->initialized) { \
|
88
|
+
rb_raise(rb_eRuntimeError, "Skewb algorithm isn't initialized."); \
|
89
|
+
} \
|
90
|
+
} while(0)
|
91
|
+
|
92
|
+
static SkewbMoveType extract_move_type(const VALUE move_symbol) {
|
93
|
+
Check_Type(move_symbol, T_SYMBOL);
|
94
|
+
const ID move_symbol_id = SYM2ID(move_symbol);
|
95
|
+
if (move_symbol_id == move_id) {
|
96
|
+
return MOVE;
|
97
|
+
} else if (move_symbol_id == rotation_id) {
|
98
|
+
return ROTATION;
|
99
|
+
} else {
|
100
|
+
rb_raise(rb_eArgError, "Got invalid move symbol.");
|
101
|
+
}
|
102
|
+
}
|
103
|
+
|
104
|
+
static SkewbAxis extract_axis(const SkewbMoveType type, const VALUE axis) {
|
105
|
+
SkewbAxis result;
|
106
|
+
switch (type) {
|
107
|
+
case MOVE:
|
108
|
+
result.corner = extract_corner(axis);
|
109
|
+
return result;
|
110
|
+
case ROTATION:
|
111
|
+
result.face_index = face_index(axis);
|
112
|
+
return result;
|
113
|
+
default:
|
114
|
+
rb_raise(rb_eRuntimeError, "invalid move type %d in extract_axis", type);
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
static VALUE SkewbAlgorithm_initialize(const VALUE self, const VALUE moves) {
|
119
|
+
Check_Type(moves, T_ARRAY);
|
120
|
+
SkewbAlgorithmData* data;
|
121
|
+
GetSkewbAlgorithmData(self, data);
|
122
|
+
data->size = RARRAY_LEN(moves);
|
123
|
+
data->initialized = TRUE;
|
124
|
+
data->moves = malloc_moves(data->size);
|
125
|
+
for (size_t i = 0; i < RARRAY_LEN(moves); ++i) {
|
126
|
+
const VALUE move = rb_ary_entry(moves, i);
|
127
|
+
if (RARRAY_LEN(move) != 3) {
|
128
|
+
rb_raise(rb_eArgError, "Moves must have 3 elements. Got %ld.", RARRAY_LEN(moves));
|
129
|
+
}
|
130
|
+
const SkewbMoveType type = extract_move_type(rb_ary_entry(move, 0));
|
131
|
+
data->moves[i].type = type;
|
132
|
+
data->moves[i].axis = extract_axis(type, rb_ary_entry(move, 1));
|
133
|
+
data->moves[i].direction = NUM2INT(rb_ary_entry(move, 2));
|
134
|
+
}
|
135
|
+
return self;
|
136
|
+
}
|
137
|
+
|
138
|
+
static void apply_move_to(const SkewbMove move, SkewbStateData* const skewb_state) {
|
139
|
+
switch (move.type) {
|
140
|
+
case MOVE:
|
141
|
+
rotate_corner_for_skewb_state(move.axis.corner, move.direction, skewb_state);
|
142
|
+
break;
|
143
|
+
case ROTATION:
|
144
|
+
rotate_skewb_state(move.axis.face_index, move.direction, skewb_state);
|
145
|
+
break;
|
146
|
+
default:
|
147
|
+
rb_raise(rb_eRuntimeError, "invalid move type %d in apply_move_to", move.type);
|
148
|
+
}
|
149
|
+
}
|
150
|
+
|
151
|
+
static VALUE SkewbAlgorithm_apply_to(const VALUE self, const VALUE skewb_state) {
|
152
|
+
SkewbStateData* skewb_state_data;
|
153
|
+
GetSkewbStateData(skewb_state, skewb_state_data);
|
154
|
+
const SkewbAlgorithmData* data;
|
155
|
+
GetInitializedSkewbAlgorithmData(self, data);
|
156
|
+
for (size_t i = 0; i < data->size; ++i) {
|
157
|
+
apply_move_to(data->moves[i], skewb_state_data);
|
158
|
+
}
|
159
|
+
return Qnil;
|
160
|
+
}
|
161
|
+
|
162
|
+
// Takes either face_index or the opposite, depending which one is present on corner.
|
163
|
+
static face_index_t axis_face_on_corner(const Corner corner, const face_index_t face_index) {
|
164
|
+
for (size_t i = 0; i < 3; ++i) {
|
165
|
+
if (same_axis(corner.face_indices[i], face_index)) {
|
166
|
+
return corner.face_indices[i];
|
167
|
+
}
|
168
|
+
}
|
169
|
+
rb_raise(rb_eRuntimeError, "invalid state in axis_face_on_corner");
|
170
|
+
}
|
171
|
+
|
172
|
+
bool corners_eq(Corner left, Corner right) {
|
173
|
+
return left.face_indices[0] == right.face_indices[0] &&
|
174
|
+
(left.face_indices[1] == right.face_indices[1] && left.face_indices[2] == right.face_indices[2] ||
|
175
|
+
left.face_indices[1] == right.face_indices[2] && left.face_indices[2] == right.face_indices[1]);
|
176
|
+
}
|
177
|
+
|
178
|
+
size_t equivalent_corner_index(const FaceCorners corners, const Corner corner) {
|
179
|
+
for (size_t i = 0; i < 4; ++i) {
|
180
|
+
for (int j = 0; j < 3; ++j) {
|
181
|
+
if (corners_eq(rotated_corner(corners.corners[i], j), corner)) {
|
182
|
+
return i;
|
183
|
+
}
|
184
|
+
}
|
185
|
+
}
|
186
|
+
rb_raise(rb_eRuntimeError, "invalid state in equivalent_corner_index");
|
187
|
+
}
|
188
|
+
|
189
|
+
static SkewbMove rotate_move_by(const SkewbMove move, const face_index_t rotation_face_index, const direction_t rotation_direction) {
|
190
|
+
SkewbMove result = move;
|
191
|
+
switch (move.type) {
|
192
|
+
case MOVE: {
|
193
|
+
const face_index_t nice_rotation_face_index = axis_face_on_corner(move.axis.corner, rotation_face_index);
|
194
|
+
const face_index_t nice_rotation_direction = rotation_face_index == nice_rotation_face_index ? rotation_direction : invert_cube_direction(rotation_direction);
|
195
|
+
FaceCorners corners = get_face_corners(nice_rotation_face_index);
|
196
|
+
const size_t corner_index = equivalent_corner_index(corners, move.axis.corner);
|
197
|
+
result.axis.corner = corners.corners[(corner_index + nice_rotation_direction) % 4];
|
198
|
+
break;
|
199
|
+
}
|
200
|
+
case ROTATION: {
|
201
|
+
if (!same_axis(move.axis.face_index, rotation_face_index)) {
|
202
|
+
const size_t index = neighbor_index(rotation_face_index, move.axis.face_index);
|
203
|
+
result.axis.face_index = neighbor_face_index(rotation_face_index, index + rotation_direction);
|
204
|
+
}
|
205
|
+
break;
|
206
|
+
}
|
207
|
+
default:
|
208
|
+
rb_raise(rb_eRuntimeError, "invalid move type %d in rotate_move_by", move.type);
|
209
|
+
}
|
210
|
+
return result;
|
211
|
+
}
|
212
|
+
|
213
|
+
static VALUE SkewbAlgorithm_rotate_by(const VALUE self, const VALUE rotation_face_symbol, const VALUE direction) {
|
214
|
+
const face_index_t rotation_face_index = face_index(rotation_face_symbol);
|
215
|
+
const direction_t rotation_direction = NUM2INT(direction);
|
216
|
+
const SkewbAlgorithmData* data;
|
217
|
+
GetInitializedSkewbAlgorithmData(self, data);
|
218
|
+
SkewbAlgorithmData* rotated_data;
|
219
|
+
const VALUE rotated = TypedData_Make_Struct(SkewbAlgorithmClass, SkewbAlgorithmData, &SkewbAlgorithmData_type, rotated_data);
|
220
|
+
rotated_data->size = data->size;
|
221
|
+
rotated_data->initialized = TRUE;
|
222
|
+
rotated_data->moves = malloc_moves(rotated_data->size);
|
223
|
+
for (size_t i = 0; i < data->size; ++i) {
|
224
|
+
rotated_data->moves[i] = rotate_move_by(data->moves[i], rotation_face_index, rotation_direction);
|
225
|
+
}
|
226
|
+
return rotated;
|
227
|
+
}
|
228
|
+
|
229
|
+
static SkewbMove mirror_move(const SkewbMove move, const face_index_t normal_face_index) {
|
230
|
+
SkewbMove result = move;
|
231
|
+
switch (move.type) {
|
232
|
+
case MOVE: {
|
233
|
+
for (size_t i = 0; i < 3; ++i) {
|
234
|
+
const face_index_t current_face_index = move.axis.corner.face_indices[i];
|
235
|
+
if (same_axis(current_face_index, normal_face_index)) {
|
236
|
+
// We need to make one face into the opposite and then swap to to fix the chirality.
|
237
|
+
result.axis.corner.face_indices[(i + 1) % 3] = opposite_face_index(current_face_index);
|
238
|
+
result.axis.corner.face_indices[i] = move.axis.corner.face_indices[(i + 1) % 3];
|
239
|
+
break;
|
240
|
+
}
|
241
|
+
}
|
242
|
+
result.direction = invert_skewb_direction(move.direction);
|
243
|
+
break;
|
244
|
+
}
|
245
|
+
case ROTATION: {
|
246
|
+
if (!same_axis(move.axis.face_index, normal_face_index)) {
|
247
|
+
result.direction = invert_cube_direction(move.direction);
|
248
|
+
}
|
249
|
+
break;
|
250
|
+
}
|
251
|
+
default:
|
252
|
+
rb_raise(rb_eRuntimeError, "invalid move type %d in mirror_move", move.type);
|
253
|
+
}
|
254
|
+
return result;
|
255
|
+
}
|
256
|
+
|
257
|
+
static VALUE SkewbAlgorithm_mirror(const VALUE self, const VALUE normal_face_symbol) {
|
258
|
+
const face_index_t normal_face_index = face_index(normal_face_symbol);
|
259
|
+
const SkewbAlgorithmData* data;
|
260
|
+
GetInitializedSkewbAlgorithmData(self, data);
|
261
|
+
SkewbAlgorithmData* mirrored_data;
|
262
|
+
const VALUE mirrored = TypedData_Make_Struct(SkewbAlgorithmClass, SkewbAlgorithmData, &SkewbAlgorithmData_type, mirrored_data);
|
263
|
+
mirrored_data->size = data->size;
|
264
|
+
mirrored_data->initialized = TRUE;
|
265
|
+
mirrored_data->moves = malloc_moves(mirrored_data->size);
|
266
|
+
for (size_t i = 0; i < data->size; ++i) {
|
267
|
+
mirrored_data->moves[i] = mirror_move(data->moves[i], normal_face_index);
|
268
|
+
}
|
269
|
+
return mirrored;
|
270
|
+
}
|
271
|
+
|
272
|
+
static SkewbMove invert_move(const SkewbMove move) {
|
273
|
+
SkewbMove result = move;
|
274
|
+
switch (move.type) {
|
275
|
+
case MOVE:
|
276
|
+
result.direction = invert_skewb_direction(result.direction);
|
277
|
+
break;
|
278
|
+
case ROTATION:
|
279
|
+
result.direction = invert_cube_direction(result.direction);
|
280
|
+
break;
|
281
|
+
default:
|
282
|
+
rb_raise(rb_eRuntimeError, "invalid move type %d in invert_move", move.type);
|
283
|
+
}
|
284
|
+
return result;
|
285
|
+
}
|
286
|
+
|
287
|
+
static VALUE SkewbAlgorithm_inverse(const VALUE self) {
|
288
|
+
const SkewbAlgorithmData* data;
|
289
|
+
GetInitializedSkewbAlgorithmData(self, data);
|
290
|
+
SkewbAlgorithmData* inverted_data;
|
291
|
+
const VALUE inverted = TypedData_Make_Struct(SkewbAlgorithmClass, SkewbAlgorithmData, &SkewbAlgorithmData_type, inverted_data);
|
292
|
+
inverted_data->size = data->size;
|
293
|
+
inverted_data->initialized = TRUE;
|
294
|
+
inverted_data->moves = malloc_moves(inverted_data->size);
|
295
|
+
for (size_t i = 0; i < data->size; ++i) {
|
296
|
+
inverted_data->moves[i] = invert_move(data->moves[data->size - 1 - i]);
|
297
|
+
}
|
298
|
+
return inverted;
|
299
|
+
}
|
300
|
+
|
301
|
+
static VALUE SkewbAlgorithm_plus(const VALUE self, const VALUE other) {
|
302
|
+
const SkewbAlgorithmData* self_data;
|
303
|
+
GetInitializedSkewbAlgorithmData(self, self_data);
|
304
|
+
const SkewbAlgorithmData* other_data;
|
305
|
+
GetInitializedSkewbAlgorithmData(other, other_data);
|
306
|
+
SkewbAlgorithmData* sum_data;
|
307
|
+
const VALUE sum = TypedData_Make_Struct(SkewbAlgorithmClass, SkewbAlgorithmData, &SkewbAlgorithmData_type, sum_data);
|
308
|
+
sum_data->size = self_data->size + other_data->size;
|
309
|
+
sum_data->initialized = TRUE;
|
310
|
+
sum_data->moves = malloc_moves(sum_data->size);
|
311
|
+
for (size_t i = 0; i < self_data->size; ++i) {
|
312
|
+
sum_data->moves[i] = self_data->moves[i];
|
313
|
+
}
|
314
|
+
for (size_t i = 0; i < other_data->size; ++i) {
|
315
|
+
sum_data->moves[self_data->size + i] = other_data->moves[i];
|
316
|
+
}
|
317
|
+
return sum;
|
318
|
+
}
|
319
|
+
|
320
|
+
void init_skewb_algorithm_class_under(const VALUE module) {
|
321
|
+
move_id = rb_intern("move");
|
322
|
+
rotation_id = rb_intern("rotation");
|
323
|
+
SkewbAlgorithmClass = rb_define_class_under(module, "SkewbAlgorithm", rb_cObject);
|
324
|
+
rb_define_alloc_func(SkewbAlgorithmClass, SkewbAlgorithm_alloc);
|
325
|
+
rb_define_method(SkewbAlgorithmClass, "initialize", SkewbAlgorithm_initialize, 1);
|
326
|
+
rb_define_method(SkewbAlgorithmClass, "apply_to", SkewbAlgorithm_apply_to, 1);
|
327
|
+
rb_define_method(SkewbAlgorithmClass, "rotate_by", SkewbAlgorithm_rotate_by, 2);
|
328
|
+
rb_define_method(SkewbAlgorithmClass, "mirror", SkewbAlgorithm_mirror, 1);
|
329
|
+
rb_define_method(SkewbAlgorithmClass, "inverse", SkewbAlgorithm_inverse, 0);
|
330
|
+
rb_define_method(SkewbAlgorithmClass, "+", SkewbAlgorithm_plus, 1);
|
331
|
+
}
|