twisty_puzzles 0.0.17 → 0.0.19

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 440643127a42de2937ef3e1b0205f588a7d8624102dcf2596b3ff24050bf57ef
4
- data.tar.gz: 8ef01a9cd10f729ed5bbb0f34a36fe75b5fcff2d8c9ee6cc64d4b7faa72e44a1
3
+ metadata.gz: 64f6766819367eee6807388d640a4302c3268bcf276a2b52fb4ca94ddbb0ebe2
4
+ data.tar.gz: 0d60796788d180feb10ad42fa74a6b7535092d5d4040a64375f959ac9a2023da
5
5
  SHA512:
6
- metadata.gz: d247081d421f4b422293dc286e794cda52c04c9cb543d7ac62de8441f94117cbc028ecf7cff0a9c8100e57f1f7f87cfff0dfcfa8932e0fc60b7aa9409fd8d5df
7
- data.tar.gz: ff1043f40ba14d3993268b4768ddfc3e8ffc7e84830c21f106a7a64d7b55a774c1120ef880e71feba101ba0f4c48b8ec920711c25a187f93b3412c27bb096002
6
+ metadata.gz: 36cb5bdc5b75cfcb7d0a832cbff120662426ab8dd1fd1120762c3231973f27b706059f6772193ca76403859a3768d847f9ee34fb4012c52deb19226862b8b38c
7
+ data.tar.gz: 8e6a49720c6219484741a6d5d3248917c02025def3c0eacac34b0de07529b7fe42802fd5473fb782a19ca34f7bbc7319b8ef4ee705bffd135240f9d12f6eb77c
@@ -9,6 +9,7 @@
9
9
  #include "skewb_coordinate.h"
10
10
  #include "skewb_layer_fingerprint.h"
11
11
  #include "skewb_state.h"
12
+ #include "sticker_cycle.h"
12
13
 
13
14
  VALUE TwistyPuzzlesModule = Qnil;
14
15
  VALUE NativeModule = Qnil;
@@ -25,4 +26,5 @@ void Init_native() {
25
26
  init_skewb_coordinate_class_under(NativeModule);
26
27
  init_skewb_layer_fingerprint_method_under(NativeModule);
27
28
  init_skewb_state_class_under(NativeModule);
29
+ init_sticker_cycle_class_under(NativeModule);
28
30
  }
