twisty_puzzles 0.0.2 → 0.0.3

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.
@@ -0,0 +1,5 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ void init_skewb_layer_fingerprint_method_under(VALUE module);
@@ -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);
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwistyPuzzles
4
- VERSION = '0.0.2'
4
+ VERSION = '0.0.3'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twisty_puzzles
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard F. Brodowsky
@@ -176,7 +176,28 @@ files:
176
176
  - CODE_OF_CONDUCT.md
177
177
  - LICENSE
178
178
  - README.md
179
+ - ext/twisty_puzzles/native/cube_algorithm.c
180
+ - ext/twisty_puzzles/native/cube_algorithm.h
181
+ - ext/twisty_puzzles/native/cube_average.c
182
+ - ext/twisty_puzzles/native/cube_average.h
183
+ - ext/twisty_puzzles/native/cube_coordinate.c
184
+ - ext/twisty_puzzles/native/cube_coordinate.h
185
+ - ext/twisty_puzzles/native/cube_state.c
186
+ - ext/twisty_puzzles/native/cube_state.h
179
187
  - ext/twisty_puzzles/native/extconf.rb
188
+ - ext/twisty_puzzles/native/face_symbols.c
189
+ - ext/twisty_puzzles/native/face_symbols.h
190
+ - ext/twisty_puzzles/native/native.c
191
+ - ext/twisty_puzzles/native/skewb_algorithm.c
192
+ - ext/twisty_puzzles/native/skewb_algorithm.h
193
+ - ext/twisty_puzzles/native/skewb_coordinate.c
194
+ - ext/twisty_puzzles/native/skewb_coordinate.h
195
+ - ext/twisty_puzzles/native/skewb_layer_fingerprint.c
196
+ - ext/twisty_puzzles/native/skewb_layer_fingerprint.h
197
+ - ext/twisty_puzzles/native/skewb_state.c
198
+ - ext/twisty_puzzles/native/skewb_state.h
199
+ - ext/twisty_puzzles/native/utils.c
200
+ - ext/twisty_puzzles/native/utils.h
180
201
  - lib/twisty_puzzles.rb
181
202
  - lib/twisty_puzzles/abstract_direction.rb
182
203
  - lib/twisty_puzzles/abstract_move.rb