Class: TwistyPuzzles::Algorithm

Inherits:
Object
  • Object
show all
Includes:
Comparable, ReversibleApplyable
Defined in:
lib/twisty_puzzles/algorithm.rb

Overview

Represents a sequence of moves that can be applied to puzzle states.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ReversibleApplyable

#apply_temporarily_to, #apply_to_dupped

Constructor Details

#initialize(moves) ⇒ Algorithm

Returns a new instance of Algorithm.



16
17
18
19
20
21
# File 'lib/twisty_puzzles/algorithm.rb', line 16

def initialize(moves)
  moves.each do |m|
    raise TypeError, "#{m.inspect} is not a suitable move." unless m.is_a?(AbstractMove)
  end
  @moves = moves
end

Instance Attribute Details

#inverseObject



71
72
73
74
75
76
77
78
# File 'lib/twisty_puzzles/algorithm.rb', line 71

def inverse
  @inverse ||=
    begin
      alg = self.class.new(@moves.reverse.map(&:inverse))
      alg.inverse = self
      alg
    end
end

#movesObject (readonly)

Returns the value of attribute moves.



32
33
34
# File 'lib/twisty_puzzles/algorithm.rb', line 32

def moves
  @moves
end

Class Method Details

.emptyObject



23
24
25
# File 'lib/twisty_puzzles/algorithm.rb', line 23

def self.empty
  Algorithm.new([])
end

.move(move) ⇒ Object

Creates a one move algorithm.



28
29
30
# File 'lib/twisty_puzzles/algorithm.rb', line 28

def self.move(move)
  Algorithm.new([move])
end

Instance Method Details

#*(other) ⇒ Object

Raises:

  • (TypeError)


136
137
138
139
140
141
142
143
144
# File 'lib/twisty_puzzles/algorithm.rb', line 136

def *(other)
  raise TypeError unless other.is_a?(Integer)

  if other.negative?
    inverse * -other
  else
    self.class.new(@moves * other)
  end
end

#+(other) ⇒ Object



80
81
82
# File 'lib/twisty_puzzles/algorithm.rb', line 80

def +(other)
  self.class.new(@moves + other.moves)
end

#<=>(other) ⇒ Object



84
85
86
# File 'lib/twisty_puzzles/algorithm.rb', line 84

def <=>(other)
  [length, @moves] <=> [other.length, other.moves]
end

#apply_to(cube_state) ⇒ Object



60
61
62
63
64
65
66
67
68
69
# File 'lib/twisty_puzzles/algorithm.rb', line 60

def apply_to(cube_state)
  case cube_state
  when SkewbState
    compiled_for_skewb.apply_to(cube_state)
  when CubeState
    compiled_for_cube(cube_state.n).apply_to(cube_state)
  else
    raise TypeError, "Unsupported cube state class #{cube_state.class}."
  end
end

#cancellations(other, cube_size, metric = :htm) ⇒ Object

Returns the number of moves that cancel if you concat the algorithm to the right of self. Note that the cube size is important to know which fat moves cancel



96
97
98
99
100
101
102
103
104
105
# File 'lib/twisty_puzzles/algorithm.rb', line 96

def cancellations(other, cube_size, metric = :htm)
  CubeState.check_cube_size(cube_size)
  AbstractMove.check_move_metric(metric)
  cancelled = cancelled(cube_size)
  other_cancelled = other.cancelled(cube_size)
  together_cancelled = (self + other).cancelled(cube_size)
  cancelled.move_count(cube_size, metric) +
    other_cancelled.move_count(cube_size, metric) -
    together_cancelled.move_count(cube_size, metric)
end

#cancelled(cube_size) ⇒ Object

Returns the cancelled version of the given algorithm. Note that the cube size is important to know which fat moves cancel



90
91
92
# File 'lib/twisty_puzzles/algorithm.rb', line 90

def cancelled(cube_size)
  CancellationHelper.cancel(self, cube_size)
end

#compiled_for_cube(cube_size) ⇒ Object



150
151
152
153
# File 'lib/twisty_puzzles/algorithm.rb', line 150

def compiled_for_cube(cube_size)
  (@compiled_for_cube ||= {})[cube_size] ||=
    CompiledCubeAlgorithm.for_moves(cube_size, @moves)
end

#compiled_for_skewbObject



146
147
148
# File 'lib/twisty_puzzles/algorithm.rb', line 146

def compiled_for_skewb
  @compiled_for_skewb ||= CompiledSkewbAlgorithm.for_moves(@moves)
end

#empty?Boolean

Returns:

  • (Boolean)


48
49
50
# File 'lib/twisty_puzzles/algorithm.rb', line 48

def empty?
  @moves.empty?
end

#eql?(other) ⇒ Boolean Also known as: ==

Returns:

  • (Boolean)


34
35
36
# File 'lib/twisty_puzzles/algorithm.rb', line 34

def eql?(other)
  self.class.equal?(other.class) && @moves == other.moves
end

#hashObject



40
41
42
# File 'lib/twisty_puzzles/algorithm.rb', line 40

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

#inspectObject



56
57
58
# File 'lib/twisty_puzzles/algorithm.rb', line 56

def inspect
  "Algorithm(#{self})"
end

#lengthObject



44
45
46
# File 'lib/twisty_puzzles/algorithm.rb', line 44

def length
  @moves.length
end

#mirror(normal_face) ⇒ Object

Mirrors the algorithm and uses the given face as the normal of the mirroring. E.g. mirroring “R U F” with “R” as the normal face, we get “L U’ F’”.

Raises:

  • (TypeError)


119
120
121
122
123
# File 'lib/twisty_puzzles/algorithm.rb', line 119

def mirror(normal_face)
  raise TypeError unless normal_face.is_a?(Face)

  self.class.new(@moves.map { |m| m.mirror(normal_face) })
end

#move_count(cube_size, metric = :htm) ⇒ Object

Cube size is needed to decide whether ‘u’ is a slice move (like on bigger cubes) or a fat move (like on 3x3).

Raises:

  • (TypeError)


127
128
129
130
131
132
133
134
# File 'lib/twisty_puzzles/algorithm.rb', line 127

def move_count(cube_size, metric = :htm)
  raise TypeError unless cube_size.is_a?(Integer)

  AbstractMove.check_move_metric(metric)
  return 0 if empty?

  @moves.sum { |m| m.move_count(cube_size, metric) }
end

#rotate_by(rotation) ⇒ Object

Rotates the algorithm, e.g. applying “y” to “R U” becomes “F U”. Applying rotation r to alg a is equivalent to r’ a r. Note that this is not implemented for all moves.

Raises:

  • (TypeError)


110
111
112
113
114
115
# File 'lib/twisty_puzzles/algorithm.rb', line 110

def rotate_by(rotation)
  raise TypeError unless rotation.is_a?(Rotation)
  return self if rotation.direction.zero?

  self.class.new(@moves.map { |m| m.rotate_by(rotation) })
end

#to_sObject



52
53
54
# File 'lib/twisty_puzzles/algorithm.rb', line 52

def to_s
  @moves.join(' ')
end