@@ -0,0 +1,196 @@
1
+ #include "cube_state.h"
2
+
3
+ #include "cube_coordinate.h"
4
+ #include "cube_state.h"
5
+ #include "utils.h"
6
+
7
+ static ID reverse;
8
+
9
+ typedef struct {
10
+ long cube_size;
11
+ size_t length;
12
+ VALUE coordinates;
13
+ size_t* indices;
14
+ } StickerCycleData;
15
+
16
+ extern const rb_data_type_t StickerCycleData_type;
17
+
18
+ #define GetStickerCycleData(obj, data) \
19
+ do { \
20
+ TypedData_Get_Struct((obj), StickerCycleData, &StickerCycleData_type, (data)); \
21
+ } while (0)
22
+
23
+ #define GetInitializedStickerCycleData(obj, data) \
24
+ do { \
25
+ GetStickerCycleData((obj), (data)); \
26
+ if (data->indices == NULL) { \
27
+ rb_raise(rb_eArgError, "Sticker cycle isn't initialized."); \
28
+ } \
29
+ } while(0)
30
+
31
+ static VALUE StickerCycleClass = Qnil;
32
+
33
+ static void StickerCycleData_mark(void* const ptr) {
34
+ const StickerCycleData* data = ptr;
35
+ rb_gc_mark(data->coordinates);
36
+ }
37
+
38
+ static void StickerCycleData_free(void* const ptr) {
39
+ const StickerCycleData* const data = ptr;
40
+ free(data->indices);
41
+ free(ptr);
42
+ }
43
+
44
+ static size_t StickerCycleData_size(const void* const ptr) {
45
+ const StickerCycleData* const data = ptr;
46
+ return sizeof(StickerCycleData) + num_stickers(data->cube_size) * sizeof(VALUE);
47
+ }
48
+
49
+ const rb_data_type_t StickerCycleData_type = {
50
+ "TwistyPuzzles::Native::StickerCycleData",
51
+ {StickerCycleData_mark, StickerCycleData_free, StickerCycleData_size, NULL},
52
+ NULL, NULL,
53
+ RUBY_TYPED_FREE_IMMEDIATELY
54
+ };
55
+
56
+ static VALUE* malloc_indices(const size_t n) {
57
+ VALUE* const indices = malloc(n * sizeof(size_t));
58
+ if (indices == NULL) {
59
+ rb_raise(rb_eNoMemError, "Allocating sticker cycle failed.");
60
+ }
61
+ return indices;
62
+ }
63
+
64
+ static VALUE StickerCycle_alloc(const VALUE klass) {
65
+ StickerCycleData* data;
66
+ const VALUE object = TypedData_Make_Struct(klass, StickerCycleData, &StickerCycleData_type, data);
67
+ data->cube_size = 0;
68
+ data->length = 0;
69
+ data->coordinates = Qnil;
70
+ data->indices = NULL;
71
+ return object;
72
+ }
73
+
74
+ static VALUE StickerCycle_initialize(const VALUE self, const VALUE cube_size, const VALUE coordinates) {
75
+ Check_Type(cube_size, T_FIXNUM);
76
+ Check_Type(coordinates, T_ARRAY);
77
+ const long checked_cube_size = FIX2INT(cube_size);
78
+ check_cube_size(checked_cube_size);
79
+ const size_t n = RARRAY_LEN(coordinates);
80
+ StickerCycleData* data;
81
+ GetStickerCycleData(self, data);
82
+ data->cube_size = checked_cube_size;
83
+ data->length = n;
84
+ data->coordinates = coordinates;
85
+ data->indices = malloc_indices(data->length);
86
+ for (size_t i = 0; i < n; ++i) {
87
+ const VALUE coordinate = rb_ary_entry(coordinates, i);
88
+ data->indices[i] = CubeCoordinate_sticker_index(coordinate, checked_cube_size);
89
+ }
90
+ return self;
91
+ }
92
+
93
+ static VALUE StickerCycle_apply_to(const VALUE self, const VALUE cube_state) {
94
+ const StickerCycleData* sticker_cycle_data;
95
+ GetInitializedStickerCycleData(self, sticker_cycle_data);
96
+
97
+ const CubeStateData* cube_state_data;
98
+ GetInitializedCubeStateData(cube_state, cube_state_data);
99
+
100
+ if (cube_state_data->cube_size != sticker_cycle_data->cube_size) {
101
+ rb_raise(rb_eArgError, "Cube size of sticker cycle must equal cube size of cube state. Got %ld vs %ld.", sticker_cycle_data->cube_size, cube_state_data->cube_size);
102
+ }
103
+ if (sticker_cycle_data->length >= 2) {
104
+ apply_sticker_cycle(cube_state_data->stickers, sticker_cycle_data->indices, sticker_cycle_data->length, false);
105
+ }
106
+ return Qnil;
107
+ }
108
+
109
+ static VALUE StickerCycle_hash(const VALUE self) {
110
+ const StickerCycleData* data;
111
+ GetInitializedStickerCycleData(self, data);
112
+
113
+ st_index_t hash = rb_hash_start((st_index_t)StickerCycle_hash);
114
+ hash = rb_hash_uint(hash, data->length);
115
+ hash = rb_hash_uint(hash, data->cube_size);
116
+ const size_t n = data->length;
117
+ for (size_t i = 0; i < n; ++i) {
118
+ hash = rb_hash_uint(hash, data->indices[i]);
119
+ }
120
+ return ST2FIX(rb_hash_end(hash));
121
+ }
122
+
123
+ static VALUE StickerCycle_eql(const VALUE self, const VALUE other) {
124
+ if (self == other) {
125
+ return Qtrue;
126
+ }
127
+ if (rb_obj_class(self) != rb_obj_class(other)) {
128
+ return Qfalse;
129
+ }
130
+ const StickerCycleData* self_data;
131
+ GetInitializedStickerCycleData(self, self_data);
132
+ const StickerCycleData* other_data;
133
+ GetInitializedStickerCycleData(other, other_data);
134
+ if (self_data->cube_size != other_data->cube_size) {
135
+ return Qfalse;
136
+ }
137
+ if (self_data->length != other_data->length) {
138
+ return Qfalse;
139
+ }
140
+ const size_t n = self_data->length;
141
+ for (size_t i = 0; i < n; ++i) {
142
+ if (self_data->indices[i] != other_data->indices[i]) {
143
+ return Qfalse;
144
+ }
145
+ }
146
+ return Qtrue;
147
+ }
148
+
149
+ static VALUE StickerCycle_cube_size(const VALUE self) {
150
+ const StickerCycleData* data;
151
+ GetInitializedStickerCycleData(self, data);
152
+ return ST2FIX(data->cube_size);
153
+ }
154
+
155
+ static VALUE StickerCycle_length(const VALUE self) {
156
+ const StickerCycleData* data;
157
+ GetInitializedStickerCycleData(self, data);
158
+ return ST2FIX(data->length);
159
+ }
160
+
161
+ static VALUE StickerCycle_coordinates(const VALUE self) {
162
+ const StickerCycleData* data;
163
+ GetInitializedStickerCycleData(self, data);
164
+ return data->coordinates;
165
+ }
166
+
167
+ static VALUE StickerCycle_inverse(const VALUE self) {
168
+ const StickerCycleData* data;
169
+ GetInitializedStickerCycleData(self, data);
170
+ const long n = data->length;
171
+ StickerCycleData* inverse_data;
172
+ const VALUE inverse = TypedData_Make_Struct(rb_obj_class(self), StickerCycleData, &StickerCycleData_type, inverse_data);
173
+ inverse_data->cube_size = data->cube_size;
174
+ inverse_data->length = n;
175
+ inverse_data->indices = malloc_indices(n);
176
+ inverse_data->coordinates = rb_funcall(data->coordinates, reverse, 0);
177
+ for (int i = 0; i < n; ++i) {
178
+ inverse_data->indices[i] = data->indices[n - 1 - i];
179
+ }
180
+ return inverse;
181
+ }
182
+
183
+ void init_sticker_cycle_class_under(const VALUE module) {
184
+ reverse = rb_intern("reverse");
185
+ StickerCycleClass = rb_define_class_under(module, "StickerCycle", rb_cObject);
186
+ rb_define_alloc_func(StickerCycleClass, StickerCycle_alloc);
187
+ rb_define_method(StickerCycleClass, "initialize", StickerCycle_initialize, 2);
188
+ rb_define_method(StickerCycleClass, "apply_to", StickerCycle_apply_to, 1);
189
+ rb_define_method(StickerCycleClass, "hash", StickerCycle_hash, 0);
190
+ rb_define_method(StickerCycleClass, "eql?", StickerCycle_eql, 1);
191
+ rb_define_alias(StickerCycleClass, "==", "eql?");
192
+ rb_define_method(StickerCycleClass, "cube_size", StickerCycle_cube_size, 0);
193
+ rb_define_method(StickerCycleClass, "length", StickerCycle_length, 0);
194
+ rb_define_method(StickerCycleClass, "coordinates", StickerCycle_coordinates, 0);
195
+ rb_define_method(StickerCycleClass, "inverse", StickerCycle_inverse, 0);
196
+ }
@@ -0,0 +1,5 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ void init_sticker_cycle_class_under(VALUE module);
@@ -28,6 +28,17 @@ module TwistyPuzzles
28
28
  @colors_to_face_symbols = face_symbols_to_colors.invert
