twisty_puzzles 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ void init_cube_average_class_under(VALUE module);
@@ -0,0 +1,207 @@
1
+ #include "cube_coordinate.h"
2
+
3
+ #include <stdio.h>
4
+
5
+ static VALUE CubeCoordinateClass = Qnil;
6
+
7
+ typedef struct {
8
+ size_t cube_size;
9
+ face_index_t on_face_index;
10
+ Point point;
11
+ } CubeCoordinateData;
12
+
13
+ static size_t CubeCoordinateData_size(const void* const ptr) {
14
+ return sizeof(CubeCoordinateData);
15
+ }
16
+
17
+ const rb_data_type_t CubeCoordinateData_type = {
18
+ "TwistyPuzzles::Native::CubeCoordinateData",
19
+ {NULL, NULL, CubeCoordinateData_size, NULL},
20
+ NULL, NULL,
21
+ RUBY_TYPED_FREE_IMMEDIATELY
22
+ };
23
+
24
+ #define GetCubeCoordinateData(obj, data) \
25
+ do { \
26
+ TypedData_Get_Struct((obj), CubeCoordinateData, &CubeCoordinateData_type, (data)); \
27
+ } while (0)
28
+
29
+ size_t num_stickers(const size_t cube_size) {
30
+ return cube_faces * cube_size * cube_size;
31
+ }
32
+
33
+ size_t sticker_index(const size_t cube_size, const face_index_t on_face_index, const Point point) {
34
+ return on_face_index * cube_size * cube_size + point.y * cube_size + point.x;
35
+ }
36
+
37
+ size_t CubeCoordinate_sticker_index(const VALUE self, const size_t cube_size) {
38
+ CubeCoordinateData* data;
39
+ GetCubeCoordinateData(self, data);
40
+ if (data->cube_size != cube_size) {
41
+ rb_raise(rb_eArgError, "Cannot use coordinate for cube size %ld on a %ldx%ld cube.", data->cube_size, cube_size, cube_size);
42
+ }
43
+ return sticker_index(cube_size, data->on_face_index, data->point);
44
+ }
45
+
46
+ static VALUE CubeCoordinate_alloc(const VALUE klass) {
47
+ CubeCoordinateData* data;
48
+ const VALUE object = TypedData_Make_Struct(klass, CubeCoordinateData, &CubeCoordinateData_type, data);
49
+ data->cube_size = 0;
50
+ data->on_face_index = 0;
51
+ data->point.x = 0;
52
+ data->point.y = 0;
53
+ return object;
54
+ }
55
+
56
+ static size_t inverted_index(const size_t cube_size, const size_t index) {
57
+ return cube_size - 1 - index;
58
+ }
59
+
60
+ size_t transform_index(const face_index_t index_base_face_index, const size_t cube_size, const size_t index) {
61
+ if (index_base_face_index == axis_index(index_base_face_index)) {
62
+ return index;
63
+ } else {
64
+ return inverted_index(cube_size, index);
65
+ }
66
+ }
67
+
68
+ bool switch_axes(const face_index_t x_base_face_index, const face_index_t y_base_face_index) {
69
+ return axis_index(x_base_face_index) > axis_index(y_base_face_index);
70
+ }
71
+
72
+ void check_base_face_indices(const face_index_t on_face_index,
73
+ const face_index_t x_base_face_index,
74
+ const face_index_t y_base_face_index) {
75
+ if (axis_index(x_base_face_index) == axis_index(on_face_index)) {
76
+ rb_raise(rb_eArgError, "Invalid value for x_base_face_symbol.");
77
+ }
78
+ if (axis_index(y_base_face_index) == axis_index(on_face_index)) {
79
+ rb_raise(rb_eArgError, "Invalid value for y_base_face_symbol.");
80
+ }
81
+ if (axis_index(x_base_face_index) == axis_index(y_base_face_index)) {
82
+ rb_raise(rb_eArgError, "Incompatible values for x_base_face_symbol and y_base_face_symbol.");
83
+ }
84
+ }
85
+
86
+ Point point_on_face(const face_index_t face_index,
87
+ const face_index_t x_base_face_index,
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);
94
+ Point point;
95
+ if (switch_axes(x_base_face_index, y_base_face_index)) {
96
+ point.x = transformed_y;
97
+ point.y = transformed_x;
98
+ } else {
99
+ point.x = transformed_x;
100
+ point.y = transformed_y;
101
+ }
102
+ return point;
103
+ }
104
+
105
+ static void check_cube_index(const size_t cube_size, const size_t index) {
106
+ if (index < 0 || index >= cube_size) {
107
+ rb_raise(rb_eArgError, "Invalid value %ld for x with cube size %ld.", index, cube_size);
108
+ }
109
+ }
110
+
111
+ static VALUE CubeCoordinate_initialize(const VALUE self,
112
+ const VALUE cube_size,
113
+ const VALUE face_symbol,
114
+ const VALUE x_base_face_symbol,
115
+ const VALUE y_base_face_symbol,
116
+ const VALUE x_num,
117
+ const VALUE y_num) {
118
+ Check_Type(cube_size, T_FIXNUM);
119
+ Check_Type(face_symbol, T_SYMBOL);
120
+ Check_Type(x_base_face_symbol, T_SYMBOL);
121
+ Check_Type(y_base_face_symbol, T_SYMBOL);
122
+ Check_Type(x_num, T_FIXNUM);
123
+ Check_Type(y_num, T_FIXNUM);
124
+ const size_t n = FIX2INT(cube_size);
125
+ const face_index_t on_face_index = face_index(face_symbol);
126
+ const face_index_t x_base_face_index = face_index(x_base_face_symbol);
127
+ const face_index_t y_base_face_index = face_index(y_base_face_symbol);
128
+ 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
+ check_cube_index(n, untransformed_x);
131
+ const size_t untransformed_y = FIX2INT(y_num);
132
+ check_cube_index(n, untransformed_y);
133
+ const Point point = point_on_face(on_face_index, x_base_face_index, y_base_face_index, n, untransformed_x, untransformed_y);
134
+ CubeCoordinateData* data;
135
+ GetCubeCoordinateData(self, data);
136
+ data->cube_size = n;
137
+ data->on_face_index = on_face_index;
138
+ data->point = point;
139
+ return self;
140
+ }
141
+
142
+ static VALUE CubeCoordinate_hash(const VALUE self) {
143
+ const CubeCoordinateData* data;
144
+ GetCubeCoordinateData(self, data);
145
+
146
+ st_index_t hash = rb_hash_start((st_index_t)CubeCoordinate_hash);
147
+ hash = rb_hash_uint(hash, data->cube_size);
148
+ hash = rb_hash_uint(hash, data->on_face_index);
149
+ hash = rb_hash_uint(hash, data->point.x);
150
+ hash = rb_hash_uint(hash, data->point.y);
151
+ return ST2FIX(rb_hash_end(hash));
152
+ }
153
+
154
+ static VALUE CubeCoordinate_eql(const VALUE self, const VALUE other) {
155
+ if (self == other) {
156
+ return Qtrue;
157
+ }
158
+ if (rb_obj_class(self) != rb_obj_class(other)) {
159
+ return Qfalse;
160
+ }
161
+ const CubeCoordinateData* self_data;
162
+ GetCubeCoordinateData(self, self_data);
163
+ const CubeCoordinateData* other_data;
164
+ GetCubeCoordinateData(other, other_data);
165
+ if (self_data->cube_size == other_data->cube_size &&
166
+ self_data->on_face_index == other_data->on_face_index &&
167
+ self_data->point.x == other_data->point.x &&
168
+ self_data->point.y == other_data->point.y) {
169
+ return Qtrue;
170
+ } else {
171
+ return Qfalse;
172
+ }
173
+ }
174
+
175
+ static VALUE CubeCoordinate_cube_size(const VALUE self) {
176
+ const CubeCoordinateData* data;
177
+ GetCubeCoordinateData(self, data);
178
+ return INT2NUM(data->cube_size);
179
+ }
180
+
181
+ static VALUE CubeCoordinate_face(const VALUE self) {
182
+ const CubeCoordinateData* data;
183
+ GetCubeCoordinateData(self, data);
184
+ return face_symbol(data->on_face_index);
185
+ }
186
+
187
+ static VALUE CubeCoordinate_coordinate(const VALUE self, const VALUE index_base_face_symbol) {
188
+ const CubeCoordinateData* data;
189
+ GetCubeCoordinateData(self, data);
190
+ const face_index_t index_base_face_index = face_index(index_base_face_symbol);
191
+ // Make use of the fact that 0 + 1 + 2 = 3
192
+ const face_index_t third_face_index = 3 - axis_index(data->on_face_index) - axis_index(index_base_face_index);
193
+ const size_t index = switch_axes(index_base_face_index, third_face_index) ? data->point.y : data->point.x;
194
+ return INT2NUM(transform_index(index_base_face_index, data->cube_size, index));
195
+ }
196
+
197
+ void init_cube_coordinate_class_under(const VALUE module) {
198
+ CubeCoordinateClass = rb_define_class_under(module, "CubeCoordinate", rb_cObject);
199
+ rb_define_alloc_func(CubeCoordinateClass, CubeCoordinate_alloc);
200
+ rb_define_method(CubeCoordinateClass, "initialize", CubeCoordinate_initialize, 6);
201
+ rb_define_method(CubeCoordinateClass, "hash", CubeCoordinate_hash, 0);
202
+ rb_define_method(CubeCoordinateClass, "eql?", CubeCoordinate_eql, 1);
203
+ rb_define_alias(CubeCoordinateClass, "==", "eql?");
204
+ rb_define_method(CubeCoordinateClass, "cube_size", CubeCoordinate_cube_size, 0);
205
+ rb_define_method(CubeCoordinateClass, "face", CubeCoordinate_face, 0);
206
+ rb_define_method(CubeCoordinateClass, "coordinate", CubeCoordinate_coordinate, 1);
207
+ }
@@ -0,0 +1,34 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ #include "face_symbols.h"
6
+ #include "utils.h"
7
+
8
+ size_t num_stickers(size_t cube_size);
9
+
10
+ typedef struct {
11
+ size_t x;
12
+ size_t y;
13
+ } Point;
14
+
15
+ size_t sticker_index(size_t cube_size, face_index_t on_face_index, Point point);
16
+
17
+ size_t transform_index(face_index_t index_base_face_index, size_t cube_size, size_t index);
18
+
19
+ bool switch_axes(face_index_t x_base_face_index, face_index_t y_base_face_index);
20
+
21
+ void check_base_face_indices(face_index_t on_face_index,
22
+ face_index_t x_base_face_index,
23
+ face_index_t y_base_face_index);
24
+
25
+ Point point_on_face(face_index_t on_face_index,
26
+ face_index_t x_base_face_index,
27
+ face_index_t y_base_face_index,
28
+ size_t cube_size,
29
+ size_t untransformed_x,
30
+ size_t untransformed_y);
31
+
32
+ size_t CubeCoordinate_sticker_index(VALUE self, size_t cube_size);
33
+
34
+ void init_cube_coordinate_class_under(VALUE module);
@@ -0,0 +1,264 @@
1
+ #include "cube_state.h"
2
+
3
+ #include <stdio.h>
4
+
5
+ #include "cube_coordinate.h"
6
+ #include "utils.h"
7
+
8
+ static ID stickers_id = 0;
9
+ static ID x_base_face_symbol_id = 0;
10
+ static ID y_base_face_symbol_id = 0;
11
+ static VALUE CubeStateClass = Qnil;
12
+
13
+ static void CubeStateData_mark(void* const ptr) {
14
+ const CubeStateData* data = ptr;
15
+ const size_t n = data->cube_size;
16
+ for (size_t i = 0; i < num_stickers(n); ++i) {
17
+ rb_gc_mark(data->stickers[i]);
18
+ }
19
+ }
20
+
21
+ static void CubeStateData_free(void* const ptr) {
22
+ const CubeStateData* const data = ptr;
23
+ free(data->stickers);
24
+ free(ptr);
25
+ }
26
+
27
+ static size_t CubeStateData_size(const void* const ptr) {
28
+ const CubeStateData* const data = ptr;
29
+ return sizeof(CubeStateData) + num_stickers(data->cube_size) * sizeof(VALUE);
30
+ }
31
+
32
+ const rb_data_type_t CubeStateData_type = {
33
+ "TwistyPuzzles::Native::CubeStateData",
34
+ {CubeStateData_mark, CubeStateData_free, CubeStateData_size, NULL},
35
+ NULL, NULL,
36
+ RUBY_TYPED_FREE_IMMEDIATELY
37
+ };
38
+
39
+ static VALUE* malloc_stickers(const size_t n) {
40
+ VALUE* const stickers = malloc(num_stickers(n) * sizeof(VALUE));
41
+ if (stickers == NULL) {
42
+ rb_raise(rb_eNoMemError, "Allocating cube state failed.");
43
+ }
44
+ return stickers;
45
+ }
46
+
47
+ static VALUE CubeState_alloc(const VALUE klass) {
48
+ CubeStateData* data;
49
+ const VALUE object = TypedData_Make_Struct(klass, CubeStateData, &CubeStateData_type, data);
50
+ data->cube_size = 0;
51
+ data->stickers = NULL;
52
+ return object;
53
+ }
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
+ static int CubeState_replace_face(const VALUE key, const VALUE value, const VALUE self) {
65
+ const CubeStateData* data;
66
+ GetInitializedCubeStateData(self, data);
67
+ const size_t n = data->cube_size;
68
+ Check_Type(value, T_HASH);
69
+ if (RHASH_SIZE(value) != 3) {
70
+ rb_raise(rb_eTypeError, "Cube faces must have 3 entries, got %ld.", RHASH_SIZE(value));
71
+ }
72
+ const face_index_t on_face_index = face_index(key);
73
+ // Caching these keys isn't easy because the garbage collector will get them.
74
+ const VALUE stickers = rb_hash_aref(value, ID2SYM(stickers_id));
75
+ if (stickers == Qnil) {
76
+ rb_raise(rb_eTypeError, "Cube faces must have a key called :stickers that contains the stickers on that face.");
77
+ }
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
+ Check_Type(stickers, T_ARRAY);
81
+ if (RARRAY_LEN(stickers) != n) {
82
+ 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
+ }
84
+ for (size_t y = 0; y < n; ++y) {
85
+ const VALUE row = rb_ary_entry(stickers, y);
86
+ Check_Type(row, T_ARRAY);
87
+ if (RARRAY_LEN(row) != n) {
88
+ 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
+ }
90
+ for (size_t x = 0; x < n; ++x) {
91
+ const VALUE cell = rb_ary_entry(row, x);
92
+ Point point = {x, y};
93
+ data->stickers[sticker_index(n, on_face_index, point)] = cell;
94
+ }
95
+ }
96
+ return ST_CONTINUE;
97
+ }
98
+
99
+ static VALUE CubeState_initialize(const VALUE self, const VALUE cube_size, const VALUE stickers) {
100
+ Check_Type(cube_size, T_FIXNUM);
101
+ Check_Type(stickers, T_HASH);
102
+ const size_t n = FIX2INT(cube_size);
103
+ CubeStateData* data;
104
+ GetCubeStateData(self, data);
105
+ data->cube_size = n;
106
+ data->stickers = malloc_stickers(n);
107
+ for (size_t i = 0; i < num_stickers(n); ++i) {
108
+ data->stickers[i] = Qnil;
109
+ }
110
+ if (RHASH_SIZE(stickers) != cube_faces) {
111
+ rb_raise(rb_eTypeError, "Cubes must have %d faces. Got %ld.", cube_faces, RHASH_SIZE(stickers));
112
+ }
113
+ rb_hash_foreach(stickers, CubeState_replace_face, self);
114
+ return self;
115
+ }
116
+
117
+ static VALUE CubeState_sticker_array(const VALUE self,
118
+ const VALUE on_face_symbol,
119
+ const VALUE x_base_face_symbol,
120
+ const VALUE y_base_face_symbol) {
121
+ Check_Type(on_face_symbol, T_SYMBOL);
122
+ Check_Type(x_base_face_symbol, T_SYMBOL);
123
+ Check_Type(y_base_face_symbol, T_SYMBOL);
124
+ const face_index_t on_face_index = face_index(on_face_symbol);
125
+ const face_index_t x_base_face_index = face_index(x_base_face_symbol);
126
+ const face_index_t y_base_face_index = face_index(y_base_face_symbol);
127
+ check_base_face_indices(on_face_index, x_base_face_index, y_base_face_index);
128
+ const CubeStateData* data;
129
+ GetInitializedCubeStateData(self, data);
130
+ const size_t n = data->cube_size;
131
+ const VALUE face = rb_ary_new2(n);
132
+ for (size_t y = 0; y < n; ++y) {
133
+ const VALUE row = rb_ary_new2(n);
134
+ for (size_t x = 0; x < n; ++x) {
135
+ const Point point = point_on_face(on_face_index, x_base_face_index, y_base_face_index, n, x, y);
136
+ const VALUE cell = data->stickers[sticker_index(n, on_face_index, point)];
137
+ rb_ary_store(row, x, cell);
138
+ }
139
+ rb_ary_store(face, y, row);
140
+ }
141
+ return face;
142
+ }
143
+
144
+ static VALUE CubeState_entry(const VALUE self, const VALUE coordinate) {
145
+ const CubeStateData* data;
146
+ GetInitializedCubeStateData(self, data);
147
+ return data->stickers[CubeCoordinate_sticker_index(coordinate, data->cube_size)];
148
+ }
149
+
150
+ static VALUE CubeState_store(const VALUE self, const VALUE coordinate, const VALUE value) {
151
+ const CubeStateData* data;
152
+ GetInitializedCubeStateData(self, data);
153
+ return data->stickers[CubeCoordinate_sticker_index(coordinate, data->cube_size)] = value;
154
+ }
155
+
156
+ static VALUE CubeState_hash(const VALUE self) {
157
+ const CubeStateData* data;
158
+ GetInitializedCubeStateData(self, data);
159
+
160
+ st_index_t hash = rb_hash_start(data->cube_size);
161
+ hash = rb_hash_uint(hash, (st_index_t)CubeState_hash);
162
+ const size_t n = data->cube_size;
163
+ for (size_t i = 0; i < num_stickers(n); i++) {
164
+ const VALUE sub_hash = rb_hash(data->stickers[i]);
165
+ hash = rb_hash_uint(hash, NUM2LONG(sub_hash));
166
+ }
167
+ return ST2FIX(rb_hash_end(hash));
168
+ }
169
+
170
+ static VALUE CubeState_eql(const VALUE self, const VALUE other) {
171
+ if (self == other) {
172
+ return Qtrue;
173
+ }
174
+ if (rb_obj_class(self) != rb_obj_class(other)) {
175
+ return Qfalse;
176
+ }
177
+ const CubeStateData* self_data;
178
+ GetInitializedCubeStateData(self, self_data);
179
+ const CubeStateData* other_data;
180
+ GetInitializedCubeStateData(other, other_data);
181
+ if (self_data->cube_size != other_data->cube_size) {
182
+ return Qfalse;
183
+ }
184
+ const size_t n = self_data->cube_size;
185
+ for (size_t i = 0; i < num_stickers(n); ++i) {
186
+ if (!color_eq(self_data->stickers[i], other_data->stickers[i])) {
187
+ return Qfalse;
188
+ }
189
+ }
190
+ return Qtrue;
191
+ }
192
+
193
+ static VALUE CubeState_dup(const VALUE self) {
194
+ const CubeStateData* data;
195
+ GetInitializedCubeStateData(self, data);
196
+ const size_t n = data->cube_size;
197
+ CubeStateData* dupped_data;
198
+ const VALUE dupped = TypedData_Make_Struct(rb_obj_class(self), CubeStateData, &CubeStateData_type, dupped_data);
199
+ dupped_data->cube_size = n;
200
+ dupped_data->stickers = malloc_stickers(n);
201
+ memcpy(dupped_data->stickers, data->stickers, num_stickers(n) * sizeof(VALUE));
202
+ return dupped;
203
+ }
204
+
205
+ static VALUE CubeState_cube_size(const VALUE self) {
206
+ const CubeStateData* data;
207
+ GetInitializedCubeStateData(self, data);
208
+ return ST2FIX(data->cube_size);
209
+ }
210
+
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) {
212
+ direction = CROP_MOD(direction, 4);
213
+ if (direction == 0) {
214
+ return;
215
+ }
216
+ const size_t n = data->cube_size;
217
+ for (size_t i = 0; i < n; ++i) {
218
+ 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);
224
+ }
225
+ apply_sticker_4cycle(data->stickers, cycle, direction);
226
+ }
227
+ }
228
+
229
+ void rotate_face_for_cube(const face_index_t turned_face_index, direction_t direction, const CubeStateData* const data) {
230
+ direction = CROP_MOD(direction, 4);
231
+ if (direction == 0) {
232
+ return;
233
+ }
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) {
237
+ Sticker4Cycle cycle;
238
+ for (size_t j = 0; j < neighbor_faces; ++j) {
239
+ const face_index_t x_face_index = neighbor_face_index(turned_face_index, j);
240
+ const face_index_t y_face_index = neighbor_face_index(turned_face_index, j + 1);
241
+ const Point point = point_on_face(turned_face_index, x_face_index, y_face_index, n, x, y);
242
+ cycle.indices[j] = sticker_index(n, turned_face_index, point);
243
+ }
244
+ apply_sticker_4cycle(data->stickers, cycle, direction);
245
+ }
246
+ }
247
+ }
248
+
249
+ void init_cube_state_class_under(const VALUE module) {
250
+ stickers_id = rb_intern("stickers");
251
+ x_base_face_symbol_id = rb_intern("x_base_face_symbol");
252
+ y_base_face_symbol_id = rb_intern("y_base_face_symbol");
253
+ CubeStateClass = rb_define_class_under(module, "CubeState", rb_cObject);
254
+ rb_define_alloc_func(CubeStateClass, CubeState_alloc);
255
+ rb_define_method(CubeStateClass, "initialize", CubeState_initialize, 2);
256
+ rb_define_method(CubeStateClass, "[]", CubeState_entry, 1);
257
+ rb_define_method(CubeStateClass, "[]=", CubeState_store, 2);
258
+ rb_define_method(CubeStateClass, "sticker_array", CubeState_sticker_array, 3);
259
+ rb_define_method(CubeStateClass, "hash", CubeState_hash, 0);
260
+ rb_define_method(CubeStateClass, "eql?", CubeState_eql, 1);
261
+ rb_define_alias(CubeStateClass, "==", "eql?");
262
+ rb_define_method(CubeStateClass, "dup", CubeState_dup, 0);
263
+ rb_define_method(CubeStateClass, "cube_size", CubeState_cube_size, 0);
264
+ }