twisty_puzzles 0.0.11 → 0.0.15

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f6166de8734039f856869be9f20b6109c194556094bc281ae3138ada4a1ad27
4
- data.tar.gz: 6a19cc1ad482ec49831c057d944b9055f70c206882ac618892b0336e8d047e3b
3
+ metadata.gz: d5631e9c30819f3520d04ed81aa9b1ceebbee7a3da5c3b51bf2a81947f8fb3a1
4
+ data.tar.gz: fc4769b6c1ebab5d14cb64ddb3e39356a408750d1d0c7954d4929156296b9f9e
5
5
  SHA512:
6
- metadata.gz: 3ba31f44cb0df6f836d9a9b9908550cd2d6ca0ede672d4784f084b609e1249fd0e8e0f8d6cdc0b09e8faba6a462d49966c698b9d5601a4901aa0ee4eb8bc95c1
7
- data.tar.gz: 16727e63c37191c99ed1c185c851c8a541c97f110505f2c6ae5eeeabb186c11c35173d35c2441cc8c15318dd88f380656afc04690d5bb4eaa9b359b9a2725de3
6
+ metadata.gz: c941aaef4dbf2bc8d580d712d669042061c20670aadcf2ee353f353eae4eb31713de9d4791f6d8126e4427ef9e7125562e26b53c85f0a92e09bfe120e8f24f04
7
+ data.tar.gz: 5e943e567b069fd2b2e21c77fdc7a48ad3e81fb365832439cd1f402da838b5771bc7af4b2293bf635fa1b6de158ddfbea78f9981e690ce3e72a6149c6b042bd2
@@ -133,9 +133,12 @@ module TwistyPuzzles
133
133
 
134
134
  def *(other)
135
135
  raise TypeError unless other.is_a?(Integer)
136
- raise ArgumentError if other.negative?
137
136
 
138
- self.class.new(@moves * other)
137
+ if other.negative?
138
+ inverse * -other
139
+ else
140
+ self.class.new(@moves * other)
141
+ end
139
142
  end
140
143
 
141
144
  def compiled_for_skewb
@@ -83,6 +83,21 @@ module TwistyPuzzles
83
83
  end
84
84
  end
85
85
 
86
+ # Slash commutator of the form A B A2 B' A.
87
+ class SlashCommutator < PureCommutator
88
+ def inverse
89
+ SlashCommutator.new(first_part.inverse, second_part)
90
+ end
91
+
92
+ def to_s
93
+ "[#{@first_part}/#{@second_part}]"
94
+ end
95
+
96
+ def algorithm
97
+ first_part + second_part + (first_part * 2) + second_part.inverse + first_part
98
+ end
99
+ end
100
+
86
101
  # Setup commutator of the form A B A'.
87
102
  class SetupCommutator < Commutator
88
103
  def initialize(setup, inner_commutator)
@@ -28,7 +28,7 @@ module TwistyPuzzles
28
28
 
29
29
  # Middle coordinate for uneven numbers, the one before for even numbers
30
30
  def self.middle_or_before(cube_size)
31
- cube_size - cube_size / 2 - 1
31
+ cube_size - (cube_size / 2) - 1
32
32
  end
33
33
 
34
34
  # Middle coordinate for uneven numbers, the one after for even numbers
@@ -38,7 +38,7 @@ module TwistyPuzzles
38
38
 
39
39
  # The last coordinate that is strictly before the middle
40
40
  def self.last_before_middle(cube_size)
41
- cube_size / 2 - 1
41
+ (cube_size / 2) - 1
42
42
  end
43
43
 
44
44
  def self.canonicalize(index, cube_size)
@@ -310,7 +310,7 @@ module TwistyPuzzles
310
310
 
311
311
  def self.for_corner(corner)
312
312
  native = Native::SkewbCoordinate.for_corner(corner.face_symbols)
313
- 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)
314
314
  end
315
315
 
316
316
  def hash
@@ -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.split('').map do |e|
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 == 3
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)
@@ -16,6 +16,12 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
16
16
  OPENING_PAREN = '('
17
17
  CLOSING_BRACKET = ']'
18
18
  CLOSING_PAREN = ')'
19
+ SLASH = '/'
20
+ COMMA = ','
21
+ SETUP_SEPARATORS = %w[; :].freeze
22
+ PURE_SEPARATORS = [SLASH, COMMA].freeze
23
+ SEPARATORS = (SETUP_SEPARATORS + PURE_SEPARATORS).freeze
24
+
19
25
  TIMES = '*'
20
26
 
21
27
  def initialize(alg_string, move_parser)
@@ -77,8 +83,8 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
77
83
  end
78
84
 
79
85
  # Parses at least one move.
80
- def parse_nonempty_moves
81
- moves = parse_moves
86
+ def parse_nonempty_moves_with_triggers
87
+ moves = parse_moves_with_triggers
82
88
  complain('move') if moves.empty?
83
89
  moves
84
90
  end
@@ -117,10 +123,26 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
117
123
  if @scanner.peek(1) == OPENING_BRACKET
118
124
  parse_commutator_internal
119
125
  else
120
- FakeCommutator.new(parse_moves_with_triggers)
126
+ parse_commutator_no_brackets
121
127
  end
122
128
  end
123
129
 
130
+ def parse_commutator_no_brackets
131
+ setup_or_first_part_or_algorithm = parse_moves_with_triggers
132
+ skip_spaces
133
+ if @scanner.eos? || !SEPARATORS.include?(@scanner.peek(1))
134
+ return FakeCommutator.new(setup_or_first_part_or_algorithm)
135
+ end
136
+
137
+ setup_or_first_part = setup_or_first_part_or_algorithm
138
+ complain('move') if setup_or_first_part.empty?
139
+ separator = parse_separator
140
+ comm = parse_commutator_internal_after_separator(setup_or_first_part, separator)
141
+ skip_spaces
142
+ complain('end of commutator') unless @scanner.eos?
143
+ comm
144
+ end
145
+
124
146
  def parse_algorithm
125
147
  skip_spaces
126
148
  parse_moves_with_triggers
@@ -131,40 +153,77 @@ module TwistyPuzzles # rubocop:disable Style/Documentation
131
153
  if @scanner.peek(1) == OPENING_BRACKET
132
154
  parse_pure_commutator
133
155
  else
134
- FakeCommutator.new(parse_moves_with_triggers)
156
+ parse_pure_commutator_no_brackets
135
157
  end
136
158
  end
137
159
 
138
160
  def parse_pure_commutator
139
161
  skip_spaces
140
162
  parse_open_bracket
141
- first_part = parse_nonempty_moves
163
+ first_part = parse_nonempty_moves_with_triggers
142
164
  skip_spaces
143
- complain('middle of pure commutator') unless @scanner.getch == ','
144
- second_part = parse_nonempty_moves
165
+ separator = parse_pure_separator
166
+ second_part = parse_nonempty_moves_with_triggers
145
167
  skip_spaces
146
168
  parse_close_bracket
147
- PureCommutator.new(first_part, second_part)
169
+ pseudo_pure_commutator(separator, first_part, second_part)
170
+ end
171
+
172
+ def parse_pure_commutator_no_brackets
173
+ first_part_or_algorithm = parse_moves_with_triggers
174
+ skip_spaces
175
+ if @scanner.eos? || !PURE_SEPARATORS.include?(@scanner.peek(1))
176
+ return FakeCommutator.new(first_part_or_algorithm)
177
+ end
178
+
179
+ first_part = first_part_or_algorithm
180
+ complain('move') if first_part.empty?
181
+ separator = parse_pure_separator
182
+ second_part = parse_nonempty_moves_with_triggers
183
+ skip_spaces
184
+ pseudo_pure_commutator(separator, first_part, second_part)
185
+ end
186
+
187
+ def parse_pure_separator
188
+ separator = @scanner.getch
189
+ complain('middle of pure commutator') unless PURE_SEPARATORS.include?(separator)
190
+ separator
148
191
  end
149
192
 
150
193
  def parse_commutator_internal_after_separator(setup_or_first_part, separator)
151
- if [':', ';'].include?(separator)
194
+ if SETUP_SEPARATORS.include?(separator)
152
195
  inner_commutator = parse_setup_commutator_inner
153
196
  SetupCommutator.new(setup_or_first_part, inner_commutator)
154
- elsif separator == ','
155
- second_part = parse_nonempty_moves
156
- PureCommutator.new(setup_or_first_part, second_part)
197
+ elsif PURE_SEPARATORS.include?(separator)
198
+ second_part = parse_nonempty_moves_with_triggers
199
+ pseudo_pure_commutator(separator, setup_or_first_part, second_part)
157
200
  else
158
201
  complain('end of setup or middle of pure commutator') unless @scanner.eos?
159
202
  end
160
203
  end
161
204
 
205
+ def pseudo_pure_commutator(separator, first_part, second_part)
206
+ if separator == COMMA
207
+ PureCommutator.new(first_part, second_part)
208
+ elsif separator == SLASH
209
+ SlashCommutator.new(first_part, second_part)
210
+ else
211
+ complain('middle of pure commutator') unless PURE_SEPARATORS.include?(separator)
212
+ end
213
+ end
214
+
215
+ def parse_separator
216
+ separator = @scanner.getch
217
+ complain('separator between commutator parts') unless SEPARATORS.include?(separator)
218
+ separator
219
+ end
220
+
162
221
  def parse_commutator_internal
163
222
  skip_spaces
164
223
  parse_open_bracket
165
- setup_or_first_part = parse_nonempty_moves
224
+ setup_or_first_part = parse_nonempty_moves_with_triggers
166
225
  skip_spaces
167
- separator = @scanner.getch
226
+ separator = parse_separator
168
227
  comm = parse_commutator_internal_after_separator(setup_or_first_part, separator)
169
228
  skip_spaces
170
229
  parse_close_bracket
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwistyPuzzles
4
- VERSION = '0.0.11'
4
+ VERSION = '0.0.15'
5
5
  end
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.11
4
+ version: 0.0.15
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-03-04 00:00:00.000000000 Z
11
+ date: 2021-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize