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
@@ -8,66 +8,65 @@ require 'twisty_puzzles/skewb_move'
8
8
  require 'twisty_puzzles/skewb_notation'
9
9
 
10
10
  module TwistyPuzzles
11
-
12
- # Parser for Skewb moves.
13
- class SkewbMoveParser < AbstractMoveParser
14
- MOVE_TYPE_CREATORS = [
15
- MoveTypeCreator.new(%i[axis_face cube_direction], Rotation),
16
- MoveTypeCreator.new(%i[axis_corner skewb_direction], SkewbMove)
17
- ].freeze
11
+ # Parser for Skewb moves.
12
+ class SkewbMoveParser < AbstractMoveParser
13
+ MOVE_TYPE_CREATORS = [
14
+ MoveTypeCreator.new(%i[axis_face cube_direction], Rotation),
15
+ MoveTypeCreator.new(%i[axis_corner skewb_direction], SkewbMove)
16
+ ].freeze
18
17
 
19
- def initialize(notation)
20
- raise TypeError unless notation.is_a?(SkewbNotation)
18
+ def initialize(notation)
19
+ raise TypeError unless notation.is_a?(SkewbNotation)
21
20
 
22
- @notation = notation
23
- end
21
+ @notation = notation
22
+ end
24
23
 
25
- FIXED_CORNER_INSTANCE = SkewbMoveParser.new(SkewbNotation.fixed_corner)
26
- SARAH_INSTANCE = SkewbMoveParser.new(SkewbNotation.sarah)
27
- RUBIKS_INSTANCE = SkewbMoveParser.new(SkewbNotation.rubiks)
24
+ FIXED_CORNER_INSTANCE = SkewbMoveParser.new(SkewbNotation.fixed_corner)
25
+ SARAH_INSTANCE = SkewbMoveParser.new(SkewbNotation.sarah)
26
+ RUBIKS_INSTANCE = SkewbMoveParser.new(SkewbNotation.rubiks)
28
27
 
29
- def regexp
30
- @regexp ||=
31
- begin
32
- skewb_direction_names =
33
- AbstractDirection::POSSIBLE_SKEWB_DIRECTION_NAMES.flatten
34
- move_part = "(?:(?<skewb_move>[#{@notation.move_strings.join}])" \
35
- "(?<skewb_direction>[#{skewb_direction_names.join}]?))"
36
- rotation_direction_names =
37
- AbstractDirection::POSSIBLE_DIRECTION_NAMES.flatten
38
- rotation_direction_names.sort_by! { |e| -e.length }
39
- rotation_part = "(?:(?<axis_name>[#{AbstractMove::AXES.join}])" \
40
- "(?<cube_direction>#{rotation_direction_names.join('|')}))"
41
- Regexp.new("#{move_part}|#{rotation_part}")
42
- end
43
- end
28
+ def regexp
29
+ @regexp ||=
30
+ begin
31
+ skewb_direction_names =
32
+ AbstractDirection::POSSIBLE_SKEWB_DIRECTION_NAMES.flatten
33
+ move_part = "(?:(?<skewb_move>[#{@notation.move_strings.join}])" \
34
+ "(?<skewb_direction>[#{skewb_direction_names.join}]?))"
35
+ rotation_direction_names =
36
+ AbstractDirection::POSSIBLE_DIRECTION_NAMES.flatten
37
+ rotation_direction_names.sort_by! { |e| -e.length }
38
+ rotation_part = "(?:(?<axis_name>[#{AbstractMove::AXES.join}])" \
39
+ "(?<cube_direction>#{rotation_direction_names.join('|')}))"
40
+ Regexp.new("#{move_part}|#{rotation_part}")
41
+ end
42
+ end
44
43
 
45
- def move_type_creators
46
- MOVE_TYPE_CREATORS
47
- end
44
+ def move_type_creators
45
+ MOVE_TYPE_CREATORS
46
+ end
48
47
 