29
29
  end
30
30
 
31
+
32
+ def eql?(other)
33
+ self.class.equal?(other.class) && colors == other.colors
34
+ end
35
+
36
+ alias == eql?
37
+
38
+ def hash
39
+ @hash ||= ([self.class] + colors).hash
40
+ end
41
+
31
42
  def color(face_symbol)
32
43
  @face_symbols_to_colors[face_symbol]
33
44
  end
@@ -4,7 +4,6 @@ require 'twisty_puzzles/cube'
4
4
  require 'twisty_puzzles/cube_constants'
5
5
  require 'twisty_puzzles/coordinate'
6
6
  require 'twisty_puzzles/cube_print_helper'
7
- require 'twisty_puzzles/state_helper'
8
7
  require 'twisty_puzzles/utils/array_helper'
9
8
  require 'twisty_puzzles/native'
10
9
 
@@ -13,7 +12,6 @@ module TwistyPuzzles
13
12
  class CubeState
14
13
  include Utils::ArrayHelper
15
14
  include CubePrintHelper
16
- include StateHelper
17
15
  include CubeConstants
18
16
 
19
17
  def self.check_cube_size(cube_size)
@@ -75,6 +73,10 @@ module TwistyPuzzles
75
73
 
76
74
  alias == eql?
77
75
 
76
+ def hash
77
+ @hash ||= [self.class, @native].hash
78
+ end
79
+
78
80
  def rotation_algorithms
79
81
  Rotation::ALL_ROTATIONS.combination(2).reject do |r0, r1|
80
82
  r0.inverse == r1
