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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/lib/twisty_puzzles.rb +37 -0
- data/lib/twisty_puzzles/abstract_direction.rb +38 -39
- data/lib/twisty_puzzles/abstract_move_parser.rb +32 -33
- data/lib/twisty_puzzles/algorithm.rb +112 -113
- data/lib/twisty_puzzles/algorithm_transformation.rb +19 -21
- data/lib/twisty_puzzles/axis_face_and_direction_move.rb +55 -56
- data/lib/twisty_puzzles/cancellation_helper.rb +124 -125
- data/lib/twisty_puzzles/commutator.rb +79 -80
- data/lib/twisty_puzzles/compiled_algorithm.rb +31 -32
- data/lib/twisty_puzzles/compiled_cube_algorithm.rb +49 -50
- data/lib/twisty_puzzles/compiled_skewb_algorithm.rb +18 -19
- data/lib/twisty_puzzles/coordinate.rb +245 -246
- data/lib/twisty_puzzles/cube.rb +494 -495
- data/lib/twisty_puzzles/cube_constants.rb +40 -41
- data/lib/twisty_puzzles/cube_direction.rb +15 -18
- data/lib/twisty_puzzles/cube_move.rb +289 -290
- data/lib/twisty_puzzles/cube_move_parser.rb +75 -76
- data/lib/twisty_puzzles/cube_print_helper.rb +132 -133
- data/lib/twisty_puzzles/cube_state.rb +80 -81
- data/lib/twisty_puzzles/move_type_creator.rb +17 -18
- data/lib/twisty_puzzles/parser.rb +176 -179
- data/lib/twisty_puzzles/part_cycle_factory.rb +39 -42
- data/lib/twisty_puzzles/puzzle.rb +16 -17
- data/lib/twisty_puzzles/reversible_applyable.rb +24 -25
- data/lib/twisty_puzzles/rotation.rb +74 -75
- data/lib/twisty_puzzles/skewb_direction.rb +14 -15
- data/lib/twisty_puzzles/skewb_move.rb +48 -49
- data/lib/twisty_puzzles/skewb_move_parser.rb +50 -51
- data/lib/twisty_puzzles/skewb_notation.rb +115 -118
- data/lib/twisty_puzzles/skewb_state.rb +120 -121
- data/lib/twisty_puzzles/state_helper.rb +20 -21
- data/lib/twisty_puzzles/sticker_cycle.rb +43 -44
- data/lib/twisty_puzzles/utils.rb +3 -0
- data/lib/twisty_puzzles/version.rb +3 -1
- 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
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
-
|
37
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
56
|
-
|
35
|
+
stickers_hash = create_stickers_hash(stickers)
|
36
|
+
new(Native::CubeState.new(cube_size, stickers_hash))
|
37
|
+
end
|
57
38
|
|
58
|
-
|
59
|
-
|
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
|
-
|
62
|
-
|
63
|
-
end
|
54
|
+
def initialize(native)
|
55
|
+
raise TypeError unless native.is_a?(Native::CubeState)
|
64
56
|
|
65
|
-
|
57
|
+
@native = native
|
58
|
+
end
|
66
59
|
|
67
|
-
|
68
|
-
|
69
|
-
|
60
|
+
def dup
|
61
|
+
CubeState.new(@native.dup)
|
62
|
+
end
|
70
63
|
|
71
|
-
|
64
|
+
attr_reader :native
|
72
65
|
|
73
|
-
|
74
|
-
|
75
|
-
|
66
|
+
def n
|
67
|
+
@native.cube_size
|
68
|
+
end
|
76
69
|
|
77
|
-
|
70
|
+
def stickers; end
|
78
71
|
|
79
|
-
|
80
|
-
|
81
|
-
|
72
|
+
def eql?(other)
|
73
|
+
self.class.equal?(other.class) && @native == other.native
|
74
|
+
end
|
82
75
|
|
83
|
-
|
84
|
-
def sticker_array(face)
|
85
|
-
raise TypeError unless face.is_a?(Face)
|
76
|
+
alias == eql?
|
86
77
|
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
98
|
-
|
99
|
-
|
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
|
-
|
102
|
-
|
103
|
-
|
96
|
+
def to_s
|
97
|
+
cube_string(self, :nocolor)
|
98
|
+
end
|
104
99
|
|
105
|
-
|
106
|
-
|
107
|
-
|
100
|
+
def colored_to_s
|
101
|
+
cube_string(self, :color)
|
102
|
+
end
|
108
103
|
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
13
|
-
|
14
|
-
|
11
|
+
@capture_keys = capture_keys.freeze
|
12
|
+
@move_class = move_class
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
def applies_to?(parsed_parts)
|
16
|
+
parsed_parts.keys.sort == @capture_keys.sort
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
19
|
+
def create(parsed_parts)
|
20
|
+
raise ArgumentError unless applies_to?(parsed_parts)
|
22
21
|
|
23
|
-
|
24
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
27
|
+
def parse_open_paren
|
28
|
+
complain('beginning of trigger') unless @scanner.getch == OPENING_PAREN
|
29
|
+
end
|
41
30
|
|
42
|
-
|
43
|
-
|
44
|
-
|
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
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
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
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
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
|
-
|
133
|
-
|
134
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
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
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
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
|
-
|
180
|
-
|
181
|
-
|
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
|
-
|
187
|
-
|
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
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
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
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
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
|
206
|
-
|
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
|
-
|
210
|
-
|
176
|
+
def parse_move_internal
|
177
|
+
move = @scanner.scan(@move_parser.regexp)
|
178
|
+
return unless move
|
211
179
|
|
212
|
-
|
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
|
220
|
-
|
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
|