49
- def parse_skewb_direction(direction_string)
50
- if AbstractDirection::POSSIBLE_DIRECTION_NAMES[0].include?(direction_string)
51
- SkewbDirection::FORWARD
52
- elsif AbstractDirection::POSSIBLE_DIRECTION_NAMES[-1].include?(direction_string)
53
- SkewbDirection::BACKWARD
54
- else
55
- raise ArgumentError
56
- end
48
+ def parse_skewb_direction(direction_string)
49
+ if AbstractDirection::POSSIBLE_DIRECTION_NAMES[0].include?(direction_string)
50
+ SkewbDirection::FORWARD
51
+ elsif AbstractDirection::POSSIBLE_DIRECTION_NAMES[-1].include?(direction_string)
52
+ SkewbDirection::BACKWARD
53
+ else
54
+ raise ArgumentError
57
55
  end
56
+ end
58
57
 
59
- def parse_part_key(name)
60
- name.sub('name', 'face').sub('skewb_move', 'axis_corner')
61
- end
58
+ def parse_part_key(name)
59
+ name.sub('name', 'face').sub('skewb_move', 'axis_corner')
60
+ end
62
61
 
63
- def parse_move_part(name, value)
64
- case name
65
- when 'axis_name' then CubeMoveParser::INSTANCE.parse_axis_face(value)
66
- when 'cube_direction' then CubeMoveParser::INSTANCE.parse_direction(value)
67
- when 'skewb_move' then @notation.corner(value)
68
- when 'skewb_direction' then parse_skewb_direction(value)
69
- else raise
70
- end
62
+ def parse_move_part(name, value)
63
+ case name
64
+ when 'axis_name' then CubeMoveParser::INSTANCE.parse_axis_face(value)
65
+ when 'cube_direction' then CubeMoveParser::INSTANCE.parse_direction(value)
66
+ when 'skewb_move' then @notation.corner(value)
67
+ when 'skewb_direction' then parse_skewb_direction(value)
68
+ else raise
71
69
  end
72
70
  end
71
+ end
73
72
  end
@@ -7,141 +7,138 @@ require 'twisty_puzzles/skewb_direction'
7
7
  require 'twisty_puzzles/skewb_move'
8
8
 
9
9
  module TwistyPuzzles
10
-
11
- # Class that represents one notation for Skewb moves, e.g. Sarahs notation or fixed
12
- # corner notation.
13
- class SkewbNotation
14
- def initialize(name, move_corner_pairs)
15
- raise TypeError unless name.is_a?(String)
16
-
17
- check_move_corner_pairs(move_corner_pairs)
18
- @name = name
19
- @move_to_corner = move_corner_pairs.to_h.freeze
20
- @corner_to_move = move_corner_pairs.collect_concat do |m, c|
21
- c.rotations.map { |e| [e, m] }
22
- end.to_h.freeze
23
- @move_strings = move_corner_pairs.map(&:first).freeze
24
- @non_zero_moves =
25
- move_corner_pairs.map(&:last).product(SkewbDirection::NON_ZERO_DIRECTIONS).map do |c, d|
26
- SkewbMove.new(c, d)
27
- end.freeze
28
- freeze
29
- end
30
-
31
- def check_move_corner_pairs(move_corner_pairs)
32
- move_corner_pairs.each do |m|
33
- raise ArgumentError unless m.length == 2
34
- raise TypeError unless m[0].is_a?(String)
35
- raise TypeError unless m[1].is_a?(Corner)
36
- end
37
- if move_corner_pairs.map(&:first).uniq.length != move_corner_pairs.length
38
- raise ArgumentError
39
- end
10
+ # Class that represents one notation for Skewb moves, e.g. Sarahs notation or fixed
11
+ # corner notation.
12
+ class SkewbNotation
13
+ def initialize(name, move_corner_pairs)
14
+ raise TypeError unless name.is_a?(String)
15
+
16
+ check_move_corner_pairs(move_corner_pairs)
17
+ @name = name
18
+ @move_to_corner = move_corner_pairs.to_h.freeze
19
+ @corner_to_move = move_corner_pairs.collect_concat do |m, c|
20
+ c.rotations.map { |e| [e, m] }
21
+ end.to_h.freeze
22
+ @move_strings = move_corner_pairs.map(&:first).freeze
23
+ @non_zero_moves =
24
+ move_corner_pairs.map(&:last).product(SkewbDirection::NON_ZERO_DIRECTIONS).map do |c, d|
25
+ SkewbMove.new(c, d)
26
+ end.freeze
27
+ freeze
28
+ end
40
29
 
41
- check_corner_coverage(move_corner_pairs.map(&:last))
30
+ def check_move_corner_pairs(move_corner_pairs)
31
+ move_corner_pairs.each do |m|
32
+ raise ArgumentError unless m.length == 2
33
+ raise TypeError unless m[0].is_a?(String)
34
+ raise TypeError unless m[1].is_a?(Corner)
42
35
  end
36
+ raise ArgumentError if move_corner_pairs.map(&:first).uniq.length != move_corner_pairs.length
37
+
38
+ check_corner_coverage(move_corner_pairs.map(&:last))
39
+ end
43
40
 
44
- def check_corner_coverage(corners)
45
- corner_closure = corners + corners.map(&:diagonal_opposite)
46
- Corner::ELEMENTS.each do |corner|
47
- unless corner_closure.any? { |c| c.turned_equals?(corner) }
48
- raise ArgumentError,
49
- "Turns around corner #{corner} cannot be represented in notation #{name}."
50
- end
41
+ def check_corner_coverage(corners)
42
+ corner_closure = corners + corners.map(&:diagonal_opposite)
43
+ Corner::ELEMENTS.each do |corner|
44
+ unless corner_closure.any? { |c| c.turned_equals?(corner) }
45
+ raise ArgumentError,
46
+ "Turns around corner #{corner} cannot be represented in notation #{name}."
51
47
  end
52
48
  end
49
+ end
53
50
 
54
- attr_reader :name, :move_strings, :non_zero_moves
55
- private_class_method :new
56
-
57
- def self.fixed_corner
58
- @fixed_corner ||= new(
59
- 'fixed corner', [
60
- ['U', Corner.for_face_symbols(%i[U L B])],
61
- ['R', Corner.for_face_symbols(%i[D R B])],
62
- ['L', Corner.for_face_symbols(%i[D F L])],
63
- ['B', Corner.for_face_symbols(%i[D B L])]
64
- ]
65
- )
66
- end
51
+ attr_reader :name, :move_strings, :non_zero_moves
52
+ private_class_method :new
53
+
54
+ def self.fixed_corner
55
+ @fixed_corner ||= new(
56
+ 'fixed corner', [
57
+ ['U', Corner.for_face_symbols(%i[U L B])],
58
+ ['R', Corner.for_face_symbols(%i[D R B])],
59
+ ['L', Corner.for_face_symbols(%i[D F L])],
60
+ ['B', Corner.for_face_symbols(%i[D B L])]
61
+ ]
62
+ )
63
+ end
67
64
 
68
- def self.sarah
69
- @sarah ||= new(
70
- 'sarah', [
71
- ['F', Corner.for_face_symbols(%i[U R F])],
72
- ['R', Corner.for_face_symbols(%i[U B R])],
73
- ['B', Corner.for_face_symbols(%i[U L B])],
74
- ['L', Corner.for_face_symbols(%i[U F L])]
75
- ]
76
- )
77
- end
65
+ def self.sarah
66
+ @sarah ||= new(
67
+ 'sarah', [
68
+ ['F', Corner.for_face_symbols(%i[U R F])],
69
+ ['R', Corner.for_face_symbols(%i[U B R])],
70
+ ['B', Corner.for_face_symbols(%i[U L B])],
71
+ ['L', Corner.for_face_symbols(%i[U F L])]
72
+ ]
73
+ )
74
+ end
78
75
 
