twisty_puzzles 0.0.6 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 59a43662a260f2e013e0b59b6597dbfc4f6b5a04bc9d49b9f350b9c3a050babe
4
- data.tar.gz: 98e23ce0bbcb677b9deb490ca02bb2e6c3fbd376c0c5a35dcb79d6e06afbd905
3
+ metadata.gz: 0f6166de8734039f856869be9f20b6109c194556094bc281ae3138ada4a1ad27
4
+ data.tar.gz: 6a19cc1ad482ec49831c057d944b9055f70c206882ac618892b0336e8d047e3b
5
5
  SHA512:
6
- metadata.gz: fb187fa6e58c48444b5629e4ab195f2063d2ad9b0c8f07aa8d3a4e19486c177fb29b38a404e2a80f0690d6491466f94cd638d04fc6d76389ffb915671c2107a4
7
- data.tar.gz: 9b89321ce8b01b446b992a318aaf43f2cdc54bc9745d16538f14e2bc93f038a413923a11c0e856e13712e20a29c6d0416344ed577ea5aac642ef295571d489a3
6
+ metadata.gz: 3ba31f44cb0df6f836d9a9b9908550cd2d6ca0ede672d4784f084b609e1249fd0e8e0f8d6cdc0b09e8faba6a462d49966c698b9d5601a4901aa0ee4eb8bc95c1
7
+ data.tar.gz: 16727e63c37191c99ed1c185c851c8a541c97f110505f2c6ae5eeeabb186c11c35173d35c2441cc8c15318dd88f380656afc04690d5bb4eaa9b359b9a2725de3
@@ -18,12 +18,12 @@ typedef struct {
18
18
  CubeMoveType type;
19
19
  face_index_t axis_face_index;
20
20
  direction_t direction;
21
- size_t slice_index;
21
+ long slice_index;
22
22
  } CubeMove;
23
23
 
24
24
  typedef struct {
25
25
  size_t size;
26
- size_t cube_size;
26
+ long cube_size;
27
27
  CubeMove* moves;
28
28
  } CubeAlgorithmData;
29
29
 
@@ -45,15 +45,6 @@ const rb_data_type_t CubeAlgorithmData_type = {
45
45
  RUBY_TYPED_FREE_IMMEDIATELY
46
46
  };
47
47
 
