twisty_puzzles 0.0.1 → 0.0.2

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -1
  3. data/lib/twisty_puzzles.rb +37 -0
  4. data/lib/twisty_puzzles/abstract_direction.rb +38 -39
  5. data/lib/twisty_puzzles/abstract_move_parser.rb +32 -33
  6. data/lib/twisty_puzzles/algorithm.rb +112 -113
  7. data/lib/twisty_puzzles/algorithm_transformation.rb +19 -21
  8. data/lib/twisty_puzzles/axis_face_and_direction_move.rb +55 -56
  9. data/lib/twisty_puzzles/cancellation_helper.rb +124 -125
  10. data/lib/twisty_puzzles/commutator.rb +79 -80
  11. data/lib/twisty_puzzles/compiled_algorithm.rb +31 -32
  12. data/lib/twisty_puzzles/compiled_cube_algorithm.rb +49 -50
  13. data/lib/twisty_puzzles/compiled_skewb_algorithm.rb +18 -19
  14. data/lib/twisty_puzzles/coordinate.rb +245 -246
  15. data/lib/twisty_puzzles/cube.rb +494 -495
  16. data/lib/twisty_puzzles/cube_constants.rb +40 -41
  17. data/lib/twisty_puzzles/cube_direction.rb +15 -18
  18. data/lib/twisty_puzzles/cube_move.rb +289 -290
  19. data/lib/twisty_puzzles/cube_move_parser.rb +75 -76
  20. data/lib/twisty_puzzles/cube_print_helper.rb +132 -133
  21. data/lib/twisty_puzzles/cube_state.rb +80 -81
  22. data/lib/twisty_puzzles/move_type_creator.rb +17 -18
  23. data/lib/twisty_puzzles/parser.rb +176 -179
  24. data/lib/twisty_puzzles/part_cycle_factory.rb +39 -42
  25. data/lib/twisty_puzzles/puzzle.rb +16 -17
  26. data/lib/twisty_puzzles/reversible_applyable.rb +24 -25
  27. data/lib/twisty_puzzles/rotation.rb +74 -75
  28. data/lib/twisty_puzzles/skewb_direction.rb +14 -15
  29. data/lib/twisty_puzzles/skewb_move.rb +48 -49
  30. data/lib/twisty_puzzles/skewb_move_parser.rb +50 -51
  31. data/lib/twisty_puzzles/skewb_notation.rb +115 -118
  32. data/lib/twisty_puzzles/skewb_state.rb +120 -121
  33. data/lib/twisty_puzzles/state_helper.rb +20 -21
  34. data/lib/twisty_puzzles/sticker_cycle.rb +43 -44
  35. data/lib/twisty_puzzles/utils.rb +3 -0
  36. data/lib/twisty_puzzles/version.rb +3 -1
  37. metadata +3 -3
@@ -9,105 +9,104 @@ require 'twisty_puzzles/utils/array_helper'
9
9
  require 'twisty_puzzles/native'
10
10
 
11
11
  module TwistyPuzzles
12
-
13
- # Represents the state (i.e. the sticker positions) of a cube.
14
- class CubeState
15
- include Utils::ArrayHelper
16
- include CubePrintHelper
17
- include StateHelper
18
- include CubeConstants
19
-
20
- def self.check_cube_size(cube_size)
21
- raise TypeError unless cube_size.is_a?(Integer)
22
- raise ArgumentError, 'Cubes of size smaller than 2 are not supported.' if cube_size < 2
23
- end
24
-
25
- def self.from_stickers(cube_size, stickers)
26
- CubeState.check_cube_size(cube_size)
27
- unless stickers.length == FACE_SYMBOLS.length
28
- raise ArgumentError, "Cubes must have #{FACE_SYMBOLS.length} sides."
29
- end
30
-
31
- unless stickers.all? { |p| p.length == cube_size && p.all? { |q| q.length == cube_size } }
32
- raise ArgumentError,
33
- "All sides of a #{cube_size}x#{cube_size} must be #{cube_size}x#{cube_size}."
34
- end
12
+ # Represents the state (i.e. the sticker positions) of a cube.
13
+ class CubeState
14
+ include Utils::ArrayHelper
15
+ include CubePrintHelper
16
+ include StateHelper
17
+ include CubeConstants
18
+
19
+ def self.check_cube_size(cube_size)
20
+ raise TypeError unless cube_size.is_a?(Integer)
21
+ raise ArgumentError, 'Cubes of size smaller than 2 are not supported.' if cube_size < 2
22
+ end
35
23
 
36
- stickers_hash = create_stickers_hash(stickers)
37
- new(Native::CubeState.new(cube_size, stickers_hash))
24
+ def self.from_stickers(cube_size, stickers)
25
+ CubeState.check_cube_size(cube_size)
26
+ unless stickers.length == FACE_SYMBOLS.length
27
+ raise ArgumentError, "Cubes must have #{FACE_SYMBOLS.length} sides."
38
28
  end
39
29
 
40
- def self.create_stickers_hash(stickers)
41
- FACE_SYMBOLS.zip(stickers).map do |face_symbol, face_stickers|
42
- face = Face.for_face_symbol(face_symbol)
43
- face_hash = {
44
- stickers: face_stickers,
45
- # Note that in the ruby code, x and y are exchanged s.t. one can say bla[x][y],
46
- # but the C code does the more logical thing,
47
- # so we have to swap coordinates here.
48
- x_base_face_symbol: face.coordinate_index_base_face(1).face_symbol,
49
- y_base_face_symbol: face.coordinate_index_base_face(0).face_symbol
50
- }
51
- [face_symbol, face_hash]
52
- end.to_h
30
+ unless stickers.all? { |p| p.length == cube_size && p.all? { |q| q.length == cube_size } }
31
+ raise ArgumentError,
32
+ "All sides of a #{cube_size}x#{cube_size} must be #{cube_size}x#{cube_size}."
53
33
  end
54
34
 
55
- def initialize(native)
56
- raise TypeError unless native.is_a?(Native::CubeState)
35
+ stickers_hash = create_stickers_hash(stickers)
36
+ new(Native::CubeState.new(cube_size, stickers_hash))
37
+ end
57
38
 
58
- @native = native
59
- end
39
+ def self.create_stickers_hash(stickers)
40
+ FACE_SYMBOLS.zip(stickers).map do |face_symbol, face_stickers|
41
+ face = Face.for_face_symbol(face_symbol)
42
+ face_hash = {
43
+ stickers: face_stickers,
44
+ # Note that in the ruby code, x and y are exchanged s.t. one can say bla[x][y],
45
+ # but the C code does the more logical thing,
46
+ # so we have to swap coordinates here.
47
+ x_base_face_symbol: face.coordinate_index_base_face(1).face_symbol,
48
+ y_base_face_symbol: face.coordinate_index_base_face(0).face_symbol
49
+ }
50
+ [face_symbol, face_hash]
51
+ end.to_h
52
+ end
60
53
 
61
- def dup
62
- CubeState.new(@native.dup)
63
- end
54
+ def initialize(native)
55
+ raise TypeError unless native.is_a?(Native::CubeState)
64
56
 
65
- attr_reader :native
57
+ @native = native
58
+ end
66
59
 
67
- def n
68
- @native.cube_size
69
- end
60
+ def dup
61
+ CubeState.new(@native.dup)
62
+ end
70
63
 
71
- def stickers; end
64
+ attr_reader :native
72
65
 
73
- def eql?(other)
74
- self.class.equal?(other.class) && @native == other.native
75
- end
66
+ def n
67
+ @native.cube_size
68
+ end
76
69
 
77
- alias == eql?
70
+ def stickers; end
78
71
 
79
- def hash
80
- @hash ||= [self.class, @native].hash
81
- end
72
+ def eql?(other)
73
+ self.class.equal?(other.class) && @native == other.native
74
+ end
82
75
 
83
- # TODO: Get rid of this backwards compatibility artifact
84
- def sticker_array(face)
85
- raise TypeError unless face.is_a?(Face)
76
+ alias == eql?
86
77
 
87
- @native.sticker_array(
88
- face.face_symbol,
89
- # Note that in the ruby code, x and y are exchanged s.t. one can say bla[x][y],
90
- # but the C code does the more logical thing,
91
- # so we have to swap coordinates here.
92
- face.coordinate_index_base_face(1).face_symbol,
93
- face.coordinate_index_base_face(0).face_symbol
94
- )
95
- end
78
+ def hash
79
+ @hash ||= [self.class, @native].hash
80
+ end
96
81
 
97
- def to_s
98
- cube_string(self, :nocolor)
99
- end
82
+ # TODO: Get rid of this backwards compatibility artifact
83
+ def sticker_array(face)
84
+ raise TypeError unless face.is_a?(Face)
85
+
86
+ @native.sticker_array(
87
+ face.face_symbol,
88
+ # Note that in the ruby code, x and y are exchanged s.t. one can say bla[x][y],
89
+ # but the C code does the more logical thing,
90
+ # so we have to swap coordinates here.
91
+ face.coordinate_index_base_face(1).face_symbol,
92
+ face.coordinate_index_base_face(0).face_symbol
93
+ )
94
+ end
100
95
 
101
- def colored_to_s
102
- cube_string(self, :color)
103
- end
96
+ def to_s
97
+ cube_string(self, :nocolor)
98
+ end
104
99
 
105
- def [](coordinate)
106
- @native[coordinate.native]
107
- end
100
+ def colored_to_s
101
+ cube_string(self, :color)
102
+ end
108
103
 
109
- def []=(coordinate, color)
110
- @native[coordinate.native] = color
111
- end
104
+ def [](coordinate)
105
+ @native[coordinate.native]
106
+ end
107
+
108
+ def []=(coordinate, color)
109
+ @native[coordinate.native] = color
112
110
  end
111
+ end
113
112
  end
@@ -1,27 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TwistyPuzzles
4
-
5
- # Class for creating one move type from its parts.
6
- # Helper class for parsing logic.
7
- class MoveTypeCreator
8
- def initialize(capture_keys, move_class)
9
- raise TypeError unless move_class.is_a?(Class)
10
- raise TypeError unless capture_keys.all? { |k| k.is_a?(Symbol) }
4
+ # Class for creating one move type from its parts.
5
+ # Helper class for parsing logic.
6
+ class MoveTypeCreator
7
+ def initialize(capture_keys, move_class)
8
+ raise TypeError unless move_class.is_a?(Class)
9
+ raise TypeError unless capture_keys.all? { |k| k.is_a?(Symbol) }
11
10
 
12
- @capture_keys = capture_keys.freeze
13
- @move_class = move_class
14
- end
11
+ @capture_keys = capture_keys.freeze
12
+ @move_class = move_class
13
+ end
15
14
 
16
- def applies_to?(parsed_parts)
17
- parsed_parts.keys.sort == @capture_keys.sort
18
- end
15
+ def applies_to?(parsed_parts)
16
+ parsed_parts.keys.sort == @capture_keys.sort
17
+ end
19
18
 
20
- def create(parsed_parts)
21
- raise ArgumentError unless applies_to?(parsed_parts)
19
+ def create(parsed_parts)
20
+ raise ArgumentError unless applies_to?(parsed_parts)
22
21
 
23
- fields = @capture_keys.map { |name| parsed_parts[name] }
24
- @move_class.new(*fields)
25
- end
22
+ fields = @capture_keys.map { |name| parsed_parts[name] }
23
+ @move_class.new(*fields)
26
24
  end
25
+ end
27
26
  end
@@ -6,217 +6,214 @@ require 'twisty_puzzles/cube_move_parser'
6
6
  require 'twisty_puzzles/skewb_move_parser'
7
7
  require 'twisty_puzzles/twisty_puzzles_error'
8
8
 
9
- module TwistyPuzzles
10
- # rubocop:disable Style/Documentation
11
-
12
- # rubocop:enable Style/Documentation
13
- class CommutatorParseError < TwistyPuzzlesError
14
- end
15
-
16
- # Parser for commutators and algorithms.
17
- class Parser
18
- OPENING_BRACKET = '['
19
- OPENING_PAREN = '('
20
- CLOSING_BRACKET = ']'
21
- CLOSING_PAREN = ')'
22
- TIMES = '*'
23
-
24
- def initialize(alg_string, move_parser)
25
- @alg_string = alg_string
26
- @scanner = StringScanner.new(alg_string)
27
- @move_parser = move_parser
28
- end
29
-
30
- def parse_open_paren
31
- complain('beginning of trigger') unless @scanner.getch == OPENING_PAREN
32
- end
33
-
34
- def parse_close_paren
35
- complain('end of trigger') unless @scanner.getch == CLOSING_PAREN
36
- end
9
+ module TwistyPuzzles # rubocop:disable Style/Documentation
10
+ class CommutatorParseError < TwistyPuzzlesError
11
+ end
12
+
13
+ # Parser for commutators and algorithms.
14
+ class Parser
15
+ OPENING_BRACKET = '['
16
+ OPENING_PAREN = '('
17
+ CLOSING_BRACKET = ']'
18
+ CLOSING_PAREN = ')'
19
+ TIMES = '*'
20
+
21
+ def initialize(alg_string, move_parser)
22
+ @alg_string = alg_string
23
+ @scanner = StringScanner.new(alg_string)
24
+ @move_parser = move_parser
25
+ end
37
26
 
38
- def parse_times
39
- complain('times symbol of multiplier') unless @scanner.getch == TIMES
40
- end
27
+ def parse_open_paren
28
+ complain('beginning of trigger') unless @scanner.getch == OPENING_PAREN
29
+ end
41
30
 
42
- def parse_factor
43
- number = @scanner.scan(/\d+/)
44
- complain('factor of multiplier') unless number
45
- Integer(number, 10)
46
- end
31
+ def parse_close_paren
32
+ complain('end of trigger') unless @scanner.getch == CLOSING_PAREN
33
+ end
47
34
 
48
- def parse_multiplier
49
- skip_spaces
50
- parse_times
51
- skip_spaces
52
- parse_factor
53
- end
35
+ def parse_times
36
+ complain('times symbol of multiplier') unless @scanner.getch == TIMES
37
+ end
54
38
 
55
- def parse_trigger
56
- parse_open_paren
57
- skip_spaces
58
- moves = parse_moves_with_triggers
59
- skip_spaces
60
- parse_close_paren
61
- skip_spaces
62
- case @scanner.peek(1)
63
- when TIMES
64
- moves * parse_multiplier
65
- when ('0'..'9')
66
- moves * parse_factor
67
- else
68
- moves
69
- end
70
- end
39
+ def parse_factor
40
+ number = @scanner.scan(/\d+/)
41
+ complain('factor of multiplier') unless number
42
+ Integer(number, 10)
43
+ end
71
44
 
72
- # Parses at least one move and allows for triggers in parentheses.
73
- def parse_moves_with_triggers
74
- skip_spaces
75
- if @scanner.peek(1) == OPENING_PAREN
76
- parse_trigger + parse_moves_with_triggers
77
- else
78
- parse_moves
79
- end
80
- end
45
+ def parse_multiplier
46
+ skip_spaces
47
+ parse_times
48
+ skip_spaces
49
+ parse_factor
50
+ end
81
51
 
82
- # Parses at least one move.
83
- def parse_nonempty_moves
84
- moves = parse_moves
85
- complain('move') if moves.empty?
52
+ def parse_trigger
53
+ parse_open_paren
54
+ skip_spaces
55
+ moves = parse_moves_with_triggers
56
+ skip_spaces
57
+ parse_close_paren
58
+ skip_spaces
59
+ case @scanner.peek(1)
60
+ when TIMES
61
+ moves * parse_multiplier
62
+ when ('0'..'9')
63
+ moves * parse_factor
64
+ else
86
65
  moves
87
66
  end
67
+ end
88
68
 
89
- # Parses a series of moves.
90
- def parse_moves
91
- moves = []
92
- while (m = begin skip_spaces; parse_move_internal end)
93
- moves.push(m)
94
- end
95
- Algorithm.new(moves)
96
- end
97
-
98
- def complain(parsed_object)
99
- raise CommutatorParseError, <<~ERROR.chomp
100
- Couldn't parse #{parsed_object} here:
101
- #{@alg_string}
102
- #{' ' * @scanner.pos}^"
103
- ERROR
104
- end
105
-
106
- def check_eos(parsed_object)
107
- complain("end of #{parsed_object}") unless @scanner.eos?
108
- end
109
-
110
- def parse_open_bracket
111
- complain('beginning of commutator') unless @scanner.getch == OPENING_BRACKET
69
+ # Parses at least one move and allows for triggers in parentheses.
70
+ def parse_moves_with_triggers
71
+ skip_spaces
72
+ if @scanner.peek(1) == OPENING_PAREN
73
+ parse_trigger + parse_moves_with_triggers
74
+ else
75
+ parse_moves
112
76
  end
77
+ end
113
78
 
114
- def parse_close_bracket
115
- complain('end of commutator') unless @scanner.getch == CLOSING_BRACKET
116
- end
79
+ # Parses at least one move.
80
+ def parse_nonempty_moves
81
+ moves = parse_moves
82
+ complain('move') if moves.empty?
83
+ moves
84
+ end
117
85
 
118
- def parse_commutator
119
- skip_spaces
120
- if @scanner.peek(1) == OPENING_BRACKET
121
- parse_commutator_internal
122
- else
123
- FakeCommutator.new(parse_moves_with_triggers)
124
- end
86
+ # Parses a series of moves.
87
+ def parse_moves
88
+ moves = []
89
+ while (m = begin skip_spaces; parse_move_internal end)
90
+ moves.push(m)
125
91
  end
92
+ Algorithm.new(moves)
93
+ end
126
94
 
127
- def parse_algorithm
128
- skip_spaces
129
- parse_moves_with_triggers
130
- end
95
+ def complain(parsed_object)
96
+ raise CommutatorParseError, <<~ERROR.chomp
97
+ Couldn't parse #{parsed_object} here:
98
+ #{@alg_string}
99
+ #{' ' * @scanner.pos}^"
100
+ ERROR
101
+ end
131
102
 
132
- def parse_setup_commutator_inner
133
- skip_spaces
134
- if @scanner.peek(1) == OPENING_BRACKET
135
- parse_pure_commutator
136
- else
137
- FakeCommutator.new(parse_moves_with_triggers)
138
- end
139
- end
103
+ def check_eos(parsed_object)
104
+ complain("end of #{parsed_object}") unless @scanner.eos?
105
+ end
140
106
 
141
- def parse_pure_commutator
142
- skip_spaces
143
- parse_open_bracket
144
- first_part = parse_nonempty_moves
145
- skip_spaces
146
- complain('middle of pure commutator') unless @scanner.getch == ','
147
- second_part = parse_nonempty_moves
148
- skip_spaces
149
- parse_close_bracket
150
- PureCommutator.new(first_part, second_part)
151
- end
107
+ def parse_open_bracket
108
+ complain('beginning of commutator') unless @scanner.getch == OPENING_BRACKET
109
+ end
152
110
 
153
- def parse_commutator_internal_after_separator(setup_or_first_part, separator)
154
- if [':', ';'].include?(separator)
155
- inner_commutator = parse_setup_commutator_inner
156
- SetupCommutator.new(setup_or_first_part, inner_commutator)
157
- elsif separator == ','
158
- second_part = parse_nonempty_moves
159
- PureCommutator.new(setup_or_first_part, second_part)
160
- else
161
- complain('end of setup or middle of pure commutator') unless @scanner.eos?
162
- end
163
- end
111
+ def parse_close_bracket
112
+ complain('end of commutator') unless @scanner.getch == CLOSING_BRACKET
113
+ end
164
114
 
165
- def parse_commutator_internal
166
- skip_spaces
167
- parse_open_bracket
168
- setup_or_first_part = parse_nonempty_moves
169
- skip_spaces
170
- separator = @scanner.getch
171
- comm = parse_commutator_internal_after_separator(setup_or_first_part, separator)
172
- skip_spaces
173
- parse_close_bracket
174
- skip_spaces
175
- complain('end of commutator') unless @scanner.eos?
176
- comm
115
+ def parse_commutator
116
+ skip_spaces
117
+ if @scanner.peek(1) == OPENING_BRACKET
118
+ parse_commutator_internal
119
+ else
120
+ FakeCommutator.new(parse_moves_with_triggers)
177
121
  end
122
+ end
178
123
 
179
- def parse_move_internal
180
- move = @scanner.scan(@move_parser.regexp)
181
- return unless move
182
-
183
- @move_parser.parse_move(move)
184
- end
124
+ def parse_algorithm
125
+ skip_spaces
126
+ parse_moves_with_triggers
127
+ end
185
128
 
186
- def skip_spaces
187
- @scanner.skip(/\s+/)
129
+ def parse_setup_commutator_inner
130
+ skip_spaces
131
+ if @scanner.peek(1) == OPENING_BRACKET
132
+ parse_pure_commutator
133
+ else
134
+ FakeCommutator.new(parse_moves_with_triggers)
188
135
  end