@@ -85,10 +87,6 @@ module TwistyPuzzles
85
87
  rotation_algorithms.any? { |r| r.apply_temporarily_to(self) { |state| state == other } }
86
88
  end
87
89
 
88
- def hash
89
- @hash ||= [self.class, @native].hash
90
- end
91
-
92
90
  # TODO: Get rid of this backwards compatibility artifact
93
91
  def sticker_array(face)
94
92
  raise TypeError unless face.is_a?(Face)
@@ -28,7 +28,7 @@ module TwistyPuzzles
28
28
  raise TypeError, 'Twists are only supported for edges and corners.'
29
29
  end
30
30
 
31
- cycles = parts.map { |p| StickerCycle.new(@cube_size, coordinates(p)) }
31
+ cycles = parts.map { |p| StickerCycle.from_coordinates(@cube_size, coordinates(p)) }
32
32
  StickerCycles.new(@cube_size, cycles)
33
33
  end
34
34
 
@@ -49,7 +49,7 @@ module TwistyPuzzles
49
49
  check_types(parts, Part)
50
50
  check_type_consistency(parts)
51
51
  part_coordinates = parts.map { |p| coordinates(p) }
52
- cycles = part_coordinates.transpose.map { |c| StickerCycle.new(@cube_size, c) }
52
+ cycles = part_coordinates.transpose.map { |c| StickerCycle.from_coordinates(@cube_size, c) }
53
53
  StickerCycles.new(@cube_size, cycles)
54
54
  end
55
55
  end
@@ -22,6 +22,7 @@ module TwistyPuzzles
22
22
  when SkewbDirection::ZERO then CubeDirection::ZERO
23
23
  when SkewbDirection::FORWARD then CubeDirection::FORWARD
24
24
  when SkewbDirection::BACKWARD then CubeDirection::BACKWARD
25
+ else raise
25
26
  end
26
27
  end
27
28
 
@@ -3,14 +3,12 @@
3
3
  require 'twisty_puzzles/coordinate'
4
4
  require 'twisty_puzzles/cube'
5
5
  require 'twisty_puzzles/cube_print_helper'
6
- require 'twisty_puzzles/state_helper'
7
6
  require 'twisty_puzzles/cube_constants'
8
7
 
9
8
  module TwistyPuzzles
10
9
  # Represents the state (i.e. the sticker positions) of a Skewb.
11
10
  class SkewbState
12
11
  include CubePrintHelper
13
- include StateHelper
14
12
  include CubeConstants
15
13
  # Pairs of coordinate pairs that should match in case of solved layers.
16
14
  MATCHING_CORNERS =
@@ -151,14 +149,5 @@ module TwistyPuzzles
151
149
 
152
150
  layer_check_neighbors(face).map { |c| self[c] }.uniq.length == 1
153
151
  end
154
-
155
- def rotate_face(face, direction)
156
- neighbors = face.neighbors
157
- inverse_order_face = face.coordinate_index_close_to(neighbors[0]) <
158
- face.coordinate_index_close_to(neighbors[1])
159
- direction = direction.inverse if inverse_order_face
160
- cycle = SkewbCoordinate.corners_on_face(face)
161
- apply_4sticker_cycle(cycle, direction)
162
- end
163
152
  end
164
153
  end
@@ -10,22 +10,47 @@ module TwistyPuzzles
10
10
  class StickerCycle
11
11
  include ReversibleApplyable
12
12
 
13
- def initialize(cube_size, sticker_cycle)
14
- @cube_size = cube_size
15
- @sticker_cycle = sticker_cycle
13
+ def self.from_coordinates(cube_size, coordinates)
14
+ CubeState.check_cube_size(cube_size)
15
+ raise TypeError unless coordinates.all?(Coordinate)
16
+
17
+ new(Native::StickerCycle.new(cube_size, coordinates.map(&:native)))
18
+ end
19
+
20
+ def initialize(native)
21
+ raise TypeError unless native.is_a?(Native::StickerCycle)
22
+
23
+ @native = native
24
+ end
25
+
26
+ attr_reader :native
27
+
28
+ def eql?(other)
29
+ self.class.equal?(other.class) && @native == other.native
16
30
  end
17
31
 
18
- attr_reader :cube_size, :sticker_cycle
32
+ alias == eql?
33
+
34
+ def hash
35
+ @hash ||= [self.class, @native].hash
36
+ end
37
+
38
+ def cube_size
39
+ @native.cube_size
40
+ end
41
+
42
+ def length
43
+ @native.length
44
+ end
19
45
 
