twisty_puzzles 0.0.10 → 0.0.14
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/lib/twisty_puzzles/color_scheme.rb +1 -1
- data/lib/twisty_puzzles/coordinate.rb +22 -3
- data/lib/twisty_puzzles/cube.rb +25 -5
- data/lib/twisty_puzzles/cube_move.rb +2 -2
- data/lib/twisty_puzzles/cube_print_helper.rb +5 -5
- data/lib/twisty_puzzles/move_type_creator.rb +1 -1
- data/lib/twisty_puzzles/parser.rb +57 -12
- data/lib/twisty_puzzles/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f95cf6c568aab20bad9dd5d48222afd5261215984a5da7c2c18b9d3bdf315763
|
4
|
+
data.tar.gz: 713e3825d332a49805f4938b8bc2be924f3813d49e25e9997278966409bb73fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e0ba5a01642a11c57a1d83aeb6b22aa4de037fcbbd6a062a2aff29028f37260cd06a38e009fe5683949a65509a899acd925bbe3b58fdf1552760d5664631ade
|
7
|
+
data.tar.gz: 3b2d41b1b10065029813152e693f0c61c6b28557e1794d16dcb4d6c7b300fd7d0d6fa94b2b23de3e01041526ef03463a05a8854b1eec1be7cfaec7ef1943debb
|
@@ -143,7 +143,7 @@ module TwistyPuzzles
|
|
143
143
|
"Color #{c} cannot be part of the color scheme because it is a reserved color."
|
144
144
|
end
|
145
145
|
end
|
146
|
-
raise ArgumentError unless face_symbols_to_colors.values.all?
|
146
|
+
raise ArgumentError unless face_symbols_to_colors.values.all?(Symbol)
|
147
147
|
end
|
148
148
|
|
149
149
|
def add_missing_mappings(turned_face_symbols_to_colors, chirality_corner_source, unknown_index)
|
@@ -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
|
@@ -27,7 +28,7 @@ module TwistyPuzzles
|
|
27
28
|
|
28
29
|
# Middle coordinate for uneven numbers, the one before for even numbers
|
29
30
|
def self.middle_or_before(cube_size)
|
30
|
-
cube_size - cube_size / 2 - 1
|
31
|
+
cube_size - (cube_size / 2) - 1
|
31
32
|
end
|
32
33
|
|
33
34
|
# Middle coordinate for uneven numbers, the one after for even numbers
|
@@ -37,7 +38,7 @@ module TwistyPuzzles
|
|
37
38
|
|
38
39
|
# The last coordinate that is strictly before the middle
|
39
40
|
def self.last_before_middle(cube_size)
|
40
|
-
cube_size / 2 - 1
|
41
|
+
(cube_size / 2) - 1
|
41
42
|
end
|
42
43
|
|
43
44
|
def self.canonicalize(index, cube_size)
|
@@ -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
|
@@ -291,7 +310,7 @@ module TwistyPuzzles
|
|
291
310
|
|
292
311
|
def self.for_corner(corner)
|
293
312
|
native = Native::SkewbCoordinate.for_corner(corner.face_symbols)
|
294
|
-
new(Face.for_face_symbol(corner.face_symbols.first), 1 + corner.piece_index % 4, native)
|
313
|
+
new(Face.for_face_symbol(corner.face_symbols.first), 1 + (corner.piece_index % 4), native)
|
295
314
|
end
|
296
315
|
|
297
316
|
def hash
|
data/lib/twisty_puzzles/cube.rb
CHANGED
@@ -34,6 +34,14 @@ module TwistyPuzzles
|
|
34
34
|
|
35
35
|
attr_reader :piece_index, :face_symbols
|
36
36
|
|
37
|
+
def self.min_parseable_face_symbols
|
38
|
+
self::FACES
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.max_parseable_face_symbols
|
42
|
+
self::FACES
|
43
|
+
end
|
44
|
+
|
37
45
|
def self.generate_parts
|
38
46
|
valid_face_symbol_combinations =
|
39
47
|
FACE_SYMBOLS.permutation(self::FACES).select do |p|
|
@@ -147,7 +155,7 @@ module TwistyPuzzles
|
|
147
155
|
|
148
156
|
def self.parse(piece_description)
|
149
157
|
face_symbols =
|
150
|
-
piece_description.upcase.strip.
|
158
|
+
piece_description.upcase.strip.chars.map do |e|
|
151
159
|
FACE_SYMBOLS[FACE_NAMES.index(e)]
|
152
160
|
end
|
153
161
|
for_face_symbols(face_symbols)
|
@@ -327,6 +335,14 @@ module TwistyPuzzles
|
|
327
335
|
class MoveableCenter < Part
|
328
336
|
FACES = 1
|
329
337
|
|
338
|
+
def self.min_parseable_face_symbols
|
339
|
+
self::CORRESPONDING_PART_CLASS::FACES
|
340
|
+
end
|
341
|
+
|
342
|
+
def self.max_parseable_face_symbols
|
343
|
+
self::CORRESPONDING_PART_CLASS::FACES
|
344
|
+
end
|
345
|
+
|
330
346
|
def self.min_cube_size
|
331
347
|
4
|
332
348
|
end
|
@@ -467,11 +483,15 @@ module TwistyPuzzles
|
|
467
483
|
false
|
468
484
|
end
|
469
485
|
|
486
|
+
def self.max_parseable_face_symbols
|
487
|
+
FACES + 1
|
488
|
+
end
|
489
|
+
|
470
490
|
def self.for_face_symbols(face_symbols)
|
471
491
|
# One additional face symbol is usually mentioned for wings.
|
472
492
|
raise unless face_symbols.length == FACES || face_symbols.length == FACES + 1
|
473
493
|
|
474
|
-
if face_symbols.length ==
|
494
|
+
if face_symbols.length == FACES + 1
|
475
495
|
for_corner_face_symbols(face_symbols)
|
476
496
|
else
|
477
497
|
for_face_symbols_internal(face_symbols)
|
@@ -518,7 +538,7 @@ module TwistyPuzzles
|
|
518
538
|
end
|
519
539
|
|
520
540
|
def num_incarnations(cube_size)
|
521
|
-
cube_size > 3 ? cube_size / 2 - 1 : 0
|
541
|
+
cube_size > 3 ? (cube_size / 2) - 1 : 0
|
522
542
|
end
|
523
543
|
|
524
544
|
# One index of such a piece on a on a NxN face.
|
@@ -617,7 +637,7 @@ module TwistyPuzzles
|
|
617
637
|
ELEMENTS = generate_parts
|
618
638
|
|
619
639
|
def num_incarnations(cube_size)
|
620
|
-
cube_size > 3 ? cube_size / 2 - 1 : 0
|
640
|
+
cube_size > 3 ? (cube_size / 2) - 1 : 0
|
621
641
|
end
|
622
642
|
|
623
643
|
# One index of such a piece on a on a NxN face.
|
@@ -643,7 +663,7 @@ module TwistyPuzzles
|
|
643
663
|
if cube_size.even? || cube_size <= 3
|
644
664
|
0
|
645
665
|
else
|
646
|
-
cube_size / 2 - 1
|
666
|
+
(cube_size / 2) - 1
|
647
667
|
end
|
648
668
|
end
|
649
669
|
|
@@ -68,8 +68,8 @@ module TwistyPuzzles
|
|
68
68
|
|
69
69
|
def equivalent_slice_move?(other, cube_size)
|
70
70
|
cube_size == 3 && other.slice_index == 1 &&
|
71
|
-
(@axis_face == other.axis_face && @direction == other.direction ||
|
72
|
-
@axis_face == other.axis_face.opposite && @direction == other.direction.inverse)
|
71
|
+
((@axis_face == other.axis_face && @direction == other.direction) ||
|
72
|
+
(@axis_face == other.axis_face.opposite && @direction == other.direction.inverse))
|
73
73
|
end
|
74
74
|
end
|
75
75
|
|
@@ -72,9 +72,9 @@ module TwistyPuzzles
|
|
72
72
|
def skewb_ascii_art_line(first_color, middle_color, last_color, num_first_color)
|
73
73
|
raise if num_first_color > SKEWB_FACE_SIZE / 2
|
74
74
|
|
75
|
-
first_color * num_first_color +
|
76
|
-
middle_color * (SKEWB_FACE_SIZE - 2 * num_first_color) +
|
77
|
-
last_color * num_first_color
|
75
|
+
(first_color * num_first_color) +
|
76
|
+
(middle_color * (SKEWB_FACE_SIZE - (2 * num_first_color))) +
|
77
|
+
(last_color * num_first_color)
|
78
78
|
end
|
79
79
|
|
80
80
|
def skewb_ascii_art(center_color, corner_colors)
|
@@ -116,7 +116,7 @@ module TwistyPuzzles
|
|
116
116
|
front_face = face_lines(cube_state, :F, 1, 3) { |c| color_character(c, color_mode) }
|
117
117
|
right_face = face_lines(cube_state, :R, 1, 3) { |c| color_character(c, color_mode) }
|
118
118
|
pll_line = front_face.first + right_face.first
|
119
|
-
(top_face + [pll_line] * 3).join("\n")
|
119
|
+
(top_face + ([pll_line] * 3)).join("\n")
|
120
120
|
end
|
121
121
|
|
122
122
|
def cube_string(cube_state, color_mode)
|
@@ -150,7 +150,7 @@ module TwistyPuzzles
|
|
150
150
|
end
|
151
151
|
|
152
152
|
def pad_lines(lines, padding)
|
153
|
-
lines.map { |line| empty_name * padding + line }
|
153
|
+
lines.map { |line| (empty_name * padding) + line }
|
154
154
|
end
|
155
155
|
|
156
156
|
def zip_concat_lines(*args)
|
@@ -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?
|
9
|
+
raise TypeError unless capture_keys.all?(Symbol)
|
10
10
|
|
11
11
|
@capture_keys = capture_keys.freeze
|
12
12
|
@move_class = move_class
|
@@ -77,8 +77,8 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
|
|
77
77
|
end
|
78
78
|
|
79
79
|
# Parses at least one move.
|
80
|
-
def
|
81
|
-
moves =
|
80
|
+
def parse_nonempty_moves_with_triggers
|
81
|
+
moves = parse_moves_with_triggers
|
82
82
|
complain('move') if moves.empty?
|
83
83
|
moves
|
84
84
|
end
|
@@ -117,8 +117,24 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
|
|
117
117
|
if @scanner.peek(1) == OPENING_BRACKET
|
118
118
|
parse_commutator_internal
|
119
119
|
else
|
120
|
-
|
120
|
+
parse_commutator_no_brackets
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def parse_commutator_no_brackets
|
125
|
+
setup_or_first_part_or_algorithm = parse_moves_with_triggers
|
126
|
+
skip_spaces
|
127
|
+
if @scanner.eos? || !SEPARATORS.include?(@scanner.peek(1))
|
128
|
+
return FakeCommutator.new(setup_or_first_part_or_algorithm)
|
121
129
|
end
|
130
|
+
|
131
|
+
setup_or_first_part = setup_or_first_part_or_algorithm
|
132
|
+
complain('move') if setup_or_first_part.empty?
|
133
|
+
separator = parse_separator
|
134
|
+
comm = parse_commutator_internal_after_separator(setup_or_first_part, separator)
|
135
|
+
skip_spaces
|
136
|
+
complain('end of commutator') unless @scanner.eos?
|
137
|
+
comm
|
122
138
|
end
|
123
139
|
|
124
140
|
def parse_algorithm
|
@@ -131,40 +147,69 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
|
|
131
147
|
if @scanner.peek(1) == OPENING_BRACKET
|
132
148
|
parse_pure_commutator
|
133
149
|
else
|
134
|
-
|
150
|
+
parse_pure_commutator_no_brackets
|
135
151
|
end
|
136
152
|
end
|
137
153
|
|
138
154
|
def parse_pure_commutator
|
139
155
|
skip_spaces
|
140
156
|
parse_open_bracket
|
141
|
-
first_part =
|
157
|
+
first_part = parse_nonempty_moves_with_triggers
|
142
158
|
skip_spaces
|
143
|
-
|
144
|
-
second_part =
|
159
|
+
parse_pure_separator
|
160
|
+
second_part = parse_nonempty_moves_with_triggers
|
145
161
|
skip_spaces
|
146
162
|
parse_close_bracket
|
147
163
|
PureCommutator.new(first_part, second_part)
|
148
164
|
end
|
149
165
|
|
166
|
+
def parse_pure_commutator_no_brackets
|
167
|
+
first_part_or_algorithm = parse_moves_with_triggers
|
168
|
+
skip_spaces
|
169
|
+
if @scanner.eos? || !PURE_SEPARATORS.include?(@scanner.peek(1))
|
170
|
+
return FakeCommutator.new(first_part_or_algorithm)
|
171
|
+
end
|
172
|
+
|
173
|
+
first_part = first_part_or_algorithm
|
174
|
+
complain('move') if first_part.empty?
|
175
|
+
parse_pure_separator
|
176
|
+
second_part = parse_nonempty_moves_with_triggers
|
177
|
+
skip_spaces
|
178
|
+
PureCommutator.new(first_part, second_part)
|
179
|
+
end
|
180
|
+
|
181
|
+
def parse_pure_separator
|
182
|
+
complain('middle of pure commutator') unless PURE_SEPARATORS.include?(@scanner.getch)
|
183
|
+
end
|
184
|
+
|
150
185
|
def parse_commutator_internal_after_separator(setup_or_first_part, separator)
|
151
|
-
if
|
186
|
+
if SETUP_SEPARATORS.include?(separator)
|
152
187
|
inner_commutator = parse_setup_commutator_inner
|
153
188
|
SetupCommutator.new(setup_or_first_part, inner_commutator)
|
154
|
-
elsif separator
|
155
|
-
second_part =
|
189
|
+
elsif PURE_SEPARATORS.include?(separator)
|
190
|
+
second_part = parse_nonempty_moves_with_triggers
|
156
191
|
PureCommutator.new(setup_or_first_part, second_part)
|
157
192
|
else
|
158
193
|
complain('end of setup or middle of pure commutator') unless @scanner.eos?
|
159
194
|
end
|
160
195
|
end
|
161
196
|
|
197
|
+
SETUP_SEPARATORS = %w[; :].freeze
|
198
|
+
PURE_SEPARATORS = %w[/ ,].freeze
|
199
|
+
SEPARATORS = (SETUP_SEPARATORS + PURE_SEPARATORS).freeze
|
200
|
+
|
201
|
+
def parse_separator
|
202
|
+
separator = @scanner.getch
|
203
|
+
complain('separator between commutator parts') unless SEPARATORS.include?(separator)
|
204
|
+
separator
|
205
|
+
end
|
206
|
+
|
162
207
|
def parse_commutator_internal
|
163
208
|
skip_spaces
|
164
209
|
parse_open_bracket
|
165
|
-
setup_or_first_part =
|
210
|
+
setup_or_first_part = parse_nonempty_moves_with_triggers
|
166
211
|
skip_spaces
|
167
|
-
separator =
|
212
|
+
separator = parse_separator
|
168
213
|
comm = parse_commutator_internal_after_separator(setup_or_first_part, separator)
|
169
214
|
skip_spaces
|
170
215
|
parse_close_bracket
|
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.
|
4
|
+
version: 0.0.14
|
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:
|
11
|
+
date: 2021-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|