189
136
  end
190
137
 
191
- def parse_commutator(alg_string, complete_parse = true)
192
- parser = Parser.new(alg_string, CubeMoveParser::INSTANCE)
193
- commutator = parser.parse_commutator
194
- parser.check_eos('commutator') if complete_parse
195
- commutator
138
+ def parse_pure_commutator
139
+ skip_spaces
140
+ parse_open_bracket
141
+ first_part = parse_nonempty_moves
142
+ skip_spaces
143
+ complain('middle of pure commutator') unless @scanner.getch == ','
144
+ second_part = parse_nonempty_moves
145
+ skip_spaces
146
+ parse_close_bracket
147
+ PureCommutator.new(first_part, second_part)
196
148
  end
197
149
 
198
- def parse_cube_algorithm(alg_string, complete_parse = true)
199
- parser = Parser.new(alg_string, CubeMoveParser::INSTANCE)
200
- algorithm = parser.parse_algorithm
201
- parser.check_eos('algorithm') if complete_parse
202
- algorithm
150
+ def parse_commutator_internal_after_separator(setup_or_first_part, separator)
151
+ if [':', ';'].include?(separator)
152
+ inner_commutator = parse_setup_commutator_inner
153
+ 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)
157
+ else
158
+ complain('end of setup or middle of pure commutator') unless @scanner.eos?
159
+ end
203
160
  end
204
161
 
205
- def parse_cube_move(move_string)
206
- CubeMoveParser::INSTANCE.parse_move(move_string)
162
+ def parse_commutator_internal
163
+ skip_spaces
164
+ parse_open_bracket
165
+ setup_or_first_part = parse_nonempty_moves
166
+ skip_spaces
167
+ separator = @scanner.getch
168
+ comm = parse_commutator_internal_after_separator(setup_or_first_part, separator)
169
+ skip_spaces
170
+ parse_close_bracket
171
+ skip_spaces
172
+ complain('end of commutator') unless @scanner.eos?
173
+ comm
207
174
  end
208
175
 
209
- alias parse_algorithm parse_cube_algorithm
210
- alias parse_move parse_cube_move
176
+ def parse_move_internal
177
+ move = @scanner.scan(@move_parser.regexp)
178
+ return unless move
211
179
 
212
- def parse_skewb_algorithm(alg_string, notation, complete_parse = true)
213
- parser = Parser.new(alg_string, SkewbMoveParser.new(notation))
214
- algorithm = parser.parse_algorithm
215
- parser.check_eos('algorithm') if complete_parse
216
- algorithm
180
+ @move_parser.parse_move(move)
217
181
  end
218
182
 
219
- def parse_skewb_move(move_string, notation)
220
- SkewbMoveParser.new(notation).parse_move(move_string)
183
+ def skip_spaces
184
+ @scanner.skip(/\s+/)
221
185
  end
186
+ end
187
+
188
+ def parse_commutator(alg_string, complete_parse = true)
189
+ parser = Parser.new(alg_string, CubeMoveParser::INSTANCE)
190
+ commutator = parser.parse_commutator
191
+ parser.check_eos('commutator') if complete_parse
192
+ commutator
193
+ end
194
+
195
+ def parse_cube_algorithm(alg_string, complete_parse = true)
196
+ parser = Parser.new(alg_string, CubeMoveParser::INSTANCE)
197
+ algorithm = parser.parse_algorithm
198
+ parser.check_eos('algorithm') if complete_parse
199
+ algorithm
200
+ end
201
+
202
+ def parse_cube_move(move_string)
203
+ CubeMoveParser::INSTANCE.parse_move(move_string)
204
+ end
205
+
206
+ alias parse_algorithm parse_cube_algorithm
207
+ alias parse_move parse_cube_move
208
+
209
+ def parse_skewb_algorithm(alg_string, notation, complete_parse = true)
210
+ parser = Parser.new(alg_string, SkewbMoveParser.new(notation))
211
+ algorithm = parser.parse_algorithm
212
+ parser.check_eos('algorithm') if complete_parse
213
+ algorithm
214
+ end
215
+
216
+ def parse_skewb_move(move_string, notation)
217
+ SkewbMoveParser.new(notation).parse_move(move_string)
218
+ end
222
219
  end