20
46
  def apply_to(cube_state)
21
47
  raise TypeError unless cube_state.is_a?(CubeState)
22
- raise ArgumentError unless cube_state.n == @cube_size
23
48
 
24
- cube_state.apply_sticker_cycle(@sticker_cycle) if @sticker_cycle.length >= 2
49
+ @native.apply_to(cube_state.native)
25
50
  end
26
51
 
27
52
  def inverse
28
- StickerCycle.new(@cube_size, @sticker_cycle.reverse)
53
+ StickerCycle.new(@native.inverse)
29
54
  end
30
55
  end
31
56
 
@@ -38,7 +63,7 @@ module TwistyPuzzles
38
63
  sticker_cycles.each do |c|
39
64
  raise TypeError unless c.is_a?(StickerCycle)
40
65
 
41
- c.sticker_cycle.each do |s|
66
+ c.native.coordinates.each do |s|
42
67
  raise ArgumentError unless affected_set.add?(s)
43
68
  end
44
69
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwistyPuzzles
4
- VERSION = '0.0.17'
4
+ VERSION = '0.0.19'
5
5
  end
@@ -33,7 +33,6 @@ require 'twisty_puzzles/skewb_move'
33
33
  require 'twisty_puzzles/skewb_move_parser'
34
34
  require 'twisty_puzzles/skewb_notation'
35
35
  require 'twisty_puzzles/skewb_state'
36
- require 'twisty_puzzles/state_helper'
37
36
  require 'twisty_puzzles/sticker_cycle'
38
37
  require 'twisty_puzzles/twisty_puzzles_error'
39
38
  require 'twisty_puzzles/version'
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.17
4
+ version: 0.0.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernhard F. Brodowsky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-01 00:00:00.000000000 Z
11
+ date: 2021-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -196,6 +196,8 @@ files:
196
196
  - ext/twisty_puzzles/native/skewb_layer_fingerprint.h
197
197
  - ext/twisty_puzzles/native/skewb_state.c
198
198
  - ext/twisty_puzzles/native/skewb_state.h
199
+ - ext/twisty_puzzles/native/sticker_cycle.c
200
+ - ext/twisty_puzzles/native/sticker_cycle.h
199
201
  - ext/twisty_puzzles/native/utils.c
200
202
  - ext/twisty_puzzles/native/utils.h
201
203
  - lib/twisty_puzzles.rb
@@ -231,7 +233,6 @@ files:
231
233
  - lib/twisty_puzzles/skewb_move_parser.rb
232
234
  - lib/twisty_puzzles/skewb_notation.rb
233
235
  - lib/twisty_puzzles/skewb_state.rb
234
- - lib/twisty_puzzles/state_helper.rb
235
236
  - lib/twisty_puzzles/sticker_cycle.rb
236
237
  - lib/twisty_puzzles/twisty_puzzles_error.rb
237
238
  - lib/twisty_puzzles/utils.rb
@@ -260,7 +261,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
260
261
  - !ruby/object:Gem::Version
261
262
  version: '0'
262
263
  requirements: []
263
- rubygems_version: 3.2.3
264
+ rubygems_version: 3.2.22
264
265
  signing_key:
265
266
  specification_version: 4
266
267
  summary: Gem for my cube_trainer rails app. Some things are better left in a separate
@@ -1,31 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'twisty_puzzles/abstract_direction'
4
-
5
- module TwistyPuzzles
6
- # Common utilities for different puzzle states.
7
- # TODO: Remove
8
- module StateHelper
9
- def apply_sticker_cycle(cycle)
10
- last_sticker = self[cycle[-1]]
11
- (cycle.length - 1).downto(1) do |i|
12
- self[cycle[i]] = self[cycle[i - 1]]
13
- end
14
- self[cycle[0]] = last_sticker
15
- end
16
-
17
- def apply_4sticker_cycle(cycle, direction)
18
- raise ArgumentError unless cycle.length == 4
19
- raise TypeError unless direction.is_a?(AbstractDirection)
20
-
21
- if direction.double_move?
22
- apply_sticker_cycle([cycle[0], cycle[2]])
23
- apply_sticker_cycle([cycle[1], cycle[3]])
24
- else
25
- # Note that we cannot do reverse! because the values are cached.
26
- actual_cycle = direction.value == 3 ? cycle.reverse : cycle
27
- apply_sticker_cycle(actual_cycle)
28
- end
29
- end
30
- end
31
- end