48
- static void check_moves(const CubeAlgorithmData* const data, const char* const name) {
49
- for (size_t i = 0; i < data->size; ++i) {
50
- const CubeMoveType type = data->moves[i].type;
51
- if (type != SLICE && type != FACE) {
52
- rb_raise(rb_eRuntimeError, "invalid move type %d in %s", type, name);
53
- }
54
- }
55
- }
56
-
57
48
  static CubeMove* malloc_moves(const size_t n) {
58
49
  CubeMove* const moves = malloc(n * sizeof(CubeMove));
59
50
  if (moves == NULL) {
@@ -96,7 +87,7 @@ static CubeMoveType extract_move_type(const VALUE move_symbol) {
96
87
  }
97
88
  }
98
89
 
99
- static size_t components_for_move_type(const CubeMoveType type) {
90
+ static long components_for_move_type(const CubeMoveType type) {
100
91
  switch (type) {
101
92
  case SLICE:
102
93
  return 4;
@@ -112,24 +103,25 @@ static VALUE CubeAlgorithm_initialize(const VALUE self, const VALUE cube_size, c
112
103
  CubeAlgorithmData* data;
113
104
  GetCubeAlgorithmData(self, data);
114
105
  data->size = RARRAY_LEN(moves);
115
- data->cube_size = NUM2INT(cube_size);
106
+ data->cube_size = FIX2INT(cube_size);
107
+ check_cube_size(data->cube_size);
116
108
  data->moves = malloc_moves(data->size);
117
- for (size_t i = 0; i < RARRAY_LEN(moves); ++i) {
109
+ for (long i = 0; i < RARRAY_LEN(moves); ++i) {
118
110
  const VALUE move = rb_ary_entry(moves, i);
119
111
  if (RARRAY_LEN(move) < 1) {
120
112
  rb_raise(rb_eArgError, "Moves cannot be empty.");
121
113
  }
122
114
  const CubeMoveType type = extract_move_type(rb_ary_entry(move, 0));
123
- const size_t num_components = components_for_move_type(type);
115
+ const long num_components = components_for_move_type(type);
124
116
  if (RARRAY_LEN(move) != num_components) {
125
117
  rb_raise(rb_eArgError, "Moves with the given type need to have %ld elements. Got %ld.", num_components, RARRAY_LEN(move));
126
118
  }
127
119
  data->moves[i].type = type;
128
120
  data->moves[i].axis_face_index = face_index(rb_ary_entry(move, 1));
129
- data->moves[i].direction = NUM2INT(rb_ary_entry(move, 2));
121
+ data->moves[i].direction = FIX2INT(rb_ary_entry(move, 2));
130
122
  if (type == SLICE) {
131
- const size_t slice_index = NUM2INT(rb_ary_entry(move, 3));
132
- if (slice_index >= data->cube_size) {
123
+ const long slice_index = FIX2INT(rb_ary_entry(move, 3));
124
+ if (slice_index < 0 || slice_index >= data->cube_size) {
133
125
  rb_raise(rb_eArgError, "Invalid slice index %ld for cube size %ld.", slice_index, data->cube_size);
134
126
  }
135
127
  data->moves[i].slice_index = slice_index;
@@ -59,7 +59,7 @@ static VALUE CubeAverage_alloc(const VALUE klass) {
59
59
 
60
60
  static VALUE CubeAverage_initialize(const VALUE self, const VALUE capacity, const VALUE initial_average) {
61
61
  Check_Type(capacity, T_FIXNUM);
62
- const size_t n = FIX2INT(capacity);
62
+ const long n = FIX2INT(capacity);
63
63
  if (n < 3) {
64
64
  rb_raise(rb_eArgError, "The number of elements for a cube average has to be at least 3. Got %ld.", n);
65
65
  }
@@ -147,7 +147,7 @@ static VALUE CubeAverage_push_all(const VALUE self, const VALUE new_values) {
147
147
  const size_t insert_index = data->insert_index;
148
148
  const size_t capacity = data->capacity;
149
149
  const size_t start = num_values > capacity ? num_values - capacity : 0;
150
- for (size_t i = start; i < RARRAY_LEN(new_values); ++i) {
150
+ for (long i = start; i < RARRAY_LEN(new_values); ++i) {
151
151
  const VALUE new_value = rb_ary_entry(new_values, i);
152
152
  data->values[(insert_index + i) % capacity] = NUM2DBL(new_value);
153
153
  }
@@ -5,7 +5,7 @@
5
5
  static VALUE CubeCoordinateClass = Qnil;
6
6
 
7
7
  typedef struct {
8
- size_t cube_size;
8
+ long cube_size;
9
9
  face_index_t on_face_index;
10
10
  Point point;
11
11
  } CubeCoordinateData;
@@ -26,15 +26,15 @@ const rb_data_type_t CubeCoordinateData_type = {
26
26
  TypedData_Get_Struct((obj), CubeCoordinateData, &CubeCoordinateData_type, (data)); \
27
27
  } while (0)
28
28
 
29
- size_t num_stickers(const size_t cube_size) {
29
+ size_t num_stickers(const long cube_size) {
30
30
  return cube_faces * cube_size * cube_size;
31
31
  }
32
32
 
33
- size_t sticker_index(const size_t cube_size, const face_index_t on_face_index, const Point point) {
33
+ size_t sticker_index(const long cube_size, const face_index_t on_face_index, const Point point) {
34
34
  return on_face_index * cube_size * cube_size + point.y * cube_size + point.x;
35
35
  }
36
36
 
37
- size_t CubeCoordinate_sticker_index(const VALUE self, const size_t cube_size) {
37
+ size_t CubeCoordinate_sticker_index(const VALUE self, const long cube_size) {
38
38
  CubeCoordinateData* data;
39
39
  GetCubeCoordinateData(self, data);
40
40
  if (data->cube_size != cube_size) {
@@ -53,11 +53,11 @@ static VALUE CubeCoordinate_alloc(const VALUE klass) {
53
53
  return object;
54
54
  }
55
55
 
56
- static size_t inverted_index(const size_t cube_size, const size_t index) {
56
+ static long inverted_index(const long cube_size, const long index) {
57
57
  return cube_size - 1 - index;
58
58
  }
59
59
 
60
- size_t transform_index(const face_index_t index_base_face_index, const size_t cube_size, const size_t index) {
60
+ long transform_index(const face_index_t index_base_face_index, const long cube_size, const long index) {
61
61
  if (index_base_face_index == axis_index(index_base_face_index)) {
62
62
  return index;
63
63
  } else {
@@ -86,11 +86,11 @@ void check_base_face_indices(const face_index_t on_face_index,
86
86
  Point point_on_face(const face_index_t face_index,
87
87
  const face_index_t x_base_face_index,
88
88
  const face_index_t y_base_face_index,
89
- const size_t cube_size,
90
- const size_t untransformed_x,
91
- const size_t untransformed_y) {
92
- const size_t transformed_x = transform_index(x_base_face_index, cube_size, untransformed_x);
93
- const size_t transformed_y = transform_index(y_base_face_index, cube_size, untransformed_y);
89
+ const long cube_size,
90
+ const long untransformed_x,
91
+ const long untransformed_y) {
92
+ const long transformed_x = transform_index(x_base_face_index, cube_size, untransformed_x);
93
+ const long transformed_y = transform_index(y_base_face_index, cube_size, untransformed_y);
94
94
  Point point;
95
95
  if (switch_axes(x_base_face_index, y_base_face_index)) {
96
96
  point.x = transformed_y;
@@ -102,7 +102,7 @@ Point point_on_face(const face_index_t face_index,
102
102
  return point;
103
103
  }
104
104
 
105
- static void check_cube_index(const size_t cube_size, const size_t index) {
105
+ static void check_cube_index(const long cube_size, const long index) {
106
106
  if (index < 0 || index >= cube_size) {
107
107
  rb_raise(rb_eArgError, "Invalid value %ld for x with cube size %ld.", index, cube_size);
108
108
  }
@@ -121,14 +121,15 @@ static VALUE CubeCoordinate_initialize(const VALUE self,
121
121
  Check_Type(y_base_face_symbol, T_SYMBOL);
122
122
  Check_Type(x_num, T_FIXNUM);
123
123
  Check_Type(y_num, T_FIXNUM);
124
- const size_t n = FIX2INT(cube_size);
124
+ const long n = FIX2INT(cube_size);
125
+ check_cube_size(n);
125
126
  const face_index_t on_face_index = face_index(face_symbol);
126
127
  const face_index_t x_base_face_index = face_index(x_base_face_symbol);
127
128
  const face_index_t y_base_face_index = face_index(y_base_face_symbol);
128
129
  check_base_face_indices(on_face_index, x_base_face_index, y_base_face_index);
129
- const size_t untransformed_x = FIX2INT(x_num);
130
+ const long untransformed_x = FIX2INT(x_num);
130
131
  check_cube_index(n, untransformed_x);
131
- const size_t untransformed_y = FIX2INT(y_num);
132
+ const long untransformed_y = FIX2INT(y_num);
132
133
  check_cube_index(n, untransformed_y);
133
134
  const Point point = point_on_face(on_face_index, x_base_face_index, y_base_face_index, n, untransformed_x, untransformed_y);
134
135
  CubeCoordinateData* data;
@@ -5,16 +5,16 @@
5
5
  #include "face_symbols.h"
6
6
  #include "utils.h"
7
7
 
8
- size_t num_stickers(size_t cube_size);
8
+ size_t num_stickers(long cube_size);
9
9
 
10
10
  typedef struct {
11
11
  size_t x;
12
12
  size_t y;
13
13
  } Point;
14
14
 
15
- size_t sticker_index(size_t cube_size, face_index_t on_face_index, Point point);
15
+ size_t sticker_index(long cube_size, face_index_t on_face_index, Point point);
16
16
 
17
- size_t transform_index(face_index_t index_base_face_index, size_t cube_size, size_t index);
17
+ long transform_index(face_index_t index_base_face_index, long cube_size, long index);
18
18
 
19
19
  bool switch_axes(face_index_t x_base_face_index, face_index_t y_base_face_index);
20
20
 
@@ -25,10 +25,10 @@ void check_base_face_indices(face_index_t on_face_index,
25
25
  Point point_on_face(face_index_t on_face_index,
26
26
  face_index_t x_base_face_index,
27
27
  face_index_t y_base_face_index,
28
- size_t cube_size,
29
- size_t untransformed_x,
30
- size_t untransformed_y);
28
+ long cube_size,
29
+ long untransformed_x,
30
+ long untransformed_y);
31
31
 
32
- size_t CubeCoordinate_sticker_index(VALUE self, size_t cube_size);
32
+ size_t CubeCoordinate_sticker_index(VALUE self, long cube_size);
33
33
 
34
34
  void init_cube_coordinate_class_under(VALUE module);
@@ -12,7 +12,7 @@ static VALUE CubeStateClass = Qnil;
12
12
 
13
13
  static void CubeStateData_mark(void* const ptr) {
14
14
  const CubeStateData* data = ptr;
15
- const size_t n = data->cube_size;
15
+ const long n = data->cube_size;
16
16
  for (size_t i = 0; i < num_stickers(n); ++i) {
17
17
  rb_gc_mark(data->stickers[i]);
18
18
  }
@@ -52,19 +52,10 @@ static VALUE CubeState_alloc(const VALUE klass) {
52
52
  return object;
53
53
  }
54
54
 
55
- static size_t extract_index_base_face_index(const VALUE face_hash, const VALUE key) {
56
- const VALUE index_base_face_symbol = rb_hash_aref(face_hash, key);
57
- if (index_base_face_symbol == Qnil) {
58
- rb_raise(rb_eTypeError, "Cube faces must have keys called :{x,y}_base_face_symbol that describes which face an x or y value of 0 is close to.");
59
- }
60
- Check_Type(index_base_face_symbol, T_SYMBOL);
61
- return face_index(index_base_face_symbol);
62
- }
63
-
64
55
  static int CubeState_replace_face(const VALUE key, const VALUE value, const VALUE self) {
65
56
  const CubeStateData* data;
66
57
  GetInitializedCubeStateData(self, data);
67
- const size_t n = data->cube_size;
58
+ const long n = data->cube_size;
68
59
  Check_Type(value, T_HASH);
69
60
  if (RHASH_SIZE(value) != 3) {
70
61
  rb_raise(rb_eTypeError, "Cube faces must have 3 entries, got %ld.", RHASH_SIZE(value));
@@ -75,19 +66,17 @@ static int CubeState_replace_face(const VALUE key, const VALUE value, const VALU
75
66
  if (stickers == Qnil) {
76
67
  rb_raise(rb_eTypeError, "Cube faces must have a key called :stickers that contains the stickers on that face.");
77
68
  }
78
- const face_index_t x_base_face_index = extract_index_base_face_index(value, ID2SYM(x_base_face_symbol_id));
79
- const face_index_t y_base_face_index = extract_index_base_face_index(value, ID2SYM(y_base_face_symbol_id));
80
69
  Check_Type(stickers, T_ARRAY);
81
70
  if (RARRAY_LEN(stickers) != n) {
82
71
  rb_raise(rb_eArgError, "All faces of a %ldx%ld cube must have %ld rows. Got %ld rows.", n, n, n, RARRAY_LEN(stickers));
83
72
  }
84
- for (size_t y = 0; y < n; ++y) {
73
+ for (long y = 0; y < n; ++y) {
85
74
  const VALUE row = rb_ary_entry(stickers, y);
86
75
  Check_Type(row, T_ARRAY);
87
76
  if (RARRAY_LEN(row) != n) {
88
77
  rb_raise(rb_eArgError, "All rows of a %ldx%ld cube must have %ld cells. Got %ld cells.", n, n, n, RARRAY_LEN(row));
89
78
  }
90
- for (size_t x = 0; x < n; ++x) {
79
+ for (long x = 0; x < n; ++x) {
91
80
  const VALUE cell = rb_ary_entry(row, x);
92
81
  Point point = {x, y};
93
82
  data->stickers[sticker_index(n, on_face_index, point)] = cell;
@@ -99,7 +88,8 @@ static int CubeState_replace_face(const VALUE key, const VALUE value, const VALU
99
88
  static VALUE CubeState_initialize(const VALUE self, const VALUE cube_size, const VALUE stickers) {
100
89
  Check_Type(cube_size, T_FIXNUM);
101
90
  Check_Type(stickers, T_HASH);
102
- const size_t n = FIX2INT(cube_size);
91
+ const long n = FIX2INT(cube_size);
92
+ check_cube_size(n);
103
93
  CubeStateData* data;
104
94
  GetCubeStateData(self, data);
105
95
  data->cube_size = n;
@@ -127,11 +117,11 @@ static VALUE CubeState_sticker_array(const VALUE self,
127
117
  check_base_face_indices(on_face_index, x_base_face_index, y_base_face_index);
128
118
  const CubeStateData* data;
129
119
  GetInitializedCubeStateData(self, data);
130
- const size_t n = data->cube_size;
120
+ const long n = data->cube_size;
131
121
  const VALUE face = rb_ary_new2(n);
132
- for (size_t y = 0; y < n; ++y) {
122
+ for (long y = 0; y < n; ++y) {
133
123
  const VALUE row = rb_ary_new2(n);
134
- for (size_t x = 0; x < n; ++x) {
124
+ for (long x = 0; x < n; ++x) {
135
125
  const Point point = point_on_face(on_face_index, x_base_face_index, y_base_face_index, n, x, y);
136
126
  const VALUE cell = data->stickers[sticker_index(n, on_face_index, point)];
137
127
  rb_ary_store(row, x, cell);
@@ -159,7 +149,7 @@ static VALUE CubeState_hash(const VALUE self) {
159
149
 
160
150
  st_index_t hash = rb_hash_start(data->cube_size);
161
151
  hash = rb_hash_uint(hash, (st_index_t)CubeState_hash);
162
- const size_t n = data->cube_size;
152
+ const long n = data->cube_size;
163
153
  for (size_t i = 0; i < num_stickers(n); i++) {
164
154
  const VALUE sub_hash = rb_hash(data->stickers[i]);
165
155
  hash = rb_hash_uint(hash, NUM2LONG(sub_hash));
@@ -181,7 +171,7 @@ static VALUE CubeState_eql(const VALUE self, const VALUE other) {
181
171
  if (self_data->cube_size != other_data->cube_size) {
182
172
  return Qfalse;
183
173
  }
184
- const size_t n = self_data->cube_size;
174
+ const long n = self_data->cube_size;
185
175
  for (size_t i = 0; i < num_stickers(n); ++i) {
186
176
  if (!color_eq(self_data->stickers[i], other_data->stickers[i])) {
187
177
  return Qfalse;
@@ -193,7 +183,7 @@ static VALUE CubeState_eql(const VALUE self, const VALUE other) {
193
183
  static VALUE CubeState_dup(const VALUE self) {
194
184
  const CubeStateData* data;
195
185
  GetInitializedCubeStateData(self, data);
196
- const size_t n = data->cube_size;
186
+ const long n = data->cube_size;
197
187
  CubeStateData* dupped_data;
198
188
  const VALUE dupped = TypedData_Make_Struct(rb_obj_class(self), CubeStateData, &CubeStateData_type, dupped_data);
199
189
  dupped_data->cube_size = n;
@@ -208,19 +198,19 @@ static VALUE CubeState_cube_size(const VALUE self) {
208
198
  return ST2FIX(data->cube_size);
209
199
  }
210
200
 
211
- void rotate_slice_for_cube(const face_index_t turned_face_index, const size_t slice_index, direction_t direction, const CubeStateData* const data) {
201
+ void rotate_slice_for_cube(const face_index_t turned_face_index, const long slice_index, direction_t direction, const CubeStateData* const data) {
212
202
  direction = CROP_MOD(direction, 4);
213
203
  if (direction == 0) {
214
204
  return;
215
205
  }
216
- const size_t n = data->cube_size;
217
- for (size_t i = 0; i < n; ++i) {
206
+ const long n = data->cube_size;
207
+ for (long x = 0; x < n; ++x) {
218
208
  Sticker4Cycle cycle;
219
- for (size_t j = 0; j < neighbor_faces; ++j) {
220
- const face_index_t on_face_index = neighbor_face_index(turned_face_index, j);
221
- const face_index_t next_face_index = neighbor_face_index(turned_face_index, j + 1);
222
- const Point point = point_on_face(on_face_index, turned_face_index, next_face_index, n, slice_index, i);
223
- cycle.indices[j] = sticker_index(n, on_face_index, point);
209
+ for (size_t i = 0; i < neighbor_faces; ++i) {
210
+ const face_index_t on_face_index = neighbor_face_index(turned_face_index, i);
211
+ const face_index_t next_face_index = neighbor_face_index(turned_face_index, i + 1);
212
+ const Point point = point_on_face(on_face_index, turned_face_index, next_face_index, n, slice_index, x);
213
+ cycle.indices[i] = sticker_index(n, on_face_index, point);
224
214
  }
225
215
  apply_sticker_4cycle(data->stickers, cycle, direction);
226
216
  }
@@ -231,9 +221,9 @@ void rotate_face_for_cube(const face_index_t turned_face_index, direction_t dire
231
221
  if (direction == 0) {
232
222
  return;
233
223
  }
234
- const size_t n = data->cube_size;
235
- for (size_t y = 0; y < n / 2; ++y) {
236
- for (size_t x = 0; x < (n + 1) / 2; ++x) {
224
+ const long n = data->cube_size;
225
+ for (long y = 0; y < n / 2; ++y) {
226
+ for (long x = 0; x < (n + 1) / 2; ++x) {
237
227
  Sticker4Cycle cycle;
238
228
  for (size_t j = 0; j < neighbor_faces; ++j) {
239
229
  const face_index_t x_face_index = neighbor_face_index(turned_face_index, j);
@@ -5,7 +5,7 @@
5
5
  #include "face_symbols.h"
6
6
 
7
7
  typedef struct {
8
- size_t cube_size;
8
+ long cube_size;
9
9
  VALUE* stickers;
10
10
  } CubeStateData;
11
11
 
@@ -24,7 +24,7 @@ extern const rb_data_type_t CubeStateData_type;
24
24
  } \
25
25
  } while(0)
26
26
 
27
- void rotate_slice_for_cube(face_index_t turned_face_index, size_t slice_index, direction_t direction, const CubeStateData* data);
27
+ void rotate_slice_for_cube(face_index_t turned_face_index, long slice_index, direction_t direction, const CubeStateData* data);
28
28
 
29
29
  void rotate_face_for_cube(face_index_t turned_face_index, direction_t direction, const CubeStateData* data);
30
30
 
@@ -4,8 +4,8 @@
4
4
 
5
5
  #include "utils.h"
6
6
 
7
- typedef char face_index_t;
8
- typedef char axis_index_t;
7
+ typedef unsigned char face_index_t;
8
+ typedef unsigned char axis_index_t;
9
9
 
10
10
  #define cube_faces 6
11
11
  #define neighbor_faces 4
@@ -50,15 +50,6 @@ const rb_data_type_t SkewbAlgorithmData_type = {
50
50
  RUBY_TYPED_FREE_IMMEDIATELY
51
51
  };
52
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
53
  static SkewbMove* malloc_moves(const size_t n) {
63
54
  SkewbMove* const moves = malloc(n * sizeof(SkewbMove));
64
55
  if (moves == NULL) {
@@ -122,7 +113,7 @@ static VALUE SkewbAlgorithm_initialize(const VALUE self, const VALUE moves) {
122
113
  data->size = RARRAY_LEN(moves);
123
114
  data->initialized = TRUE;
124
115
  data->moves = malloc_moves(data->size);
125
- for (size_t i = 0; i < RARRAY_LEN(moves); ++i) {
116
+ for (long i = 0; i < RARRAY_LEN(moves); ++i) {
126
117
  const VALUE move = rb_ary_entry(moves, i);
127
118
  if (RARRAY_LEN(move) != 3) {
128
119
  rb_raise(rb_eArgError, "Moves must have 3 elements. Got %ld.", RARRAY_LEN(moves));
@@ -171,8 +162,8 @@ static face_index_t axis_face_on_corner(const Corner corner, const face_index_t
171
162
 
172
163
  bool corners_eq(Corner left, Corner right) {
173
164
  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]);
165
+ ((left.face_indices[1] == right.face_indices[1] && left.face_indices[2] == right.face_indices[2]) ||
166
+ (left.face_indices[1] == right.face_indices[2] && left.face_indices[2] == right.face_indices[1]));
176
167
  }
177
168
 
178
169
  size_t equivalent_corner_index(const FaceCorners corners, const Corner corner) {
@@ -56,17 +56,6 @@ size_t center_sticker_index(const face_index_t on_face_index) {
56
56
  return on_face_index * skewb_stickers_per_face;
57
57
  }
58
58
 
59
- static VALUE part_type_from_symbol(const VALUE part_type_symbol) {
60
- Check_Type(face_symbol, T_SYMBOL);
61
- if (SYM2ID(part_type_symbol) == center_part_type_id) {
62
- return CENTER;
63
- } else if (SYM2ID(part_type_symbol) == corner_part_type_id) {
64
- return CORNER;
65
- } else {
66
- rb_raise(rb_eArgError, "Invalid part type symbol %+"PRIsVALUE"", part_type_symbol);
67
- }
68
- }
69
-
70
59
  static VALUE part_type_to_symbol(const SkewbPartType part_type) {
71
60
  // Caching these keys isn't easy because the garbage collector will get them.
72
61
  switch (part_type) {
@@ -32,7 +32,7 @@ static ID times = 848;
32
32
 
33
33
  typedef struct {
34
34
  Corner corner_pairs[max_corner_pair_group_size][2];
35
- int num_corner_pairs;
35
+ size_t num_corner_pairs;
36
36
  // Number of different group fingerprints. This can be used to merge several group fingerprints.
37
37
  int num_group_fingerprints;
38
38
  } CornerPairGroup;
@@ -55,7 +55,7 @@ static bool has_color_at(const ActualCornerStickers actual, const size_t index,
55
55
  }
56
56
 
57
57
  typedef struct {
58
- int layer_index;
58
+ size_t layer_index;
59
59
  bool is_oriented;
60
60
  bool is_present;
61
61
  } ActualCornerStickersInfo;
@@ -268,4 +268,5 @@ void init_skewb_layer_fingerprint_method_under(const VALUE module) {
268
268
  plus = rb_intern("+");
269
269
  times = rb_intern("*");
270
270
  rb_define_singleton_method(module, "skewb_layer_fingerprint", skewb_layer_fingerprint, 2);
271
+ init_corner_pair_groups();
271
272
  }
@@ -43,8 +43,6 @@ static int SkewbState_replace_face(const VALUE key, const VALUE value, const VAL
43
43
 
44
44
  static VALUE SkewbState_initialize(const VALUE self, const VALUE stickers) {
45
45
  Check_Type(stickers, T_HASH);
46
- SkewbStateData* data;
47
- GetSkewbStateData(self, data);
48
46
  if (RHASH_SIZE(stickers) != skewb_faces) {
49
47
  rb_raise(rb_eTypeError, "Skewbs must have %d faces. Got %ld.", skewb_faces, RHASH_SIZE(stickers));
50
48
  }
@@ -64,7 +64,7 @@ int log2_64_floor(uint64_t value) {
64
64
  return tab64[((uint64_t)((value - (value >> 1))*0x07EDD5E59A4E28C2)) >> 58];
65
65
  }
66
66
 
67
- uint64_t iexp(const uint64_t base, uint32_t exp) {
67
+ uint64_t iexp(const uint64_t base, const uint32_t exp) {
68
68
  uint64_t result = 1;
69
69
  for (uint32_t m = 1 << 31; m; m >>= 1) {
70
70
  result = result * result;
@@ -74,3 +74,9 @@ uint64_t iexp(const uint64_t base, uint32_t exp) {
74
74
  }
75
75
  return result;
76
76
  }
77
+
78
+ void check_cube_size(const long cube_size) {
79
+ if (cube_size <= 0) {
80
+ rb_raise(rb_eArgError, "Cube size must be positive. Got %ld.", cube_size);
81
+ }
82
+ }
@@ -5,11 +5,8 @@
5
5
 
6
6
  #define MIN(a, b) ((a) > (b) ? (b) : (a))
7
7
  #define MAX(a, b) ((a) > (b) ? (a) : (b))
8
- #define FALSE 0
9
- #define TRUE 1
10
8
  #define CROP_MOD(a, b) (((a) % (b) + (b)) % (b))
11
9
 
12
- typedef char bool;
13
10
  typedef char direction_t;
14
11
 
15
12
  typedef struct {
@@ -29,3 +26,5 @@ int color_eq(VALUE left, VALUE right);
29
26
  int log2_64_floor(uint64_t value);
30
27
 
31
28
  uint64_t iexp(uint64_t base, uint32_t exp);
29
+
30
+ void check_cube_size(long cube_size);
@@ -143,6 +143,10 @@ module TwistyPuzzles
143
143
  prepend_slice_move(other, cube_size)
144
144
  end
145
145
 
146
+ def prepend_slice_move(_other, _cube_size)
147
+ raise NotImplementedError, "#{self.class}#prepend_slice_move is not implemented"
148
+ end
149
+
146
150
  private
147
151
 
148
152
  def move_count_internal(metric, slice_factor, direction_factor)
@@ -31,14 +31,14 @@ module TwistyPuzzles
31
31
  def parse_move(move_string)
32
32
  match = move_string.match(regexp)
33
33
  if !match || !match.pre_match.empty? || !match.post_match.empty?
34
- raise ArgumentError("Invalid move #{move_string}.")
34
+ raise ArgumentError, "Invalid move #{move_string}."
35
35
  end
36
36
 
37
37
  parsed_parts = parse_named_captures(match)
38
38
  move_type_creators.each do |parser|
39
39
  return parser.create(parsed_parts) if parser.applies_to?(parsed_parts)
40
40
  end
41
- raise "No move type creator applies to #{parsed_parts}"
41
+ raise ArgumentError, "No move type creator applies to #{parsed_parts}"
42
42
  end
43
43
  end
44
44
  end
@@ -4,28 +4,36 @@ require 'twisty_puzzles/cube_direction'
4
4
  require 'twisty_puzzles/rotation'
5
5
 
6
6
  module TwistyPuzzles
7
- AlgorithmTransformation =
8
- Struct.new(:rotation, :mirror, :mirror_normal_face) do
9
- def transformed(algorithm)
10
- algorithm = algorithm.mirror(mirror_normal_face) if mirror
11
- algorithm.rotate_by(rotation)
12
- end
7
+ # A transformation consisting of mirroring and rotating that can be applied to an algorithm.
8
+ class AlgorithmTransformation
9
+ def initialize(rotation, mirror, mirror_normal_face)
10
+ @rotation = rotation
11
+ @mirror = mirror
12
+ @mirror_normal_face = mirror_normal_face
13
+ end
13
14
 
14
- def identity?
15
- rotation.identity? && !mirror
16
- end
15
+ attr_reader :rotation, :mirror, :mirror_normal_face
17
16
 
18
- # Returns algorithm transformations that mirror an algorithm and rotate it around a face.
19
- def self.around_face(face)
20
- around_face_rotations = CubeDirection::ALL_DIRECTIONS.map { |d| Rotation.new(face, d) }
21
- mirror_normal_face = face.neighbors.first
22
- around_face_rotations.product([true, false]).map do |r, m|
23
- AlgorithmTransformation.new(r, m, mirror_normal_face)
24
- end
25
- end
17
+ def transformed(algorithm)
18
+ algorithm = algorithm.mirror(mirror_normal_face) if mirror
19
+ algorithm.rotate_by(rotation)
20
+ end
26
21
 
27
- def self.around_face_without_identity(face)
28
- around_face(face).reject(&:identity?)
22
+ def identity?
23
+ rotation.identity? && !mirror
24
+ end
25
+
26
+ # Returns algorithm transformations that mirror an algorithm and rotate it around a face.
27
+ def self.around_face(face)
28
+ around_face_rotations = CubeDirection::ALL_DIRECTIONS.map { |d| Rotation.new(face, d) }
29
+ mirror_normal_face = face.neighbors.first
30
+ around_face_rotations.product([true, false]).map do |r, m|
31
+ AlgorithmTransformation.new(r, m, mirror_normal_face)
29
32
  end
30
33
  end
34
+
35
+ def self.around_face_without_identity(face)
36
+ around_face(face).reject(&:identity?)
37
+ end
38
+ end
31
39
  end
@@ -55,7 +55,9 @@ module TwistyPuzzles
55
55
  self
56
56
  else
57
57
  rotation_neighbors = rotation.axis_face.neighbors
58
- face_index = rotation_neighbors.index(@axis_face) || raise
58
+ face_index = rotation_neighbors.index(@axis_face)
59
+ raise unless face_index
60
+
59
61
  new_axis_face =
60
62
  rotation_neighbors[(face_index + rotation.direction.value) % rotation_neighbors.length]
61
63
  fields = replace_once(identifying_fields, @axis_face, new_axis_face)
@@ -37,7 +37,7 @@ module TwistyPuzzles
37
37
  end
38
38
 
39
39
  def part_for_colors(part_type, colors)
40
- raise ArgumentError unless part_type.is_a?(Class)
40
+ raise ArgumentError unless part_type.is_a?(Class) && (part_type < Part)
41
41
 
42
42
  part_type.for_face_symbols(colors.map { |c| face_symbol(c) })
43
43
  end
@@ -95,10 +95,12 @@ module TwistyPuzzles
95
95
 
96
96
  def chirality_corner_source_and_unknown_index(obvious_turned_face_symbols_to_colors)
97
97
  corner_matcher =
98
- CornerMatcher.new(CHIRALITY_FACE_SYMBOLS.map do |s|
99
- # This will return nil for exactly one face that we don't know yet.
100
- @colors_to_face_symbols[obvious_turned_face_symbols_to_colors[s]]
101
- end)
98
+ CornerMatcher.new(
99
+ CHIRALITY_FACE_SYMBOLS.map do |s|
100
+ # This will return nil for exactly one face that we don't know yet.
101
+ @colors_to_face_symbols[obvious_turned_face_symbols_to_colors[s]]
102
+ end
103
+ )
102
104
 
103
105
  # There should be exactly one corner that gets mapped to the chirality corner.
104
106
  chirality_corner_source =
@@ -141,7 +143,7 @@ module TwistyPuzzles
141
143
  "Color #{c} cannot be part of the color scheme because it is a reserved color."
142
144
  end
143
145
  end
144
- raise ArgumentError unless face_symbols_to_colors.values.all? { |c| c.is_a?(Symbol) }
146
+ raise ArgumentError unless face_symbols_to_colors.values.all?(Symbol)
145
147
  end
146
148
 
147
149
  def add_missing_mappings(turned_face_symbols_to_colors, chirality_corner_source, unknown_index)
@@ -10,6 +10,10 @@ module TwistyPuzzles
10
10
  def cancellations(other, cube_size, metric = :htm)
11
11
  algorithm.cancellations(other.algorithm, cube_size, metric)
12
12
  end
13
+
14
+ def algorithm
15
+ raise NotImplementedError
16
+ end
13
17
  end
14
18
 
15
19
  # Algorithm that is used like a commutator but actually isn't one.
@@ -6,6 +6,7 @@ require 'twisty_puzzles/native'
6
6
 
7
7
  module TwistyPuzzles
8
8
  # Coordinate of a sticker on the cube.
9
+ # rubocop:disable Metrics/ClassLength
9
10
  class Coordinate
10
11
  def self.highest_coordinate(cube_size)
11
12
  cube_size - 1
@@ -121,6 +122,23 @@ module TwistyPuzzles
121
122
  from_indices(face, cube_size, m, m)
122
123
  end
123
124
 
125
+ def self.face(face, cube_size)
126
+ neighbor_a, neighbor_b = face.neighbors[0..1]
127
+ coordinate_range(cube_size).collect_concat do |x|
128
+ coordinate_range(cube_size).map do |y|
129
+ from_face_distances(face, cube_size, neighbor_a => x, neighbor_b => y)
130
+ end
131
+ end
132
+ end
133
+
134
+ def self.layer(face, cube_size)
135
+ face.neighbors.zip(face.neighbors.rotate(1)).collect_concat do |neighbor, next_neighbor|
136
+ coordinate_range(cube_size).map do |i|
137
+ from_face_distances(neighbor, cube_size, face => 0, next_neighbor => i)
138
+ end
139
+ end + self.face(face, cube_size)
140
+ end
141
+
124
142
  def self.edges_outside(face, cube_size)
125
143
  face.neighbors.zip(face.neighbors.rotate(1)).collect_concat do |neighbor, next_neighbor|
126
144
  1.upto(cube_size - 2).map do |i|
@@ -261,6 +279,7 @@ module TwistyPuzzles
261
279
  rots
262
280
  end
263
281
  end
282
+ # rubocop:enable Metrics/ClassLength
264
283
 
265
284
  # Coordinate of a sticker on the Skewb.
266
285
  class SkewbCoordinate
@@ -64,10 +64,18 @@ module TwistyPuzzles
64
64
  true
65
65
  end
66
66
 
67
+ def num_incarnations(_cube_size)
68
+ 1
69
+ end
70
+
67
71
  def base_index_on_face(cube_size, incarnation_index)
68
72
  base_index_on_other_face(solved_face, cube_size, incarnation_index)
69
73
  end
70
74
 
75
+ def base_index_on_other_face(face, cube_size, incarnation_index)
76
+ raise NotImplementedError
77
+ end
78
+
71
79
  def self.for_face_symbols_internal(face_symbols)
72
80
  raise unless face_symbols.length == self::FACES
73
81
 
@@ -82,6 +90,10 @@ module TwistyPuzzles
82
90
  self::ELEMENTS[index]
83
91
  end
84
92
 
93
+ def self.valid?(_face_symbols)
94
+ false
95
+ end
96
+
85
97
  def <=>(other)
86
98
  @piece_index <=> other.piece_index
87
99
  end
@@ -110,7 +122,7 @@ module TwistyPuzzles
110
122
  # Rotate a piece such that the given face symbol is the first face symbol.
111
123
  def rotate_face_symbol_up(face_symbol)
112
124
  index = @face_symbols.index(face_symbol)
113
- raise "Part #{self} doesn't have face symbol #{c}." unless index
125
+ raise "Part #{self} doesn't have face symbol #{face_symbol}." unless index
114
126
 
115
127
  rotate_by(index)
116
128
  end
@@ -133,10 +145,6 @@ module TwistyPuzzles
133
145
  (0...@face_symbols.length).map { |i| rotate_by(i) }
134
146
  end
135
147
 
136
- def self.create_for_face_symbols(face_symbols)
137
- new(face_symbols)
138
- end
139
-
140
148
  def self.parse(piece_description)
141
149
  face_symbols =
142
150
  piece_description.upcase.strip.split('').map do |e|
@@ -338,10 +346,6 @@ module TwistyPuzzles
338
346
  find_only(self::ELEMENTS) { |e| e.corresponding_part == corresponding_part }
339
347
  end
340
348
 
341
- def self.create_for_face_symbols(face_symbols)
342
- new(self::CORRESPONDING_PART_CLASS.create_for_face_symbols(face_symbols))
343
- end
344
-
345
349
  def face_symbol
346
350
  @face_symbols[0]
347
351
  end
@@ -514,7 +518,7 @@ module TwistyPuzzles
514
518
  end
515
519
 
516
520
  def num_incarnations(cube_size)
517
- [cube_size / 2 - 1, 0].max
521
+ cube_size > 3 ? cube_size / 2 - 1 : 0
518
522
  end
519
523
 
520
524
  # One index of such a piece on a on a NxN face.
@@ -530,14 +534,6 @@ module TwistyPuzzles
530
534
  class Corner < Part
531
535
  FACES = 3
532
536
 
533
- def self.create_for_face_symbols(face_symbols)
534
- piece_candidates =
535
- face_symbols[1..].permutation.map do |cs|
536
- new([face_symbols[0]] + cs)
537
- end
538
- find_only(piece_candidates, &:valid?)
539
- end
540
-
541
537
  def self.for_face_symbols(face_symbols)
542
538
  unless face_symbols.length == FACES
543
539
  raise "Invalid number of face_symbols to create a corner: #{face_symbols.inspect}"
@@ -621,7 +617,7 @@ module TwistyPuzzles
621
617
  ELEMENTS = generate_parts
622
618
 
623
619
  def num_incarnations(cube_size)
624
- [cube_size / 2 - 1, 0].max
620
+ cube_size > 3 ? cube_size / 2 - 1 : 0
625
621
  end
626
622
 
627
623
  # One index of such a piece on a on a NxN face.
@@ -644,10 +640,10 @@ module TwistyPuzzles
644
640
  end
645
641
 
646
642
  def num_incarnations(cube_size)
647
- if cube_size.even?
643
+ if cube_size.even? || cube_size <= 3
648
644
  0
649
645
  else
650
- [cube_size / 2 - 1, 0].max
646
+ cube_size / 2 - 1
651
647
  end
652
648
  end
653
649
 
@@ -75,6 +75,16 @@ module TwistyPuzzles
75
75
 
76
76
  alias == eql?
77
77
 
78
+ def rotation_algorithms
79
+ Rotation::ALL_ROTATIONS.combination(2).reject do |r0, r1|
80
+ r0.inverse == r1
81
+ end.map { |rs| Algorithm.new(rs) } # rubocop:disable Style/MultilineBlockChain
82
+ end
83
+
84
+ def equal_modulo_rotations?(other)
85
+ rotation_algorithms.any? { |r| r.apply_temporarily_to(self) { |state| state == other } }
86
+ end
87
+
78
88
  def hash
79
89
  @hash ||= [self.class, @native].hash
80
90
  end
@@ -6,7 +6,7 @@ module TwistyPuzzles
6
6
  class MoveTypeCreator
7
7
  def initialize(capture_keys, move_class)
8
8
  raise TypeError unless move_class.is_a?(Class)
9
- raise TypeError unless capture_keys.all? { |k| k.is_a?(Symbol) }
9
+ raise TypeError unless capture_keys.all?(Symbol)
10
10
 
11
11
  @capture_keys = capture_keys.freeze
12
12
  @move_class = move_class
@@ -35,10 +35,12 @@ module TwistyPuzzles
35
35
 
36
36
  direction = translated_direction(skewb_direction)
37
37
 
38
- Algorithm.new([
39
- Rotation.new(corner.faces[skewb_direction.value], direction),
40
- Rotation.new(corner.faces[0], direction)
41
- ])
38
+ Algorithm.new(
39
+ [
40
+ Rotation.new(corner.faces[skewb_direction.value], direction),
41
+ Rotation.new(corner.faces[0], direction)
42
+ ]
43
+ )
42
44
  end
43
45
 
44
46
  def to_s
@@ -26,10 +26,12 @@ module TwistyPuzzles
26
26
  next unless c2.face_symbols.include?(c1_rot.face_symbols.first)
27
27
 
28
28
  c2_rot = c2.rotate_face_symbol_up(c1_rot.face_symbols.first)
29
- check_parts.push([
30
- SkewbCoordinate.for_corner(c1_rot),
31
- SkewbCoordinate.for_corner(c2_rot)
32
- ])
29
+ check_parts.push(
30
+ [
31
+ SkewbCoordinate.for_corner(c1_rot),
32
+ SkewbCoordinate.for_corner(c2_rot)
33
+ ]
34
+ )
33
35
  end
34
36
  matching_corners.push(check_parts)
35
37
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwistyPuzzles
4
- VERSION = '0.0.6'
4
+ VERSION = '0.0.11'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twisty_puzzles
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard F. Brodowsky
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-21 00:00:00.000000000 Z
11
+ date: 2021-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -164,7 +164,7 @@ dependencies:
164
164
  - - ">="
165
165
  - !ruby/object:Gem::Version
166
166
  version: '0'
167
- description:
167
+ description:
168
168
  email: bernhard.brodowsky@gmail.com
169
169
  executables: []
170
170
  extensions:
@@ -245,7 +245,7 @@ metadata:
245
245
  homepage_uri: https://github.com/Lykos/twisty_puzzles
246
246
  source_code_uri: https://github.com/Lykos/twisty_puzzles
247
247
  changelog_uri: https://github.com/Lykos/twisty_puzzles/blob/master/CHANGELOG.md
248
- post_install_message:
248
+ post_install_message:
249
249
  rdoc_options: []
250
250
  require_paths:
251
251
  - lib
@@ -253,15 +253,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
253
253
  requirements:
254
254
  - - ">="
255
255
  - !ruby/object:Gem::Version
256
- version: 2.6.0
256
+ version: 3.0.0
257
257
  required_rubygems_version: !ruby/object:Gem::Requirement
258
258
  requirements:
259
259
  - - ">="
260
260
  - !ruby/object:Gem::Version
261
261
  version: '0'
262
262
  requirements: []
263
- rubygems_version: 3.1.2
264
- signing_key:
263
+ rubygems_version: 3.2.3
264
+ signing_key:
265
265
  specification_version: 4
266
266
  summary: Gem for my cube_trainer rails app. Some things are better left in a separate
267
267
  gem with no rails, e.g. native extensions. The main purpose is to support my Rails