Created
January 5, 2021 16:22
-
-
Save doooby/d9767a14fd6a92efd4518445d3187f3b to your computer and use it in GitHub Desktop.
it modifies a rubic's cube algorithm
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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