79
- def self.rubiks
80
- @rubiks ||= new(
81
- 'rubiks', [
82
- ['F', Corner.for_face_symbols(%i[U R F])],
83
- ['R', Corner.for_face_symbols(%i[U B R])],
84
- ['B', Corner.for_face_symbols(%i[U L B])],
85
- ['L', Corner.for_face_symbols(%i[U F L])],
86
- ['f', Corner.for_face_symbols(%i[D F R])],
87
- ['r', Corner.for_face_symbols(%i[D R B])],
88
- ['b', Corner.for_face_symbols(%i[D B L])],
89
- ['l', Corner.for_face_symbols(%i[D L F])]
90
- ]
91
- )
92
- end
76
+ def self.rubiks
77
+ @rubiks ||= new(
78
+ 'rubiks', [
79
+ ['F', Corner.for_face_symbols(%i[U R F])],
80
+ ['R', Corner.for_face_symbols(%i[U B R])],
81
+ ['B', Corner.for_face_symbols(%i[U L B])],
82
+ ['L', Corner.for_face_symbols(%i[U F L])],
83
+ ['f', Corner.for_face_symbols(%i[D F R])],
84
+ ['r', Corner.for_face_symbols(%i[D R B])],
85
+ ['b', Corner.for_face_symbols(%i[D B L])],
86
+ ['l', Corner.for_face_symbols(%i[D L F])]
87
+ ]
88
+ )
89
+ end
93
90
 
94
- def to_s
95
- @name
96
- end
91
+ def to_s
92
+ @name
93
+ end
97
94
 
98
- def corner(move)
99
- @move_to_corner[move] || (raise ArgumentError)
100
- end
95
+ def corner(move)
96
+ @move_to_corner[move] || (raise ArgumentError)
97
+ end
101
98
 
102
- def algorithm_to_string(algorithm)
103
- reversed_rotations = []
104
- num_tail_rotations = CancellationHelper.num_tail_rotations(algorithm)
105
- alg_string = algorithm.moves[0...algorithm.length - num_tail_rotations].map do |m|
106
- move_to_string(m, reversed_rotations)
107
- end.join(' ')
108
- new_tail_rotations = reversed_rotations.reverse! +
109
- algorithm.moves[algorithm.length - num_tail_rotations..-1]
110
- cancelled_rotations = Algorithm.new(new_tail_rotations).cancelled(3)
111
- cancelled_rotations.empty? ? alg_string : "#{alg_string} #{cancelled_rotations}"
112
- end
99
+ def algorithm_to_string(algorithm)
100
+ reversed_rotations = []
101
+ num_tail_rotations = CancellationHelper.num_tail_rotations(algorithm)
102
+ alg_string = algorithm.moves[0...algorithm.length - num_tail_rotations].map do |m|
103
+ move_to_string(m, reversed_rotations)
104
+ end.join(' ')
105
+ new_tail_rotations = reversed_rotations.reverse! +
106
+ algorithm.moves[algorithm.length - num_tail_rotations..-1]
107
+ cancelled_rotations = Algorithm.new(new_tail_rotations).cancelled(3)
108
+ cancelled_rotations.empty? ? alg_string : "#{alg_string} #{cancelled_rotations}"
109
+ end
113
110
 
114
- private
111
+ private
115
112
 
116
- def move_to_string(move, reversed_rotations)
117
- reversed_rotations.each { |r| move = move.rotate_by(r.inverse) }
118
- case move
119
- when SkewbMove then skewb_move_to_string(move, reversed_rotations)
120
- when Rotation then move.to_s
121
- else raise ArgumentError, "Couldn't transform #{move} to #{@name} Skewb notation."
122
- end
113
+ def move_to_string(move, reversed_rotations)
114
+ reversed_rotations.each { |r| move = move.rotate_by(r.inverse) }
115
+ case move
116
+ when SkewbMove then skewb_move_to_string(move, reversed_rotations)
117
+ when Rotation then move.to_s
118
+ else raise ArgumentError, "Couldn't transform #{move} to #{@name} Skewb notation."
123
119
  end
120
+ end
124
121
 
125
- def skewb_move_to_string(move, reversed_rotations)
126
- move_string, rotate = move_to_string_internal(move)
127
- if rotate
128
- reversed_additional_rotations =
129
- Rotation.around_corner(move.axis_corner, move.direction).moves.reverse
130
- reversed_rotations.concat(reversed_additional_rotations)
131
- end
132
- "#{move_string}#{move.direction.name}"
122
+ def skewb_move_to_string(move, reversed_rotations)
123
+ move_string, rotate = move_to_string_internal(move)
124
+ if rotate
125
+ reversed_additional_rotations =
126
+ Rotation.around_corner(move.axis_corner, move.direction).moves.reverse
127
+ reversed_rotations.concat(reversed_additional_rotations)
133
128
  end
129
+ "#{move_string}#{move.direction.name}"
130
+ end
134
131
 
135
- # Returns the move string of the given move and true if a rotation has to be done to correct
136
- # for the fact that we actually used the opposite corner.
137
- def move_to_string_internal(move)
138
- if (move_string = @corner_to_move[move.axis_corner])
139
- [move_string, false]
140
- elsif (move_string = @corner_to_move[move.axis_corner.diagonal_opposite])
141
- [move_string, !move.direction.zero?]
142
- else
143
- raise
144
- end
132
+ # Returns the move string of the given move and true if a rotation has to be done to correct
133
+ # for the fact that we actually used the opposite corner.
134
+ def move_to_string_internal(move)
135
+ if (move_string = @corner_to_move[move.axis_corner])
136
+ [move_string, false]
137
+ elsif (move_string = @corner_to_move[move.axis_corner.diagonal_opposite])
138
+ [move_string, !move.direction.zero?]
139
+ else
140
+ raise
145
141
  end
146
142
  end
143
+ end
147
144
  end
@@ -7,157 +7,156 @@ require 'twisty_puzzles/state_helper'
7
7
  require 'twisty_puzzles/cube_constants'
8
8
 
9
9
  module TwistyPuzzles
10
-
11
- # Represents the state (i.e. the sticker positions) of a Skewb.
12
- class SkewbState
13
- include CubePrintHelper
14
- include StateHelper
15
- include CubeConstants
16
- # Pairs of coordinate pairs that should match in case of solved layers.
17
- MATCHING_CORNERS =
18
- begin
19
- matching_corners = []
20
- Corner::ELEMENTS.each do |c1|
21
- Corner::ELEMENTS.each do |c2|
22
- # Take corner pairs that have a common edge.
23
- next unless c1.common_edge_with?(c2)
24
-
25
- check_parts = []
26
- c1.rotations.each do |c1_rot|
27
- next unless c2.face_symbols.include?(c1_rot.face_symbols.first)
28
-
29
- c2_rot = c2.rotate_face_symbol_up(c1_rot.face_symbols.first)
30
- check_parts.push([
31
- SkewbCoordinate.for_corner(c1_rot),
32
- SkewbCoordinate.for_corner(c2_rot)
33
- ])
34
- end
35
- matching_corners.push(check_parts)
10
+ # Represents the state (i.e. the sticker positions) of a Skewb.
11
+ class SkewbState
12
+ include CubePrintHelper
13
+ include StateHelper
14
+ include CubeConstants
15
+ # Pairs of coordinate pairs that should match in case of solved layers.
16
+ MATCHING_CORNERS =
17
+ begin
18
+ matching_corners = []
19
+ Corner::ELEMENTS.each do |c1|
20
+ Corner::ELEMENTS.each do |c2|
21
+ # Take corner pairs that have a common edge.
22
+ next unless c1.common_edge_with?(c2)
23
+
24
+ check_parts = []
25
+ c1.rotations.each do |c1_rot|
26
+ next unless c2.face_symbols.include?(c1_rot.face_symbols.first)
27
+
28
+ c2_rot = c2.rotate_face_symbol_up(c1_rot.face_symbols.first)
29
+ check_parts.push([
30
+ SkewbCoordinate.for_corner(c1_rot),
31
+ SkewbCoordinate.for_corner(c2_rot)
32
+ ])
36
33
  end
34
+ matching_corners.push(check_parts)
37
35
  end
38
- matching_corners.uniq
39
36
  end
