twisty_puzzles 0.0.1 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -1
- data/README.md +6 -1
- data/ext/twisty_puzzles/native/cube_algorithm.c +267 -0
- data/ext/twisty_puzzles/native/cube_algorithm.h +5 -0
- data/ext/twisty_puzzles/native/cube_average.c +184 -0
- data/ext/twisty_puzzles/native/cube_average.h +5 -0
- data/ext/twisty_puzzles/native/cube_coordinate.c +207 -0
- data/ext/twisty_puzzles/native/cube_coordinate.h +34 -0
- data/ext/twisty_puzzles/native/cube_state.c +264 -0
- data/ext/twisty_puzzles/native/cube_state.h +31 -0
- data/ext/twisty_puzzles/native/extconf.rb +1 -1
- data/ext/twisty_puzzles/native/face_symbols.c +67 -0
- data/ext/twisty_puzzles/native/face_symbols.h +34 -0
- data/ext/twisty_puzzles/native/native.c +28 -0
- data/ext/twisty_puzzles/native/skewb_algorithm.c +331 -0
- data/ext/twisty_puzzles/native/skewb_algorithm.h +5 -0
- data/ext/twisty_puzzles/native/skewb_coordinate.c +237 -0
- data/ext/twisty_puzzles/native/skewb_coordinate.h +36 -0
- data/ext/twisty_puzzles/native/skewb_layer_fingerprint.c +271 -0
- data/ext/twisty_puzzles/native/skewb_layer_fingerprint.h +5 -0
- data/ext/twisty_puzzles/native/skewb_state.c +214 -0
- data/ext/twisty_puzzles/native/skewb_state.h +23 -0
- data/ext/twisty_puzzles/native/utils.c +76 -0
- data/ext/twisty_puzzles/native/utils.h +31 -0
- data/lib/twisty_puzzles.rb +38 -0
- data/lib/twisty_puzzles/abstract_direction.rb +38 -39
- data/lib/twisty_puzzles/abstract_move.rb +1 -2
- data/lib/twisty_puzzles/abstract_move_parser.rb +32 -33
- data/lib/twisty_puzzles/algorithm.rb +112 -113
- data/lib/twisty_puzzles/algorithm_transformation.rb +19 -21
- data/lib/twisty_puzzles/axis_face_and_direction_move.rb +56 -56
- data/lib/twisty_puzzles/cancellation_helper.rb +124 -125
- data/lib/twisty_puzzles/color_scheme.rb +1 -1
- data/lib/twisty_puzzles/commutator.rb +82 -80
- data/lib/twisty_puzzles/compiled_algorithm.rb +31 -32
- data/lib/twisty_puzzles/compiled_cube_algorithm.rb +49 -50
- data/lib/twisty_puzzles/compiled_skewb_algorithm.rb +18 -19
- data/lib/twisty_puzzles/coordinate.rb +243 -246
- data/lib/twisty_puzzles/cube.rb +494 -495
- data/lib/twisty_puzzles/cube_constants.rb +40 -41
- data/lib/twisty_puzzles/cube_direction.rb +15 -18
- data/lib/twisty_puzzles/cube_move.rb +285 -290
- data/lib/twisty_puzzles/cube_move_parser.rb +75 -76
- data/lib/twisty_puzzles/cube_print_helper.rb +133 -133
- data/lib/twisty_puzzles/cube_state.rb +80 -81
- data/lib/twisty_puzzles/move_type_creator.rb +17 -18
- data/lib/twisty_puzzles/parser.rb +176 -179
- data/lib/twisty_puzzles/part_cycle_factory.rb +39 -42
- data/lib/twisty_puzzles/puzzle.rb +16 -17
- data/lib/twisty_puzzles/reversible_applyable.rb +24 -25
- data/lib/twisty_puzzles/rotation.rb +76 -75
- data/lib/twisty_puzzles/skewb_direction.rb +14 -15
- data/lib/twisty_puzzles/skewb_move.rb +49 -49
- data/lib/twisty_puzzles/skewb_move_parser.rb +51 -51
- data/lib/twisty_puzzles/skewb_notation.rb +121 -118
- data/lib/twisty_puzzles/skewb_state.rb +120 -121
- data/lib/twisty_puzzles/state_helper.rb +20 -21
- data/lib/twisty_puzzles/sticker_cycle.rb +43 -44
- data/lib/twisty_puzzles/utils.rb +3 -0
- data/lib/twisty_puzzles/version.rb +3 -1
- metadata +30 -10
@@ -10,91 +10,90 @@ require 'twisty_puzzles/rotation'
|
|
10
10
|
require 'twisty_puzzles/skewb_move'
|
11
11
|
|
12
12
|
module TwistyPuzzles
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
end
|
13
|
+
# Parser for cube moves.
|
14
|
+
class CubeMoveParser < AbstractMoveParser
|
15
|
+
REGEXP =
|
16
|
+
begin
|
17
|
+
axes_part = "(?<axis_name>[#{AbstractMove::AXES.join}])"
|
18
|
+
face_names = CubeConstants::FACE_NAMES.join
|
19
|
+
fat_move_part =
|
20
|
+
"(?<width>\\d*)(?<fat_face_name>[#{face_names}])w"
|
21
|
+
normal_move_part = "(?<face_name>[#{face_names}])"
|
22
|
+
downcased_face_names = face_names.downcase
|
23
|
+
maybe_fat_maybe_slice_move_part =
|
24
|
+
"(?<maybe_fat_face_maybe_slice_name>[#{downcased_face_names}])"
|
25
|
+
slice_move_part =
|
26
|
+
"(?<slice_index>\\d+)(?<slice_name>[#{downcased_face_names}])"
|
27
|
+
mslice_move_part =
|
28
|
+
"(?<mslice_name>[#{AbstractMove::SLICE_FACES.keys.join}])"
|
29
|
+
move_part = "(?:#{axes_part}|" \
|
30
|
+
"#{fat_move_part}|" \
|
31
|
+
"#{normal_move_part}|" \
|
32
|
+
"#{maybe_fat_maybe_slice_move_part}|" \
|
33
|
+
"#{slice_move_part}|#{mslice_move_part})"
|
34
|
+
direction_names =
|
35
|
+
AbstractDirection::POSSIBLE_DIRECTION_NAMES.flatten
|
36
|
+
direction_names.sort_by! { |e| -e.length }
|
37
|
+
direction_part = "(?<direction>#{direction_names.join('|')})"
|
38
|
+
Regexp.new("#{move_part}#{direction_part}")
|
39
|
+
end
|
41
40
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
MOVE_TYPE_CREATORS = [
|
42
|
+
MoveTypeCreator.new(%i[axis_face direction], Rotation),
|
43
|
+
MoveTypeCreator.new(%i[fat_face direction width], FatMove),
|
44
|
+
MoveTypeCreator.new(%i[face direction], FatMove),
|
45
|
+
MoveTypeCreator.new(%i[maybe_fat_face_maybe_slice_face direction], MaybeFatMaybeSliceMove),
|
46
|
+
MoveTypeCreator.new(%i[slice_face direction slice_index], SliceMove),
|
47
|
+
MoveTypeCreator.new(%i[mslice_face direction], MaybeFatMSliceMaybeInnerMSliceMove)
|
48
|
+
].freeze
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
INSTANCE = CubeMoveParser.new
|
51
|
+
def regexp
|
52
|
+
REGEXP
|
53
|
+
end
|
55
54
|
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
def move_type_creators
|
56
|
+
MOVE_TYPE_CREATORS
|
57
|
+
end
|
59
58
|
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
def parse_part_key(name)
|
60
|
+
name.sub('_name', '_face').sub('face_face', 'face')
|
61
|
+
end
|
63
62
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
def parse_direction(direction_string)
|
64
|
+
value = AbstractDirection::POSSIBLE_DIRECTION_NAMES.index do |ds|
|
65
|
+
ds.include?(direction_string)
|
66
|
+
end + 1
|
67
|
+
CubeDirection.new(value)
|
68
|
+
end
|
70
69
|
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
def parse_axis_face(axis_face_string)
|
71
|
+
Face::ELEMENTS[AbstractMove::AXES.index(axis_face_string)]
|
72
|
+
end
|
74
73
|
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
def parse_mslice_face(mslice_name)
|
75
|
+
AbstractMove::SLICE_FACES[mslice_name]
|
76
|
+
end
|
78
77
|
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
def parse_width(width_string)
|
79
|
+
width_string.empty? ? 2 : Integer(width_string, 10)
|
80
|
+
end
|
82
81
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
end
|
82
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
83
|
+
def parse_move_part(name, value)
|
84
|
+
case name
|
85
|
+
when 'axis_name' then parse_axis_face(value)
|
86
|
+
when 'width' then parse_width(value)
|
87
|
+
when 'slice_index' then Integer(value, 10)
|
88
|
+
when 'fat_face_name', 'face_name' then Face.by_name(value)
|
89
|
+
when 'maybe_fat_face_maybe_slice_name', 'slice_name'
|
90
|
+
Face.by_name(value.upcase)
|
91
|
+
when 'mslice_name'
|
92
|
+
parse_mslice_face(value)
|
93
|
+
when 'direction' then parse_direction(value)
|
94
|
+
else raise
|
97
95
|
end
|
98
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
99
96
|
end
|
97
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
98
|
+
end
|
100
99
|
end
|
@@ -4,157 +4,157 @@ require 'colorize'
|
|
4
4
|
require 'twisty_puzzles/utils/array_helper'
|
5
5
|
|
6
6
|
module TwistyPuzzles
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
else color
|
17
|
-
end
|
7
|
+
# Module to print and display cube and Skewb states.
|
8
|
+
module CubePrintHelper
|
9
|
+
include Utils::ArrayHelper
|
10
|
+
|
11
|
+
def color_symbol(color)
|
12
|
+
case color
|
13
|
+
when :orange then :light_red
|
14
|
+
when :unknown then :light_black
|
15
|
+
else color
|
18
16
|
end
|
17
|
+
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
char = color.to_s[0].upcase
|
37
|
-
if color_mode == :color
|
38
|
-
char.colorize(background: color_symbol(color))
|
39
|
-
else
|
40
|
-
char
|
41
|
-
end
|
19
|
+
COLOR_MODES = %i[color nocolor].freeze
|
20
|
+
ColorInfo = Struct.new(:reverse_lines_mode, :reverse_columns_mode, :skewb_corner_permutation)
|
21
|
+
FACE_SYMBOL_INFOS = {
|
22
|
+
U: ColorInfo.new(:reverse, :reverse, [2, 3, 0, 1]),
|
23
|
+
L: ColorInfo.new(:keep, :reverse, [2, 0, 3, 1]),
|
24
|
+
F: ColorInfo.new(:keep, :reverse, [2, 0, 3, 1]),
|
25
|
+
R: ColorInfo.new(:keep, :keep, [1, 0, 3, 2]),
|
26
|
+
B: ColorInfo.new(:keep, :keep, [1, 0, 3, 2]),
|
27
|
+
D: ColorInfo.new(:keep, :reverse, [2, 0, 3, 1])
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
def color_character(color, color_mode)
|
31
|
+
unless COLOR_MODES.include?(color_mode)
|
32
|
+
raise ArgumentError, "Invalid color mode #{color_mode}"
|
42
33
|
end
|
43
34
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
else
|
50
|
-
raise
|
51
|
-
end
|
35
|
+
char = color.to_s[0].upcase
|
36
|
+
if color_mode == :color
|
37
|
+
char.colorize(background: color_symbol(color))
|
38
|
+
else
|
39
|
+
char
|
52
40
|
end
|
41
|
+
end
|
53
42
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
maybe_reverse(face_symbol_info.reverse_lines_mode, lines)
|
43
|
+
def maybe_reverse(reverse_mode, stuff)
|
44
|
+
case reverse_mode
|
45
|
+
when :reverse
|
46
|
+
stuff.reverse
|
47
|
+
when :keep
|
48
|
+
stuff
|
49
|
+
else
|
50
|
+
raise
|
64
51
|
end
|
52
|
+
end
|
65
53
|
|
66
|
-
|
67
|
-
|
68
|
-
|
54
|
+
def face_lines(cube_state, face_symbol, row_multiplicity = 1, column_multiplicity = 1)
|
55
|
+
face = Face.for_face_symbol(face_symbol)
|
56
|
+
face_symbol_info = FACE_SYMBOL_INFOS[face_symbol]
|
57
|
+
stickers = cube_state.sticker_array(face)
|
58
|
+
lines =
|
59
|
+
stickers.collect_concat do |sticker_line|
|
60
|
+
line = sticker_line.map { |c| yield(c) * column_multiplicity }
|
61
|
+
[maybe_reverse(face_symbol_info.reverse_columns_mode, line).join] * row_multiplicity
|
62
|
+
end
|
63
|
+
maybe_reverse(face_symbol_info.reverse_lines_mode, lines)
|
64
|
+
end
|
69
65
|
|
70
|
-
|
66
|
+
def simple_face_lines(cube_state, face_symbol, color_mode)
|
67
|
+
face_lines(cube_state, face_symbol) { |c| color_character(c, color_mode) }
|
68
|
+
end
|
71
69
|
|
72
|
-
|
73
|
-
raise if num_first_color > SKEWB_FACE_SIZE / 2
|
70
|
+
SKEWB_FACE_SIZE = 5
|
74
71
|
|
75
|
-
|
76
|
-
|
77
|
-
last_color * num_first_color
|
78
|
-
end
|
72
|
+
def skewb_ascii_art_line(first_color, middle_color, last_color, num_first_color)
|
73
|
+
raise if num_first_color > SKEWB_FACE_SIZE / 2
|
79
74
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
(1..SKEWB_FACE_SIZE / 2).to_a.reverse.map do |i|
|
85
|
-
skewb_ascii_art_line(corner_colors[0], center_color, corner_colors[1], i)
|
86
|
-
end
|
87
|
-
middle_part = SKEWB_FACE_SIZE.odd? ? [center_color * SKEWB_FACE_SIZE] : []
|
88
|
-
last_part =
|
89
|
-
(1..SKEWB_FACE_SIZE / 2).map do |i|
|
90
|
-
skewb_ascii_art_line(corner_colors[2], center_color, corner_colors[3], i)
|
91
|
-
end
|
92
|
-
first_part + middle_part + last_part
|
93
|
-
end
|
75
|
+
first_color * num_first_color +
|
76
|
+
middle_color * (SKEWB_FACE_SIZE - 2 * num_first_color) +
|
77
|
+
last_color * num_first_color
|
78
|
+
end
|
94
79
|
|
95
|
-
|
96
|
-
|
97
|
-
# rgggw
|
98
|
-
# ggggg
|
99
|
-
# ogggb
|
100
|
-
# oogbb
|
101
|
-
def skewb_face_lines(cube_state, face_symbol, color_mode)
|
102
|
-
face = Face.for_face_symbol(face_symbol)
|
103
|
-
face_symbol_info = FACE_SYMBOL_INFOS[face_symbol]
|
104
|
-
stickers = cube_state.sticker_array(face)
|
105
|
-
center_color = color_character(stickers[0], color_mode)
|
106
|
-
corner_colors = stickers[1..-1].map { |c| color_character(c, color_mode) }
|
107
|
-
permuted_corner_colors =
|
108
|
-
apply_permutation(corner_colors, face_symbol_info.skewb_corner_permutation)
|
109
|
-
raise unless corner_colors.length == 4
|
110
|
-
|
111
|
-
skewb_ascii_art(center_color, permuted_corner_colors)
|
112
|
-
end
|
80
|
+
def skewb_ascii_art(center_color, corner_colors)
|
81
|
+
raise unless corner_colors.length == 4
|
113
82
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
83
|
+
first_part =
|
84
|
+
(1..SKEWB_FACE_SIZE / 2).to_a.reverse.map do |i|
|
85
|
+
skewb_ascii_art_line(corner_colors[0], center_color, corner_colors[1], i)
|
86
|
+
end
|
87
|
+
middle_part = SKEWB_FACE_SIZE.odd? ? [center_color * SKEWB_FACE_SIZE] : []
|
88
|
+
last_part =
|
89
|
+
(1..SKEWB_FACE_SIZE / 2).map do |i|
|
90
|
+
skewb_ascii_art_line(corner_colors[2], center_color, corner_colors[3], i)
|
91
|
+
end
|
92
|
+
first_part + middle_part + last_part
|
93
|
+
end
|
121
94
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
95
|
+
# Prints a Skewb face like this:
|
96
|
+
# rrgww
|
97
|
+
# rgggw
|
98
|
+
# ggggg
|
99
|
+
# ogggb
|
100
|
+
# oogbb
|
101
|
+
def skewb_face_lines(cube_state, face_symbol, color_mode)
|
102
|
+
face = Face.for_face_symbol(face_symbol)
|
103
|
+
face_symbol_info = FACE_SYMBOL_INFOS[face_symbol]
|
104
|
+
stickers = cube_state.sticker_array(face)
|
105
|
+
center_color = color_character(stickers[0], color_mode)
|
106
|
+
corner_colors = stickers[1..].map { |c| color_character(c, color_mode) }
|
107
|
+
permuted_corner_colors =
|
108
|
+
apply_permutation(corner_colors, face_symbol_info.skewb_corner_permutation)
|
109
|
+
raise unless corner_colors.length == 4
|
110
|
+
|
111
|
+
skewb_ascii_art(center_color, permuted_corner_colors)
|
112
|
+
end
|
134
113
|
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
middle_belt = zip_concat_lines(left_face, front_face, right_face, back_face)
|
143
|
-
lines = pad_lines(top_face, SKEWB_FACE_SIZE) + middle_belt +
|
144
|
-
pad_lines(bottom_face, SKEWB_FACE_SIZE)
|
145
|
-
lines.join("\n")
|
146
|
-
end
|
114
|
+
def ll_string(cube_state, color_mode)
|
115
|
+
top_face = face_lines(cube_state, :U, 2, 3) { |c| color_character(c, color_mode) }
|
116
|
+
front_face = face_lines(cube_state, :F, 1, 3) { |c| color_character(c, color_mode) }
|
117
|
+
right_face = face_lines(cube_state, :R, 1, 3) { |c| color_character(c, color_mode) }
|
118
|
+
pll_line = front_face.first + right_face.first
|
119
|
+
(top_face + [pll_line] * 3).join("\n")
|
120
|
+
end
|
147
121
|
|
148
|
-
|
149
|
-
|
150
|
-
|
122
|
+
def cube_string(cube_state, color_mode)
|
123
|
+
top_face = simple_face_lines(cube_state, :U, color_mode)
|
124
|
+
left_face = simple_face_lines(cube_state, :L, color_mode)
|
125
|
+
front_face = simple_face_lines(cube_state, :F, color_mode)
|
126
|
+
right_face = simple_face_lines(cube_state, :R, color_mode)
|
127
|
+
back_face = simple_face_lines(cube_state, :B, color_mode)
|
128
|
+
bottom_face = simple_face_lines(cube_state, :D, color_mode)
|
129
|
+
middle_belt = zip_concat_lines(left_face, front_face, right_face, back_face)
|
130
|
+
lines = pad_lines(top_face, cube_state.n) + middle_belt +
|
131
|
+
pad_lines(bottom_face, cube_state.n)
|
132
|
+
lines.join("\n")
|
133
|
+
end
|
151
134
|
|
152
|
-
|
153
|
-
|
154
|
-
|
135
|
+
def skewb_string(skewb_state, color_mode)
|
136
|
+
top_face = skewb_face_lines(skewb_state, :U, color_mode)
|
137
|
+
left_face = skewb_face_lines(skewb_state, :L, color_mode)
|
138
|
+
front_face = skewb_face_lines(skewb_state, :F, color_mode)
|
139
|
+
right_face = skewb_face_lines(skewb_state, :R, color_mode)
|
140
|
+
back_face = skewb_face_lines(skewb_state, :B, color_mode)
|
141
|
+
bottom_face = skewb_face_lines(skewb_state, :D, color_mode)
|
142
|
+
middle_belt = zip_concat_lines(left_face, front_face, right_face, back_face)
|
143
|
+
lines = pad_lines(top_face, SKEWB_FACE_SIZE) + middle_belt +
|
144
|
+
pad_lines(bottom_face, SKEWB_FACE_SIZE)
|
145
|
+
lines.join("\n")
|
146
|
+
end
|
155
147
|
|
156
|
-
|
157
|
-
|
158
|
-
|
148
|
+
def empty_name
|
149
|
+
' '
|
150
|
+
end
|
151
|
+
|
152
|
+
def pad_lines(lines, padding)
|
153
|
+
lines.map { |line| empty_name * padding + line }
|
154
|
+
end
|
155
|
+
|
156
|
+
def zip_concat_lines(*args)
|
157
|
+
args.transpose.map(&:join)
|
159
158
|
end
|
159
|
+
end
|
160
160
|
end
|