twisty_puzzles 0.0.5 → 0.0.10
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 +4 -4
- data/README.md +6 -1
- data/ext/twisty_puzzles/native/cube_algorithm.c +10 -18
- data/ext/twisty_puzzles/native/cube_average.c +2 -2
- data/ext/twisty_puzzles/native/cube_coordinate.c +16 -15
- data/ext/twisty_puzzles/native/cube_coordinate.h +7 -7
- data/ext/twisty_puzzles/native/cube_state.c +23 -33
- data/ext/twisty_puzzles/native/cube_state.h +2 -2
- data/ext/twisty_puzzles/native/face_symbols.h +2 -2
- data/ext/twisty_puzzles/native/skewb_algorithm.c +3 -12
- data/ext/twisty_puzzles/native/skewb_coordinate.c +0 -11
- data/ext/twisty_puzzles/native/skewb_layer_fingerprint.c +3 -2
- data/ext/twisty_puzzles/native/skewb_state.c +0 -2
- data/ext/twisty_puzzles/native/utils.c +7 -1
- data/ext/twisty_puzzles/native/utils.h +2 -3
- data/lib/twisty_puzzles/abstract_move.rb +5 -2
- data/lib/twisty_puzzles/abstract_move_parser.rb +3 -3
- data/lib/twisty_puzzles/algorithm.rb +1 -1
- data/lib/twisty_puzzles/algorithm_transformation.rb +27 -19
- data/lib/twisty_puzzles/axis_face_and_direction_move.rb +4 -1
- data/lib/twisty_puzzles/cancellation_helper.rb +1 -1
- data/lib/twisty_puzzles/color_scheme.rb +8 -6
- data/lib/twisty_puzzles/commutator.rb +7 -0
- data/lib/twisty_puzzles/compiled_algorithm.rb +4 -4
- data/lib/twisty_puzzles/coordinate.rb +4 -6
- data/lib/twisty_puzzles/cube.rb +19 -23
- 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/cube_state.rb +10 -0
- data/lib/twisty_puzzles/parser.rb +3 -3
- data/lib/twisty_puzzles/rotation.rb +8 -4
- 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/skewb_state.rb +6 -4
- data/lib/twisty_puzzles/version.rb +1 -1
- metadata +11 -12
@@ -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
|
-
|
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
|
-
|
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)
|
@@ -150,8 +154,7 @@ module TwistyPuzzles
|
|
150
154
|
when :qtm then slice_factor * direction_factor
|
151
155
|
when :htm then slice_factor
|
152
156
|
when :stm then 1
|
153
|
-
when :qstm then direction_factor
|
154
|
-
when :sqtm then direction_factor
|
157
|
+
when :qstm, :sqtm then direction_factor
|
155
158
|
else raise ArgumentError, "Invalid move metric #{metric.inspect}."
|
156
159
|
end
|
157
160
|
end
|
@@ -20,7 +20,7 @@ module TwistyPuzzles
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def parse_named_captures(match)
|
23
|
-
present_named_captures = match.named_captures.
|
23
|
+
present_named_captures = match.named_captures.compact
|
24
24
|
present_named_captures.map do |name, string|
|
25
25
|
key = parse_part_key(name).to_sym
|
26
26
|
value = parse_move_part(name, string)
|
@@ -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
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
15
|
-
rotation.identity? && !mirror
|
16
|
-
end
|
15
|
+
attr_reader :rotation, :mirror, :mirror_normal_face
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
28
|
-
|
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
|
@@ -11,6 +11,7 @@ module TwistyPuzzles
|
|
11
11
|
raise TypeError, "Unsuitable axis face #{axis_face}." unless axis_face.is_a?(Face)
|
12
12
|
raise TypeError unless direction.is_a?(CubeDirection)
|
13
13
|
|
14
|
+
super()
|
14
15
|
@axis_face = axis_face
|
15
16
|
@direction = direction
|
16
17
|
end
|
@@ -54,7 +55,9 @@ module TwistyPuzzles
|
|
54
55
|
self
|
55
56
|
else
|
56
57
|
rotation_neighbors = rotation.axis_face.neighbors
|
57
|
-
face_index = rotation_neighbors.index(@axis_face)
|
58
|
+
face_index = rotation_neighbors.index(@axis_face)
|
59
|
+
raise unless face_index
|
60
|
+
|
58
61
|
new_axis_face =
|
59
62
|
rotation_neighbors[(face_index + rotation.direction.value) % rotation_neighbors.length]
|
60
63
|
fields = replace_once(identifying_fields, @axis_face, new_axis_face)
|
@@ -135,7 +135,7 @@ module TwistyPuzzles
|
|
135
135
|
def self.alg_plus_cancelled_move(algorithm, move, cube_size)
|
136
136
|
if move.is_a?(Rotation) && (tail_rotations = num_tail_rotations(algorithm)) >= 2
|
137
137
|
Algorithm.new(algorithm.moves[0...-tail_rotations]) +
|
138
|
-
cancelled_rotations(algorithm.moves[-tail_rotations
|
138
|
+
cancelled_rotations(algorithm.moves[-tail_rotations..] + [move])
|
139
139
|
else
|
140
140
|
Algorithm.new(algorithm.moves[0...-1]) +
|
141
141
|
algorithm.moves[-1].join_with_cancellation(move, cube_size)
|
@@ -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
|
@@ -56,7 +56,7 @@ module TwistyPuzzles
|
|
56
56
|
raise ArgumentError unless colors.include?(top_color)
|
57
57
|
raise ArgumentError unless colors.include?(front_color)
|
58
58
|
|
59
|
-
#
|
59
|
+
# NOTE: The reason that this is so complicated is that we want it to still work if the
|
60
60
|
# chirality corner gets exchanged.
|
61
61
|
|
62
62
|
# Do the obvious and handle opposites of the top and front color so we have no
|
@@ -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(
|
99
|
-
|
100
|
-
|
101
|
-
|
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 =
|
@@ -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.
|
@@ -17,6 +21,7 @@ module TwistyPuzzles
|
|
17
21
|
def initialize(algorithm)
|
18
22
|
raise ArgumentError unless algorithm.is_a?(Algorithm)
|
19
23
|
|
24
|
+
super()
|
20
25
|
@algorithm = algorithm
|
21
26
|
end
|
22
27
|
|
@@ -47,6 +52,7 @@ module TwistyPuzzles
|
|
47
52
|
raise ArgumentError unless first_part.is_a?(Algorithm)
|
48
53
|
raise ArgumentError unless second_part.is_a?(Algorithm)
|
49
54
|
|
55
|
+
super()
|
50
56
|
@first_part = first_part
|
51
57
|
@second_part = second_part
|
52
58
|
end
|
@@ -85,6 +91,7 @@ module TwistyPuzzles
|
|
85
91
|
raise ArgumentError, 'Inner commutator has to be a commutator.'
|
86
92
|
end
|
87
93
|
|
94
|
+
super()
|
88
95
|
@setup = setup
|
89
96
|
@inner_commutator = inner_commutator
|
90
97
|
end
|
@@ -90,7 +90,7 @@ module TwistyPuzzles
|
|
90
90
|
base_coordinate = Coordinate.from_indices(
|
91
91
|
part.solved_face, cube_size, *part.base_index_on_face(cube_size, incarnation_index)
|
92
92
|
)
|
93
|
-
other_face_symbols = part.corresponding_part.face_symbols[1
|
93
|
+
other_face_symbols = part.corresponding_part.face_symbols[1..]
|
94
94
|
match_coordinate_internal(base_coordinate, other_face_symbols)
|
95
95
|
end
|
96
96
|
|
@@ -99,7 +99,7 @@ module TwistyPuzzles
|
|
99
99
|
def self.solved_positions(part, cube_size, incarnation_index)
|
100
100
|
solved_coordinate = solved_position(part, cube_size, incarnation_index)
|
101
101
|
other_coordinates =
|
102
|
-
part.face_symbols[1
|
102
|
+
part.face_symbols[1..].map.with_index do |f, i|
|
103
103
|
face = Face.for_face_symbol(f)
|
104
104
|
# The reverse is important for edge like parts. We are not in the same position as usual
|
105
105
|
# solved pieces would be.
|
@@ -109,7 +109,7 @@ module TwistyPuzzles
|
|
109
109
|
base_coordinate = Coordinate.from_indices(face, cube_size, *base_indices)
|
110
110
|
other_face_symbols = [part.face_symbols[0]] +
|
111
111
|
part.corresponding_part.face_symbols[1...i + 1] +
|
112
|
-
part.corresponding_part.face_symbols[i + 2
|
112
|
+
part.corresponding_part.face_symbols[i + 2..]
|
113
113
|
match_coordinate_internal(base_coordinate, other_face_symbols)
|
114
114
|
end
|
115
115
|
[solved_coordinate] + other_coordinates
|
@@ -276,7 +276,7 @@ module TwistyPuzzles
|
|
276
276
|
@native = native
|
277
277
|
end
|
278
278
|
|
279
|
-
attr_reader :native
|
279
|
+
attr_reader :native, :coordinate
|
280
280
|
|
281
281
|
private_class_method :new
|
282
282
|
|
@@ -311,7 +311,5 @@ module TwistyPuzzles
|
|
311
311
|
def face
|
312
312
|
@face ||= Face.for_face_symbol(@native.face)
|
313
313
|
end
|
314
|
-
|
315
|
-
attr_reader :coordinate
|
316
314
|
end
|
317
315
|
end
|
data/lib/twisty_puzzles/cube.rb
CHANGED
@@ -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
|
@@ -97,7 +109,7 @@ module TwistyPuzzles
|
|
97
109
|
end
|
98
110
|
|
99
111
|
def inspect
|
100
|
-
self.class
|
112
|
+
"#{self.class}(#{@face_symbols.map(&:to_s).join(', ')})"
|
101
113
|
end
|
102
114
|
|
103
115
|
def to_s
|
@@ -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 #{
|
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
|
@@ -365,7 +369,7 @@ module TwistyPuzzles
|
|
365
369
|
attr_reader :corresponding_part
|
366
370
|
|
367
371
|
def inspect
|
368
|
-
self.class
|
372
|
+
"#{self.class}(#{face_symbol}, #{@corresponding_part.inspect})"
|
369
373
|
end
|
370
374
|
|
371
375
|
def rotate_by(_number)
|
@@ -514,7 +518,7 @@ module TwistyPuzzles
|
|
514
518
|
end
|
515
519
|
|
516
520
|
def num_incarnations(cube_size)
|
517
|
-
|
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..-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
|
-
|
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
|
-
|
646
|
+
cube_size / 2 - 1
|
651
647
|
end
|
652
648
|
end
|
653
649
|
|