twisty_puzzles 0.0.10 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- 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
|