40
- # Pairs of stickers that can be used to check whether the "outside" of a layer on the given
41
- # face is a proper layer.
42
- LAYER_CHECK_NEIGHBORS =
43
- begin
44
- layer_check_neighbors = {}
45
- MATCHING_CORNERS.each do |a, b|
46
- [[a.first.face, b], [b.first.face, a]].each do |face, coordinates|
47
- # We take the first one we encounter, but it doesn't matter, we could take any.
48
- layer_check_neighbors[face] ||= coordinates
49
- end
37
+ matching_corners.uniq
38
+ end
39
+ # Pairs of stickers that can be used to check whether the "outside" of a layer on the given
40
+ # face is a proper layer.
41
+ LAYER_CHECK_NEIGHBORS =
42
+ begin
43
+ layer_check_neighbors = {}
44
+ MATCHING_CORNERS.each do |a, b|
45
+ [[a.first.face, b], [b.first.face, a]].each do |face, coordinates|
46
+ # We take the first one we encounter, but it doesn't matter, we could take any.
47
+ layer_check_neighbors[face] ||= coordinates
50
48
  end
51
- layer_check_neighbors
52
49
  end
50
+ layer_check_neighbors
51
+ end
53
52
 
54
- def initialize(native)
55
- raise TypeError unless native.is_a?(Native::SkewbState)
53
+ def initialize(native)
54
+ raise TypeError unless native.is_a?(Native::SkewbState)
56
55
 
57
- @native = native
58
- end
56
+ @native = native
57
+ end
59
58
 
60
- attr_reader :native
59
+ attr_reader :native
61
60
 
62
- def self.for_solved_colors(solved_colors)
63
- native = Native::SkewbState.new(solved_colors)
64
- new(native)
65
- end
61
+ def self.for_solved_colors(solved_colors)
62
+ native = Native::SkewbState.new(solved_colors)
63
+ new(native)
64
+ end
66
65
 
67
- def eql?(other)
68
- self.class.equal?(other.class) && @native == other.native
69
- end
66
+ def eql?(other)
67
+ self.class.equal?(other.class) && @native == other.native
68
+ end
70
69
 
71
- alias == eql?
70
+ alias == eql?
72
71
 
73
- def hash
74
- @hash ||= [self.class, @native].hash
75
- end
72
+ def hash
73
+ @hash ||= [self.class, @native].hash
74
+ end
76
75
 
77
- # TODO: Get rid of this backwards compatibility artifact
78
- def sticker_array(face)
79
- raise TypeError unless face.is_a?(Face)
76
+ # TODO: Get rid of this backwards compatibility artifact
77
+ def sticker_array(face)
78
+ raise TypeError unless face.is_a?(Face)
80
79
 
81
- center_sticker = self[SkewbCoordinate.for_center(face)]
82
- corner_stickers =
83
- face.clockwise_corners.sort.map do |c|
84
- self[SkewbCoordinate.for_corner(c)]
85
- end
86
- [center_sticker] + corner_stickers
87
- end
80
+ center_sticker = self[SkewbCoordinate.for_center(face)]
81
+ corner_stickers =
82
+ face.clockwise_corners.sort.map do |c|
83
+ self[SkewbCoordinate.for_corner(c)]
84
+ end
85
+ [center_sticker] + corner_stickers
86
+ end
88
87
 
89
- def dup
90
- SkewbState.new(@native.dup)
91
- end
88
+ def dup
89
+ SkewbState.new(@native.dup)
90
+ end
92
91
 
93
- def to_s
94
- skewb_string(self, :nocolor)
95
- end
92
+ def to_s
93
+ skewb_string(self, :nocolor)
94
+ end
96
95
 
97
- def colored_to_s
98
- skewb_string(self, :color)
99
- end
96
+ def colored_to_s
97
+ skewb_string(self, :color)
98
+ end
100
99
 
101
- def apply_move(move)
102
- move.apply_to(self)
103
- end
100
+ def apply_move(move)
101
+ move.apply_to(self)
102
+ end
104
103
 
105
- def apply_algorithm(alg)
106
- alg.apply_to(self)
107
- end
104
+ def apply_algorithm(alg)
105
+ alg.apply_to(self)
106
+ end
108
107
 
