Class: TwistyPuzzles::AbstractMove
Overview
Constant Summary
collapse
- AXES =
%w[y z x].freeze
- SLICE_FACES =
rubocop:disable Style/StringHashKeys
{ 'E' => Face::D, 'S' => Face::F, 'M' => Face::L }.freeze
- SLICE_NAMES =
rubocop:enable Style/StringHashKeys
SLICE_FACES.invert.freeze
- MOVE_METRICS =
%i[qtm htm stm sqtm qstm].freeze
Class Method Summary
collapse
Instance Method Summary
collapse
-
#<=>(other) ⇒ Object
-
#can_swap?(other) ⇒ Boolean
-
#decide_meaning(_cube_size) ⇒ Object
We handle the annoying inconsistency that u is a slice move for bigger cubes, but a fat move for 3x3.
-
#direction ⇒ Object
-
#eql?(other) ⇒ Boolean
(also: #==)
-
#equivalent?(other, cube_size) ⇒ Boolean
-
#equivalent_internal?(other, _cube_size) ⇒ Boolean
-
#hash ⇒ Object
-
#identifying_fields ⇒ Object
-
#identity? ⇒ Boolean
-
#inverse ⇒ Object
-
#join_with_cancellation(other, cube_size) ⇒ Object
Return an algorithm from cancelling this move with ‘other` and cancelling as much as possible.
-
#mirror(_normal_face) ⇒ Object
-
#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).
-
#prepend_inner_m_slice_move(other, cube_size) ⇒ Object
In terms of prepending, inner M slice moves are exactly like other slice moves.
-
#prepend_slice_move(_other, _cube_size) ⇒ Object
-
#puzzles ⇒ Object
The superclass for all moves that work on the same type puzzle as the given one (modulo cube size, i.e. 3x3 is the same as 4x4, but Skewb is different).
-
#rotate_by(_rotation) ⇒ Object
-
#slice_move? ⇒ Boolean
-
#swap(other) ⇒ Object
For moves A, B, returns [C, D] if they can be swapped.
-
#swap_internal(other) ⇒ Object
#apply_permutation, #check_types, #find_only, #only, #replace_once, #rotate_out_nils, #turned_equals?
#camel_case_to_snake_case, #format_time, #simple_class_name, #snake_case_class_name
Class Method Details
.check_move_metric(metric) ⇒ Object
48
49
50
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 48
def self.check_move_metric(metric)
raise ArgumentError, "Invalid move metric #{metric}." unless MOVE_METRICS.include?(metric)
end
|
Instance Method Details
#<=>(other) ⇒ Object
21
22
23
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 21
def <=>(other)
[self.class.name] + identifying_fields <=> [other.class.name] + other.identifying_fields
end
|
#can_swap?(other) ⇒ Boolean
60
61
62
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 60
def can_swap?(other)
is_a?(Rotation) || other.is_a?(Rotation)
end
|
#decide_meaning(_cube_size) ⇒ Object
We handle the annoying inconsistency that u is a slice move for bigger cubes, but a fat move for 3x3. Furthermore, M slice moves are fat m slice moves for even cubes and normal m slice moves for odd cubes.
137
138
139
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 137
def decide_meaning(_cube_size)
self
end
|
#direction ⇒ Object
99
100
101
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 99
def direction
raise NotImplementedError
end
|
#eql?(other) ⇒ Boolean
Also known as:
==
29
30
31
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 29
def eql?(other)
self.class == other.class && identifying_fields == other.identifying_fields
end
|
#equivalent?(other, cube_size) ⇒ Boolean
52
53
54
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 52
def equivalent?(other, cube_size)
decide_meaning(cube_size).equivalent_internal?(other.decide_meaning(cube_size), cube_size)
end
|
#equivalent_internal?(other, _cube_size) ⇒ Boolean
56
57
58
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 56
def equivalent_internal?(other, _cube_size)
self == other
end
|
#hash ⇒ Object
25
26
27
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 25
def hash
@hash ||= [self.class, identifying_fields].hash
end
|
#identifying_fields ⇒ Object
35
36
37
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 35
def identifying_fields
raise NotImplementedError
end
|
#identity? ⇒ Boolean
44
45
46
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 44
def identity?
direction.zero?
end
|
#inverse ⇒ Object
39
40
41
42
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 39
def inverse
fields = replace_once(identifying_fields, direction, direction.inverse)
self.class.new(*fields)
end
|
#join_with_cancellation(other, cube_size) ⇒ Object
Return an algorithm from cancelling this move with ‘other` and cancelling as much as possible. Note that it doesn’t cancel rotations with moves even if we theoretically could do this by using uncanonical wide moves. Expects prepend_xyz methods to be present. That one can return a cancelled implementation or nil if nothing can be cancelled.
123
124
125
126
127
128
129
130
131
132
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 123
def join_with_cancellation(other, cube_size)
raise ArgumentError if (puzzles & other.puzzles).empty?
maybe_alg = prepend_to(other, cube_size)
if maybe_alg
Algorithm.new(maybe_alg.moves.select { |m| m.direction.non_zero? })
else
Algorithm.new([self, other].select { |m| m.direction.non_zero? })
end
end
|
#mirror(_normal_face) ⇒ Object
107
108
109
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 107
def mirror(_normal_face)
raise NotImplementedError
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).
84
85
86
87
88
89
90
91
92
93
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 84
def move_count(cube_size, metric = :htm)
raise TypeError unless cube_size.is_a?(Integer)
AbstractMove.check_move_metric(metric)
return 0 if direction.zero?
slice_factor = decide_meaning(cube_size).slice_move? ? 2 : 1
direction_factor = direction.double_move? ? 2 : 1
move_count_internal(metric, slice_factor, direction_factor)
end
|
#prepend_inner_m_slice_move(other, cube_size) ⇒ Object
In terms of prepending, inner M slice moves are exactly like other slice moves.
142
143
144
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 142
def prepend_inner_m_slice_move(other, cube_size)
prepend_slice_move(other, cube_size)
end
|
#prepend_slice_move(_other, _cube_size) ⇒ Object
146
147
148
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 146
def prepend_slice_move(_other, _cube_size)
raise NotImplementedError, "#{self.class}#prepend_slice_move is not implemented"
end
|
#puzzles ⇒ Object
The superclass for all moves that work on the same type puzzle as the given one (modulo cube size, i.e. 3x3 is the same as 4x4, but Skewb is different).
113
114
115
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 113
def puzzles
raise NotImplementedError
end
|
#rotate_by(_rotation) ⇒ Object
103
104
105
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 103
def rotate_by(_rotation)
raise NotImplementedError
end
|
#slice_move? ⇒ Boolean
95
96
97
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 95
def slice_move?
raise NotImplementedError, "Not implemented for #{self}:#{self.class}."
end
|
#swap(other) ⇒ Object
For moves A, B, returns [C, D] if they can be swapped.
65
66
67
68
69
70
71
72
73
74
75
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 65
def swap(other)
raise ArgumentError unless can_swap?(other)
if is_a?(Rotation)
[other.rotate_by(inverse), self]
elsif other.is_a?(Rotation)
[other, rotate_by(other)]
else
swap_internal(other)
end
end
|
#swap_internal(other) ⇒ Object
77
78
79
80
|
# File 'lib/twisty_puzzles/abstract_move.rb', line 77
def swap_internal(other)
raise NotImplementedError,
"Not implemented for #{self}:#{self.class} and #{other}:#{other.class}."
end
|