twisty_puzzles 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/lib/twisty_puzzles/abstract_move.rb +1 -2
- data/lib/twisty_puzzles/abstract_move_parser.rb +1 -1
- data/lib/twisty_puzzles/algorithm.rb +1 -1
- data/lib/twisty_puzzles/axis_face_and_direction_move.rb +1 -0
- data/lib/twisty_puzzles/cancellation_helper.rb +1 -1
- data/lib/twisty_puzzles/color_scheme.rb +1 -1
- data/lib/twisty_puzzles/commutator.rb +3 -0
- data/lib/twisty_puzzles/compiled_algorithm.rb +4 -4
- data/lib/twisty_puzzles/coordinate.rb +4 -6
- data/lib/twisty_puzzles/cube.rb +3 -3
- 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/parser.rb +3 -3
- data/lib/twisty_puzzles/rotation.rb +2 -0
- 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/version.rb +1 -1
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 59a43662a260f2e013e0b59b6597dbfc4f6b5a04bc9d49b9f350b9c3a050babe
|
4
|
+
data.tar.gz: 98e23ce0bbcb677b9deb490ca02bb2e6c3fbd376c0c5a35dcb79d6e06afbd905
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb187fa6e58c48444b5629e4ab195f2063d2ad9b0c8f07aa8d3a4e19486c177fb29b38a404e2a80f0690d6491466f94cd638d04fc6d76389ffb915671c2107a4
|
7
|
+
data.tar.gz: 9b89321ce8b01b446b992a318aaf43f2cdc54bc9745d16538f14e2bc93f038a413923a11c0e856e13712e20a29c6d0416344ed577ea5aac642ef295571d489a3
|
data/README.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
![Ruby](https://github.com/Lykos/twisty_puzzles/workflows/Ruby/badge.svg)
|
2
|
+
![Rubocop](https://github.com/Lykos/twisty_puzzles/workflows/Rubocop/badge.svg)
|
3
|
+
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/twisty_puzzles.svg)](https://badge.fury.io/rb/twisty_puzzles)
|
5
|
+
|
1
6
|
# Twisty Puzzles
|
2
7
|
Gem for my cube_trainer rails app. Some things are better left in a separate gem with no rails, e.g. native extensions. The main purpose is to support my Rails app, but if it's useful for someone else, feel free to use it at your own risk.
|
3
8
|
|
@@ -25,7 +30,7 @@ TODO: Write usage instructions here
|
|
25
30
|
|
26
31
|
After checking out the repo, run `bundle install` to install dependencies. Then, run `bundle exec rake spec` to run the tests. You can also run `bundle exec bin/console` for an interactive prompt that will allow you to experiment.
|
27
32
|
|
28
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
33
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `lib/twisty_puzzles/version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
29
34
|
|
30
35
|
## Contributing
|
31
36
|
|
@@ -150,8 +150,7 @@ module TwistyPuzzles
|
|
150
150
|
when :qtm then slice_factor * direction_factor
|
151
151
|
when :htm then slice_factor
|
152
152
|
when :stm then 1
|
153
|
-
when :qstm then direction_factor
|
154
|
-
when :sqtm then direction_factor
|
153
|
+
when :qstm, :sqtm then direction_factor
|
155
154
|
else raise ArgumentError, "Invalid move metric #{metric.inspect}."
|
156
155
|
end
|
157
156
|
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)
|
@@ -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)
|
@@ -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
|
@@ -17,6 +17,7 @@ module TwistyPuzzles
|
|
17
17
|
def initialize(algorithm)
|
18
18
|
raise ArgumentError unless algorithm.is_a?(Algorithm)
|
19
19
|
|
20
|
+
super()
|
20
21
|
@algorithm = algorithm
|
21
22
|
end
|
22
23
|
|
@@ -47,6 +48,7 @@ module TwistyPuzzles
|
|
47
48
|
raise ArgumentError unless first_part.is_a?(Algorithm)
|
48
49
|
raise ArgumentError unless second_part.is_a?(Algorithm)
|
49
50
|
|
51
|
+
super()
|
50
52
|
@first_part = first_part
|
51
53
|
@second_part = second_part
|
52
54
|
end
|
@@ -85,6 +87,7 @@ module TwistyPuzzles
|
|
85
87
|
raise ArgumentError, 'Inner commutator has to be a commutator.'
|
86
88
|
end
|
87
89
|
|
90
|
+
super()
|
88
91
|
@setup = setup
|
89
92
|
@inner_commutator = inner_commutator
|
90
93
|
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
@@ -97,7 +97,7 @@ module TwistyPuzzles
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def inspect
|
100
|
-
self.class
|
100
|
+
"#{self.class}(#{@face_symbols.map(&:to_s).join(', ')})"
|
101
101
|
end
|
102
102
|
|
103
103
|
def to_s
|
@@ -365,7 +365,7 @@ module TwistyPuzzles
|
|
365
365
|
attr_reader :corresponding_part
|
366
366
|
|
367
367
|
def inspect
|
368
|
-
self.class
|
368
|
+
"#{self.class}(#{face_symbol}, #{@corresponding_part.inspect})"
|
369
369
|
end
|
370
370
|
|
371
371
|
def rotate_by(_number)
|
@@ -532,7 +532,7 @@ module TwistyPuzzles
|
|
532
532
|
|
533
533
|
def self.create_for_face_symbols(face_symbols)
|
534
534
|
piece_candidates =
|
535
|
-
face_symbols[1
|
535
|
+
face_symbols[1..].permutation.map do |cs|
|
536
536
|
new([face_symbols[0]] + cs)
|
537
537
|
end
|
538
538
|
find_only(piece_candidates, &:valid?)
|
@@ -139,8 +139,6 @@ module TwistyPuzzles
|
|
139
139
|
end
|
140
140
|
end
|
141
141
|
|
142
|
-
# rubocop:disable Metrics/PerceivedComplexity
|
143
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
144
142
|
def prepend_fat_move(other, cube_size)
|
145
143
|
if same_fat_block?(other)
|
146
144
|
merge_with_same_fat_block(other)
|
@@ -156,8 +154,6 @@ module TwistyPuzzles
|
|
156
154
|
Algorithm.move(other.inner_fat_mslice_move(cube_size))
|
157
155
|
end
|
158
156
|
end
|
159
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
160
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
161
157
|
|
162
158
|
def prepend_slice_move(other, cube_size)
|
163
159
|
return unless same_axis?(other)
|
@@ -14,29 +14,29 @@ module TwistyPuzzles
|
|
14
14
|
class CubeMoveParser < AbstractMoveParser
|
15
15
|
REGEXP =
|
16
16
|
begin
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
17
|
+
axes_part = "(?<axis_name>[#{AbstractMove::AXES.join}])"
|
18
|
+
face_names = CubeConstants::FACE_NAMES.join
|
19
|
+
fat_move_part =
|
20
|
+
"(?<width>\\d*)(?<fat_face_name>[#{face_names}])w"
|
21
|
+
normal_move_part = "(?<face_name>[#{face_names}])"
|
22
|
+
downcased_face_names = face_names.downcase
|
23
|
+
maybe_fat_maybe_slice_move_part =
|
24
|
+
"(?<maybe_fat_face_maybe_slice_name>[#{downcased_face_names}])"
|
25
|
+
slice_move_part =
|
26
|
+
"(?<slice_index>\\d+)(?<slice_name>[#{downcased_face_names}])"
|
27
|
+
mslice_move_part =
|
28
|
+
"(?<mslice_name>[#{AbstractMove::SLICE_FACES.keys.join}])"
|
29
|
+
move_part = "(?:#{axes_part}|" \
|
30
|
+
"#{fat_move_part}|" \
|
31
|
+
"#{normal_move_part}|" \
|
32
|
+
"#{maybe_fat_maybe_slice_move_part}|" \
|
33
|
+
"#{slice_move_part}|#{mslice_move_part})"
|
34
|
+
direction_names =
|
35
|
+
AbstractDirection::POSSIBLE_DIRECTION_NAMES.flatten
|
36
|
+
direction_names.sort_by! { |e| -e.length }
|
37
|
+
direction_part = "(?<direction>#{direction_names.join('|')})"
|
38
|
+
Regexp.new("#{move_part}#{direction_part}")
|
39
|
+
end
|
40
40
|
|
41
41
|
MOVE_TYPE_CREATORS = [
|
42
42
|
MoveTypeCreator.new(%i[axis_face direction], Rotation),
|
@@ -41,9 +41,10 @@ module TwistyPuzzles
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def maybe_reverse(reverse_mode, stuff)
|
44
|
-
|
44
|
+
case reverse_mode
|
45
|
+
when :reverse
|
45
46
|
stuff.reverse
|
46
|
-
|
47
|
+
when :keep
|
47
48
|
stuff
|
48
49
|
else
|
49
50
|
raise
|
@@ -102,7 +103,7 @@ module TwistyPuzzles
|
|
102
103
|
face_symbol_info = FACE_SYMBOL_INFOS[face_symbol]
|
103
104
|
stickers = cube_state.sticker_array(face)
|
104
105
|
center_color = color_character(stickers[0], color_mode)
|
105
|
-
corner_colors = stickers[1
|
106
|
+
corner_colors = stickers[1..].map { |c| color_character(c, color_mode) }
|
106
107
|
permuted_corner_colors =
|
107
108
|
apply_permutation(corner_colors, face_symbol_info.skewb_corner_permutation)
|
108
109
|
raise unless corner_colors.length == 4
|
@@ -185,14 +185,14 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
|
|
185
185
|
end
|
186
186
|
end
|
187
187
|
|
188
|
-
def parse_commutator(alg_string, complete_parse
|
188
|
+
def parse_commutator(alg_string, complete_parse: true)
|
189
189
|
parser = Parser.new(alg_string, CubeMoveParser::INSTANCE)
|
190
190
|
commutator = parser.parse_commutator
|
191
191
|
parser.check_eos('commutator') if complete_parse
|
192
192
|
commutator
|
193
193
|
end
|
194
194
|
|
195
|
-
def parse_cube_algorithm(alg_string, complete_parse
|
195
|
+
def parse_cube_algorithm(alg_string, complete_parse: true)
|
196
196
|
parser = Parser.new(alg_string, CubeMoveParser::INSTANCE)
|
197
197
|
algorithm = parser.parse_algorithm
|
198
198
|
parser.check_eos('algorithm') if complete_parse
|
@@ -206,7 +206,7 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
|
|
206
206
|
alias parse_algorithm parse_cube_algorithm
|
207
207
|
alias parse_move parse_cube_move
|
208
208
|
|
209
|
-
def parse_skewb_algorithm(alg_string, notation, complete_parse
|
209
|
+
def parse_skewb_algorithm(alg_string, notation, complete_parse: true)
|
210
210
|
parser = Parser.new(alg_string, SkewbMoveParser.new(notation))
|
211
211
|
algorithm = parser.parse_algorithm
|
212
212
|
parser.check_eos('algorithm') if complete_parse
|
@@ -62,6 +62,7 @@ module TwistyPuzzles
|
|
62
62
|
[self, alternative].include?(other)
|
63
63
|
end
|
64
64
|
|
65
|
+
# rubocop:disable Metrics/AbcSize
|
65
66
|
def prepend_rotation(other, _cube_size)
|
66
67
|
if same_axis?(other)
|
67
68
|
direction = translated_direction(other.axis_face)
|
@@ -74,6 +75,7 @@ module TwistyPuzzles
|
|
74
75
|
Algorithm.move(Rotation.new(remaining_face, CubeDirection::DOUBLE))
|
75
76
|
end
|
76
77
|
end
|
78
|
+
# rubocop:enable Metrics/AbcSize
|
77
79
|
|
78
80
|
def prepend_fat_m_slice_move(_other, _cube_size)
|
79
81
|
nil
|
@@ -12,6 +12,7 @@ module TwistyPuzzles
|
|
12
12
|
raise TypeError unless axis_corner.is_a?(Corner)
|
13
13
|
raise TypeError unless direction.is_a?(SkewbDirection)
|
14
14
|
|
15
|
+
super()
|
15
16
|
@axis_corner = axis_corner.rotate_face_up(axis_corner.faces.min_by(&:piece_index))
|
16
17
|
@direction = direction
|
17
18
|
end
|
@@ -10,9 +10,11 @@ module TwistyPuzzles
|
|
10
10
|
# Class that represents one notation for Skewb moves, e.g. Sarahs notation or fixed
|
11
11
|
# corner notation.
|
12
12
|
class SkewbNotation
|
13
|
+
# rubocop:disable Metrics/AbcSize
|
13
14
|
def initialize(name, move_corner_pairs)
|
14
15
|
raise TypeError unless name.is_a?(String)
|
15
16
|
|
17
|
+
super()
|
16
18
|
check_move_corner_pairs(move_corner_pairs)
|
17
19
|
@name = name
|
18
20
|
@move_to_corner = move_corner_pairs.to_h.freeze
|
@@ -26,7 +28,9 @@ module TwistyPuzzles
|
|
26
28
|
end.freeze
|
27
29
|
freeze
|
28
30
|
end
|
31
|
+
# rubocop:enable Metrics/AbcSize
|
29
32
|
|
33
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
30
34
|
def check_move_corner_pairs(move_corner_pairs)
|
31
35
|
move_corner_pairs.each do |m|
|
32
36
|
raise ArgumentError unless m.length == 2
|
@@ -37,6 +41,7 @@ module TwistyPuzzles
|
|
37
41
|
|
38
42
|
check_corner_coverage(move_corner_pairs.map(&:last))
|
39
43
|
end
|
44
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
40
45
|
|
41
46
|
def check_corner_coverage(corners)
|
42
47
|
corner_closure = corners + corners.map(&:diagonal_opposite)
|
@@ -49,6 +54,7 @@ module TwistyPuzzles
|
|
49
54
|
end
|
50
55
|
|
51
56
|
attr_reader :name, :move_strings, :non_zero_moves
|
57
|
+
|
52
58
|
private_class_method :new
|
53
59
|
|
54
60
|
def self.fixed_corner
|
@@ -103,7 +109,7 @@ module TwistyPuzzles
|
|
103
109
|
move_to_string(m, reversed_rotations)
|
104
110
|
end.join(' ')
|
105
111
|
new_tail_rotations = reversed_rotations.reverse! +
|
106
|
-
algorithm.moves[algorithm.length - num_tail_rotations
|
112
|
+
algorithm.moves[algorithm.length - num_tail_rotations..]
|
107
113
|
cancelled_rotations = Algorithm.new(new_tail_rotations).cancelled(3)
|
108
114
|
cancelled_rotations.empty? ? alg_string : "#{alg_string} #{cancelled_rotations}"
|
109
115
|
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.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bernhard F. Brodowsky
|
@@ -112,16 +112,16 @@ dependencies:
|
|
112
112
|
name: rubocop
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - "
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
117
|
+
version: '1.7'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - "
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
124
|
+
version: '1.7'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: rubocop-performance
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -253,15 +253,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
253
253
|
requirements:
|
254
254
|
- - ">="
|
255
255
|
- !ruby/object:Gem::Version
|
256
|
-
version: 2.
|
256
|
+
version: 2.6.0
|
257
257
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
258
258
|
requirements:
|
259
259
|
- - ">="
|
260
260
|
- !ruby/object:Gem::Version
|
261
261
|
version: '0'
|
262
262
|
requirements: []
|
263
|
-
|
264
|
-
rubygems_version: 2.7.6.2
|
263
|
+
rubygems_version: 3.1.2
|
265
264
|
signing_key:
|
266
265
|
specification_version: 4
|
267
266
|
summary: Gem for my cube_trainer rails app. Some things are better left in a separate
|