Class: TwistyPuzzles::PartCycle
Overview
A cycle of parts of the cube, e.g. a corner 3 cycle. Note that this is abstract and contains no information on the cube size. E.g. for wings on a 7x7, it’s not clear whether inner or outer wings are used. Check StickerCycleFactory for making it concrete and applyable.
Constant Summary
collapse
- RAW_DATA_RESERVED =
[' ', '(', ')'].freeze
Instance Attribute Summary collapse
Class Method Summary
collapse
Instance Method Summary
collapse
camel_case_to_snake_case, format_time, simple_class_name, snake_case_class_name
#apply_permutation, #check_types, #find_only, #only, #replace_once, #rotate_out_nils, #turned_equals?
Constructor Details
#initialize(parts, twist = 0) ⇒ PartCycle
Returns a new instance of PartCycle.
20
21
22
23
24
25
26
27
28
29
30
31
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 20
def initialize(parts, twist = 0)
raise ArgumentError if parts.empty?
raise TypeError unless twist.is_a?(Integer)
raise ArgumentError if twist.negative?
raise ArgumentError if twist >= parts.first.rotations.length
check_types(parts, Part)
check_type_consistency(parts)
@parts = parts
@twist = twist
end
|
Instance Attribute Details
#parts ⇒ Object
Returns the value of attribute parts.
33
34
35
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 33
def parts
@parts
end
|
#twist ⇒ Object
Returns the value of attribute twist.
33
34
35
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 33
def twist
@twist
end
|
Class Method Details
.from_raw_data(data) ⇒ Object
119
120
121
122
123
124
125
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 119
def self.from_raw_data(data)
raw_part_type, raw_parts, raw_twist = data.match(/^(.*)\((.*?)(?:, (.+))?\)$/).captures
part_type = PART_TYPES.find { |p| simple_class_name(p) == raw_part_type }
twist = raw_twist ? Integer(raw_twist) : 0
parts = raw_parts.split.map { |r| part_type.parse(r) }
new(parts, twist)
end
|
Instance Method Details
#<=>(other) ⇒ Object
79
80
81
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 79
def <=>(other)
[part_type.name, @parts, @twist] <=> [other.part_type.name, other.parts, other.twist]
end
|
#canonicalize ⇒ Object
83
84
85
86
87
88
89
90
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 83
def canonicalize
@canonicalize ||=
@parts.map.with_index do |part, index|
min_part = part.rotations.min
map_rotate_by_number = part.rotations.index(min_part)
rotate_by(index).map_rotate_by(map_rotate_by_number)
end.min
end
|
#contains?(part) ⇒ Boolean
Note that this returns the same answer for all rotations of one part.
93
94
95
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 93
def contains?(part)
@parts.any? { |p| p.turned_equals?(part) }
end
|
#contains_any_part?(parts) ⇒ Boolean
54
55
56
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 54
def contains_any_part?(parts)
parts.any? { |p| contains?(p) }
end
|
#eql?(other) ⇒ Boolean
Also known as:
==
35
36
37
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 35
def eql?(other)
self.class.equal?(other.class) && @parts == other.parts && @twist == other.twist
end
|
#equivalent?(other) ⇒ Boolean
107
108
109
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 107
def equivalent?(other)
self == other || canonicalize == other.canonicalize
end
|
#hash ⇒ Object
46
47
48
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 46
def hash
@hash ||= [self.class, @parts, @twist].hash
end
|
#inspect ⇒ Object
41
42
43
44
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 41
def inspect
@inspect ||=
"#{self.class.name.split('::').last}(#{@parts.map(&:inspect).join(', ')}#{twist_suffix})"
end
|
#inverse ⇒ Object
115
116
117
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 115
def inverse
self.class.new([@parts[0]] + @parts[1..].reverse, inverse_twist)
end
|
#inverse_twist ⇒ Object
111
112
113
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 111
def inverse_twist
@twist.zero? ? @twist : parts.first.rotations.length - @twist
end
|
#length ⇒ Object
67
68
69
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 67
def length
@parts.length
end
|
#map_rotate_by(number) ⇒ Object
75
76
77
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 75
def map_rotate_by(number)
self.class.new(@parts.map { |p| p.rotate_by(number) }, @twist)
end
|
#mirror(normal_face) ⇒ Object
134
135
136
137
138
139
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 134
def mirror(normal_face)
raise TypeError unless normal_face.is_a?(Face)
mirrored_parts = @parts.map { |p| p.mirror(normal_face) }
self.class.new(mirrored_parts, inverse_twist)
end
|
#part_type ⇒ Object
50
51
52
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 50
def part_type
@parts.first.class
end
|
#rotate_by(number) ⇒ Object
71
72
73
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 71
def rotate_by(number)
self.class.new(@parts.rotate(number), @twist)
end
|
#rotate_by_rotation(rotation) ⇒ Object
127
128
129
130
131
132
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 127
def rotate_by_rotation(rotation)
raise TypeError unless rotation.is_a?(Rotation)
rotated_parts = @parts.map { |p| p.rotate_by_rotation(rotation) }
PartCycle.new(rotated_parts, @twist)
end
|
#start_with(part) ⇒ Object
Returns an equivalent cycle that starts with the given part. Raises an error if the cycle doesn’t contain the given part.
99
100
101
102
103
104
105
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 99
def start_with(part)
raise ArgumentError unless contains?(part)
index = @parts.find_index { |p| p.turned_equals?(part) }
map_rotate_by_number = @parts[index].rotations.index(part)
rotate_by(index).map_rotate_by(map_rotate_by_number)
end
|
#to_raw_data ⇒ Object
62
63
64
65
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 62
def to_raw_data
@to_raw_data ||=
"#{simple_class_name(part_type)}(#{self}#{twist_suffix})"
end
|
#to_s ⇒ Object
58
59
60
|
# File 'lib/twisty_puzzles/part_cycle.rb', line 58
def to_s
@to_s ||= @parts.join(' ')
end
|