twisty_puzzles 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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