Class: TwistyPuzzles::PartCycle

Inherits:
Object
  • Object
show all
Extended by:
Utils::StringHelper
Includes:
Utils::ArrayHelper, Utils::StringHelper
Defined in:
lib/twisty_puzzles/part_cycle.rb

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

Methods included from Utils::StringHelper

camel_case_to_snake_case, format_time, simple_class_name, snake_case_class_name

Methods included from Utils::ArrayHelper

#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.

Raises:

  • (ArgumentError)


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

#partsObject (readonly)

Returns the value of attribute parts.



33
34
35
# File 'lib/twisty_puzzles/part_cycle.rb', line 33

def parts
  @parts
end

#twistObject (readonly)

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

#canonicalizeObject



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.

Returns:

  • (Boolean)


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

Returns:

  • (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: ==

Returns:

  • (Boolean)


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

Returns:

  • (Boolean)


107
108
109
# File 'lib/twisty_puzzles/part_cycle.rb', line 107

def equivalent?(other)
  self == other || canonicalize == other.canonicalize
end

#hashObject



46
47
48
# File 'lib/twisty_puzzles/part_cycle.rb', line 46

def hash
  @hash ||= [self.class, @parts, @twist].hash
end

#inspectObject



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

#inverseObject



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_twistObject



111
112
113
# File 'lib/twisty_puzzles/part_cycle.rb', line 111

def inverse_twist
  @twist.zero? ? @twist : parts.first.rotations.length - @twist
end

#lengthObject



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

Raises:

  • (TypeError)


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_typeObject



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

Raises:

  • (TypeError)


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.

Raises:

  • (ArgumentError)


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_dataObject



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_sObject



58
59
60
# File 'lib/twisty_puzzles/part_cycle.rb', line 58

def to_s
  @to_s ||= @parts.join(' ')
end