109
- def apply_rotation(rot)
110
- rot.apply_to_skewb(self)
111
- end
108
+ def apply_rotation(rot)
109
+ rot.apply_to_skewb(self)
110
+ end
112
111
 
113
- def [](coordinate)
114
- @native[coordinate.native]
115
- end
112
+ def [](coordinate)
113
+ @native[coordinate.native]
114
+ end
116
115
 
117
- def []=(coordinate, color)
118
- @native[coordinate.native] = color
119
- sticker_array(coordinate.face)[coordinate.coordinate] = color
120
- end
116
+ def []=(coordinate, color)
117
+ @native[coordinate.native] = color
118
+ sticker_array(coordinate.face)[coordinate.coordinate] = color
119
+ end
121
120
 
122
- def any_layer_solved?
123
- !solved_layers.empty?
124
- end
121
+ def any_layer_solved?
122
+ !solved_layers.empty?
123
+ end
125
124
 
126
- # Returns the color of all solved layers. Empty if there is none.
127
- def solved_layers
128
- solved_faces = Face::ELEMENTS.select { |f| layer_at_face_solved?(f) }
129
- solved_faces.map { |f| self[SkewbCoordinate.for_center(f)] }
130
- end
125
+ # Returns the color of all solved layers. Empty if there is none.
126
+ def solved_layers
127
+ solved_faces = Face::ELEMENTS.select { |f| layer_at_face_solved?(f) }
128
+ solved_faces.map { |f| self[SkewbCoordinate.for_center(f)] }
129
+ end
131
130
 
132
- def layer_solved?(color)
133
- Face::ELEMENTS.any? do |f|
134
- self[SkewbCoordinate.for_center(f)] == color && layer_at_face_solved?(f)
135
- end
131
+ def layer_solved?(color)
132
+ Face::ELEMENTS.any? do |f|
133
+ self[SkewbCoordinate.for_center(f)] == color && layer_at_face_solved?(f)
136
134
  end
135
+ end
137
136
 
138
- def center_face(color)
139
- Face::ELEMENTS.find { |f| self[SkewbCoordinate.for_center(f)] == color }
140
- end
137
+ def center_face(color)
138
+ Face::ELEMENTS.find { |f| self[SkewbCoordinate.for_center(f)] == color }
139
+ end
141
140
 
142
- def layer_check_neighbors(face)
143
- LAYER_CHECK_NEIGHBORS[face]
144
- end
141
+ def layer_check_neighbors(face)
142
+ LAYER_CHECK_NEIGHBORS[face]
143
+ end
145
144
 
146
- # Note that this does NOT say that the layer corresponding to the given face is solved.
147
- # The face argument is used as the position where a solved face is present.
148
- def layer_at_face_solved?(face)
149
- return false unless native.face_solved?(face.face_symbol)
145
+ # Note that this does NOT say that the layer corresponding to the given face is solved.
146
+ # The face argument is used as the position where a solved face is present.
147
+ def layer_at_face_solved?(face)
148
+ return false unless native.face_solved?(face.face_symbol)
150
149
 
151
- layer_check_neighbors(face).map { |c| self[c] }.uniq.length == 1
152
- end
150
+ layer_check_neighbors(face).map { |c| self[c] }.uniq.length == 1
151
+ end
153
152
 
154
- def rotate_face(face, direction)
155
- neighbors = face.neighbors
156
- inverse_order_face = face.coordinate_index_close_to(neighbors[0]) <
157
- face.coordinate_index_close_to(neighbors[1])
158
- direction = direction.inverse if inverse_order_face
159
- cycle = SkewbCoordinate.corners_on_face(face)
160
- apply_4sticker_cycle(cycle, direction)
161
- end
153
+ def rotate_face(face, direction)
154
+ neighbors = face.neighbors
155
+ inverse_order_face = face.coordinate_index_close_to(neighbors[0]) <
156
+ face.coordinate_index_close_to(neighbors[1])
157
+ direction = direction.inverse if inverse_order_face
158
+ cycle = SkewbCoordinate.corners_on_face(face)
159
+ apply_4sticker_cycle(cycle, direction)
162
160
  end
161
+ end
163
162
  end