Skip to content

Instantly share code, notes, and snippets.

@doooby
Created January 5, 2021 16:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doooby/d9767a14fd6a92efd4518445d3187f3b to your computer and use it in GitHub Desktop.
Save doooby/d9767a14fd6a92efd4518445d3187f3b to your computer and use it in GitHub Desktop.
it modifies a rubic's cube algorithm
# Usage: cube_mod_alg.rb operation algorithm
# operations can be chained: "op1 | op2"
# algorithm suports basic moves written in standard notaion: "D'L' B'L BD "
# left hand fingers up, palm-away
# thumb = +x
# fingers = +y
# palm = +z
WORLD_AXES = {
x: [ :blue, :green ].freeze,
y: [ :white, :yellow ].freeze,
z: [ :red, :orange ].freeze,
}.freeze
DIR_X_ = [ :x, 1 ].freeze
DIR__X = [ :x, -1 ].freeze
DIR_Y_ = [ :y, 1 ].freeze
DIR__Y = [ :y, -1 ].freeze
DIR_Z_ = [ :z, 1 ].freeze
DIR__Z = [ :z, -1 ].freeze
class Move
MOVE_ROTATIONS = {
x: [ DIR_Y_, DIR_Z_, DIR__Y, DIR__Z ].freeze,
y: [ DIR_X_, DIR__Z, DIR__X, DIR_Z_ ].freeze,
z: [ DIR_X_, DIR_Y_, DIR__X, DIR__Y ].freeze,
}.freeze
attr_reader :axis, :side, :rotation
attr_reader :name
alias inspect name
alias to_s name
def initialize axis, side, rotation
correct = (
[ :x, :y, :z ].include?(axis) &&
[ 1, -1 ].include?(side) &&
[ :cw, :ccw ].include?(rotation)
)
@axis = axis
@side = side
@rotation = rotation
raise "incorrect Move definition: %s %s %s" % [axis, side, rotation] unless correct
end
def reverse
new_rotation = case rotation
when :cw then :ccw
when :ccw then :cw
else raise
end
new_move = MOVE_NOTATION.values.find do |move|
move.axis == axis &&
move.side == side &&
move.rotation == new_rotation
end
new_move or raise
end
def rotate axis, direction
return self if axis == self.axis
rotations = MOVE_ROTATIONS[axis] or raise
index = rotations.index [ self.axis, side ]
case direction
when :cw
index += 1
index = 0 if index == 4
when :ccw
index -= 1
index = 0 if index == -1
else raise
end
new_axis, new_side = rotations[index]
new_move = MOVE_NOTATION.values.find do |move|
move.axis == new_axis &&
move.side == new_side &&
move.rotation == rotation
end
new_move or raise
end
def self.parse_algorithm string
parts = string.strip.split /(?=#{MOVE_EXPRESSION})/
normalized_parts = parts.map do |part|
part.match(/^\s*(#{MOVE_EXPRESSION})\s*$/)&.send :[], 1
end
invalid_part_index = normalized_parts.index &:nil?
if invalid_part_index
normalized_parts[invalid_part_index] = " #{parts[invalid_part_index]} "
puts "invalid notation: #{normalized_parts.join '-'}"
return
end
normalized_parts.map(&:as_move)
end
end
MOVE_NOTATION = {
"R" => Move.new(:x, 1, :cw),
"R'" => Move.new(:x, 1, :ccw),
"L" => Move.new(:x, -1, :cw),
"L'" => Move.new(:x, -1, :ccw),
"U" => Move.new(:y, 1, :cw),
"U'" => Move.new(:y, 1, :ccw),
"D" => Move.new(:y, -1, :cw),
"D'" => Move.new(:y, -1, :ccw),
"F" => Move.new(:z, -1, :cw),
"F'" => Move.new(:z, -1, :ccw),
"B" => Move.new(:z, 1, :cw),
"B'" => Move.new(:z, 1, :ccw),
}
MOVE_NOTATION.freeze
MOVE_NOTATION.each do |name, move|
move.instance_variable_set "@name", name
move.freeze
end
MOVE_EXPRESSION = MOVE_NOTATION.keys.sort_by(&:length).reverse.join('|').freeze
String.class_exec do
def as_move
MOVE_NOTATION[self] or raise "bad move #{self}"
end
end
operation, algorithm, *_ = ARGV
if algorithm.nil?
algorithm = operation
operation = nil
end
algorithm = Move.parse_algorithm algorithm
exit 1 unless algorithm
puts algorithm.join(nil)
OPERATIONS = {
'rev' => -> (alg) {
alg.reverse.map(&:reverse)
},
'rot-x' => -> (alg) {
alg.map{|m| m.rotate :x, :cw}
},
'rot-x\'' => -> (alg) {
alg.map{|m| m.rotate :x, :ccw}
},
'rot-y' => -> (alg) {
alg.map{|m| m.rotate :y, :cw}
},
'rot-y\'' => -> (alg) {
alg.map{|m| m.rotate :y, :ccw}
},
'rot-z' => -> (alg) {
alg.map{|m| m.rotate :z, :cw}
},
'rot-z\'' => -> (alg) {
alg.map{|m| m.rotate :z, :ccw}
},
}
operation = '' if operation.nil?
operations = operation.split '|'
operations.each do |op_name|
op_name = op_name.strip
op = OPERATIONS[op_name]
next unless op
puts "operation: #{op_name}"
algorithm = op.(algorithm)
end
puts algorithm.join(nil)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment