rubiks_cube 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/CONTRIBUTING.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +18 -0
- data/lib/rubiks_cube/algorithms.rb +78 -0
- data/lib/rubiks_cube/corner_cubie.rb +8 -0
- data/lib/rubiks_cube/cube.rb +203 -0
- data/lib/rubiks_cube/cubie.rb +29 -0
- data/lib/rubiks_cube/edge_cubie.rb +7 -0
- data/lib/rubiks_cube/two_cycle_solution.rb +120 -0
- data/lib/rubiks_cube/version.rb +3 -0
- data/lib/rubiks_cube.rb +7 -0
- data/rubiks_cube.gemspec +25 -0
- data/spec/rubiks_cube/algorithms_spec.rb +11 -0
- data/spec/rubiks_cube/cube_spec.rb +385 -0
- data/spec/rubiks_cube/cubie_spec.rb +67 -0
- data/spec/rubiks_cube/two_cycle_solution_spec.rb +110 -0
- data/spec/spec_helper.rb +1 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6c52f18a7cefa561a5ddcf4e3ced978f5da8b921
|
4
|
+
data.tar.gz: d876ec06323fb7574a7c14d585bbe9b5d247dd5d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0bfdc210f6c713f895c216b943b9bfd5ec186963a066c88c91a1748b50a77f32c5628b2976d43c97e606c783dd8c9a8d843474a3c6718df29c6a313a2b39f7b5
|
7
|
+
data.tar.gz: 2a673c8aa861243b077c1e026fdcb81488c570949d6008758d2f7f7b47a779aead7b10304edfb502fed4e0f257eefbdb59f89356cbf33e959eb3e3f8b8b825af
|
data/.gitignore
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
Want to contribute? Awesome! Thank you so much.
|
4
|
+
|
5
|
+
## How?
|
6
|
+
|
7
|
+
1. [Fork it](https://help.github.com/articles/fork-a-repo)
|
8
|
+
2. Create a feature branch (`git checkout -b my-new-feature`)
|
9
|
+
3. Commit changes, **with tests** (`git commit -am 'Add some feature'`)
|
10
|
+
4. Run the tests (`bundle exec rake`)
|
11
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
12
|
+
6. Create new [Pull
|
13
|
+
Request](https://help.github.com/articles/using-pull-requests)
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Chris Hunt
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# Rubik's Cube
|
2
|
+
![](http://www.mikesfreegifs.com/main4/underconstruction/atwork89.gif)
|
3
|
+
|
4
|
+
## Description
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
## Contributing
|
11
|
+
Please see the [Contributing
|
12
|
+
Document](https://github.com/chrishunt/rubiks-cube/blob/master/CONTRIBUTING.md)
|
13
|
+
|
14
|
+
## License
|
15
|
+
Copyright (C) 2013 Chris Hunt, [MIT
|
16
|
+
License](https://github.com/chrishunt/rubiks-cube/blob/master/LICENSE.txt)
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'cane/rake_task'
|
4
|
+
require 'cane/hashcheck'
|
5
|
+
|
6
|
+
desc 'Run all tests'
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.rspec_opts = '--color --order random'
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Check code quality'
|
12
|
+
Cane::RakeTask.new(:quality) do |task|
|
13
|
+
task.abc_max = 9
|
14
|
+
task.use Cane::HashCheck
|
15
|
+
end
|
16
|
+
|
17
|
+
task default: :spec
|
18
|
+
task default: :quality
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module RubiksCube
|
2
|
+
module Algorithms
|
3
|
+
def self.reverse(algorithm)
|
4
|
+
algorithm.split.map do |move|
|
5
|
+
case modifier = move[-1]
|
6
|
+
when "'"
|
7
|
+
move[0]
|
8
|
+
when "2"
|
9
|
+
move
|
10
|
+
else
|
11
|
+
"#{move}'"
|
12
|
+
end
|
13
|
+
end.reverse.join ' '
|
14
|
+
end
|
15
|
+
|
16
|
+
module Permutation
|
17
|
+
Edge = "R U R' U' R' F R2 U' R' U' R U R' F'"
|
18
|
+
Corner = "U F R U' R' U' R U R' F' R U R' U' R' F R F' U'"
|
19
|
+
|
20
|
+
module Setup
|
21
|
+
Edge = {
|
22
|
+
0 => "M2 D L2",
|
23
|
+
2 => "M2 D' L2",
|
24
|
+
3 => "",
|
25
|
+
4 => "U' F U",
|
26
|
+
5 => "U' F' U",
|
27
|
+
6 => "U B U'",
|
28
|
+
7 => "U B' U'",
|
29
|
+
8 => "D' L2",
|
30
|
+
9 => "D2 L2",
|
31
|
+
10 => "D L2",
|
32
|
+
11 => "L2"
|
33
|
+
}
|
34
|
+
|
35
|
+
Corner = {
|
36
|
+
1 => "R2 D' R2",
|
37
|
+
2 => "",
|
38
|
+
3 => "B2 D' R2",
|
39
|
+
4 => "D R2",
|
40
|
+
5 => "R2",
|
41
|
+
6 => "D' R2",
|
42
|
+
7 => "D2 R2"
|
43
|
+
}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Orientation
|
48
|
+
Edge = "M' U M' U M' U2 M U M U M U2"
|
49
|
+
Corner = "R' D R F D F' U' F D' F' R' D' R U"
|
50
|
+
|
51
|
+
module Setup
|
52
|
+
Edge = {
|
53
|
+
1 => "R B",
|
54
|
+
2 => "",
|
55
|
+
3 => "L' B'",
|
56
|
+
4 => "L2 B'",
|
57
|
+
5 => "R2 B",
|
58
|
+
6 => "B",
|
59
|
+
7 => "B'",
|
60
|
+
8 => "D2 B2",
|
61
|
+
9 => "D B2",
|
62
|
+
10 => "B2",
|
63
|
+
11 => "D' B2"
|
64
|
+
}
|
65
|
+
|
66
|
+
Corner = {
|
67
|
+
1 => "",
|
68
|
+
2 => "R'",
|
69
|
+
3 => "B2 R2",
|
70
|
+
4 => "D2 R2",
|
71
|
+
5 => "D R2",
|
72
|
+
6 => "R2",
|
73
|
+
7 => "D' R2"
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,203 @@
|
|
1
|
+
module RubiksCube
|
2
|
+
# Standard 3x3x3 Rubik's Cube with normal turn operations (l, r, u, d, f, b)
|
3
|
+
class Cube
|
4
|
+
SOLVED_STATE = %w(
|
5
|
+
UF UR UB UL FL FR BR BL DF DR DB DL UFL URF UBR ULB DLF DFR DRB DBL
|
6
|
+
)
|
7
|
+
|
8
|
+
def initialize(state = nil)
|
9
|
+
@state = build_state_from_string(
|
10
|
+
state.to_s.empty? ? SOLVED_STATE.join(' ') : state
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other)
|
15
|
+
state == other.state
|
16
|
+
end
|
17
|
+
|
18
|
+
def state
|
19
|
+
@state.join ' '
|
20
|
+
end
|
21
|
+
|
22
|
+
def edges
|
23
|
+
@state[0..11]
|
24
|
+
end
|
25
|
+
|
26
|
+
def corners
|
27
|
+
@state[12..-1]
|
28
|
+
end
|
29
|
+
|
30
|
+
def solved?
|
31
|
+
state == SOLVED_STATE.join(' ')
|
32
|
+
end
|
33
|
+
|
34
|
+
def edge_permuted?(edge)
|
35
|
+
cubie_permuted? :edges, edge
|
36
|
+
end
|
37
|
+
|
38
|
+
def corner_permuted?(corner)
|
39
|
+
cubie_permuted? :corners, corner
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_correct_edge_permutation?
|
43
|
+
incorrect_edge_permutation_locations.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
def has_correct_corner_permutation?
|
47
|
+
incorrect_corner_permutation_locations.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_correct_edge_orientation?
|
51
|
+
incorrect_edge_orientation_locations.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def has_correct_corner_orientation?
|
55
|
+
incorrect_corner_orientation_locations.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
def incorrect_edge_permutation_locations
|
59
|
+
unpermuted_locations_for :edges
|
60
|
+
end
|
61
|
+
|
62
|
+
def incorrect_corner_permutation_locations
|
63
|
+
unpermuted_locations_for :corners
|
64
|
+
end
|
65
|
+
|
66
|
+
def incorrect_edge_orientation_locations
|
67
|
+
unoriented_locations_for :edges
|
68
|
+
end
|
69
|
+
|
70
|
+
def incorrect_corner_orientation_locations
|
71
|
+
unoriented_locations_for :corners
|
72
|
+
end
|
73
|
+
|
74
|
+
def permuted_location_for(cubie)
|
75
|
+
while (location = SOLVED_STATE.index cubie.state) == nil
|
76
|
+
cubie = cubie.rotate
|
77
|
+
end
|
78
|
+
|
79
|
+
location -= 12 if location >= 12
|
80
|
+
location
|
81
|
+
end
|
82
|
+
|
83
|
+
def perform!(algorithm)
|
84
|
+
algorithm.split.each { |move| perform_move! move }
|
85
|
+
algorithm
|
86
|
+
end
|
87
|
+
|
88
|
+
def undo!(algorithm)
|
89
|
+
perform! reverse(algorithm)
|
90
|
+
end
|
91
|
+
|
92
|
+
def r
|
93
|
+
turn [1, 5, 9, 6]
|
94
|
+
turn [13, 17, 18, 14]
|
95
|
+
rotate [13, 13, 14, 17, 18, 18]
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def l
|
100
|
+
turn [3, 7, 11, 4]
|
101
|
+
turn [12, 15, 19, 16]
|
102
|
+
rotate [12, 15, 15, 16, 16, 19]
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
def u
|
107
|
+
turn [0, 1, 2, 3]
|
108
|
+
turn [12, 13, 14, 15]
|
109
|
+
self
|
110
|
+
end
|
111
|
+
|
112
|
+
def d
|
113
|
+
turn [8, 11, 10, 9]
|
114
|
+
turn [16, 19, 18, 17]
|
115
|
+
self
|
116
|
+
end
|
117
|
+
|
118
|
+
def f
|
119
|
+
turn [0, 4, 8, 5]
|
120
|
+
rotate [0, 4, 8, 5]
|
121
|
+
turn [12, 16, 17, 13]
|
122
|
+
rotate [12, 12, 13, 16, 17, 17]
|
123
|
+
self
|
124
|
+
end
|
125
|
+
|
126
|
+
def b
|
127
|
+
turn [2, 6, 10, 7]
|
128
|
+
rotate [2, 6, 10, 7]
|
129
|
+
turn [14, 18, 19, 15]
|
130
|
+
rotate [14, 14, 15, 18, 19, 19]
|
131
|
+
self
|
132
|
+
end
|
133
|
+
|
134
|
+
def m
|
135
|
+
turn [0, 2, 10, 8]
|
136
|
+
rotate [0, 2, 10, 8]
|
137
|
+
self
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def build_state_from_string(state)
|
143
|
+
state.split.map { |state| RubiksCube::Cubie.new state }
|
144
|
+
end
|
145
|
+
|
146
|
+
def cubie_permuted?(type, cubie)
|
147
|
+
send(type).index(cubie) == permuted_location_for(cubie)
|
148
|
+
end
|
149
|
+
|
150
|
+
def unpermuted_locations_for(type)
|
151
|
+
send(type).each_with_index.map do |cubie, location|
|
152
|
+
location unless location == permuted_location_for(cubie)
|
153
|
+
end.compact
|
154
|
+
end
|
155
|
+
|
156
|
+
def unoriented_locations_for(type)
|
157
|
+
send(type).each_with_index.map do |cubie, location|
|
158
|
+
oriented_state = SOLVED_STATE.fetch(
|
159
|
+
if type == :corners
|
160
|
+
location + 12
|
161
|
+
else
|
162
|
+
location
|
163
|
+
end
|
164
|
+
)
|
165
|
+
|
166
|
+
location unless cubie.state == oriented_state
|
167
|
+
end.compact
|
168
|
+
end
|
169
|
+
|
170
|
+
def turn(sequence)
|
171
|
+
current_cubie = sequence.shift
|
172
|
+
first_cubie = @state[current_cubie]
|
173
|
+
|
174
|
+
sequence.each do |cubie|
|
175
|
+
@state[current_cubie] = @state[cubie]
|
176
|
+
current_cubie = cubie
|
177
|
+
end
|
178
|
+
|
179
|
+
@state[current_cubie] = first_cubie
|
180
|
+
end
|
181
|
+
|
182
|
+
def rotate(cubies)
|
183
|
+
cubies.each { |cubie| @state[cubie].rotate! }
|
184
|
+
end
|
185
|
+
|
186
|
+
def perform_move!(move)
|
187
|
+
operation = "#{move[0].downcase}"
|
188
|
+
|
189
|
+
case modifier = move[-1]
|
190
|
+
when "'"
|
191
|
+
3.times { send operation }
|
192
|
+
when "2"
|
193
|
+
2.times { send operation }
|
194
|
+
else
|
195
|
+
send operation
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def reverse(algorithm)
|
200
|
+
RubiksCube::Algorithms.reverse algorithm
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module RubiksCube
|
2
|
+
# Generic cubie piece, either edge cubie or corner cubie
|
3
|
+
class Cubie
|
4
|
+
def initialize(state)
|
5
|
+
@cubie = state.size == 2 ? EdgeCubie.new(state) : CornerCubie.new(state)
|
6
|
+
end
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
state == other.state
|
10
|
+
end
|
11
|
+
|
12
|
+
def state
|
13
|
+
@cubie.state
|
14
|
+
end
|
15
|
+
|
16
|
+
def rotate!
|
17
|
+
@cubie.rotate!
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def rotate
|
22
|
+
Cubie.new(state.dup).rotate!
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
@cubie.state
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module RubiksCube
|
2
|
+
# Very inefficient two-cycle solving algorithm, useful for blindfold
|
3
|
+
class TwoCycleSolution
|
4
|
+
attr_reader :cube
|
5
|
+
|
6
|
+
def initialize(cube)
|
7
|
+
@cube = Cube.new(cube.state)
|
8
|
+
end
|
9
|
+
|
10
|
+
def state
|
11
|
+
cube.state
|
12
|
+
end
|
13
|
+
|
14
|
+
def solved?
|
15
|
+
cube.solved?
|
16
|
+
end
|
17
|
+
|
18
|
+
def solve!
|
19
|
+
@solution ||= begin
|
20
|
+
solution = []
|
21
|
+
solution << solution_for(:permutation)
|
22
|
+
solution << solution_for(:orientation)
|
23
|
+
solution.flatten
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def solution
|
28
|
+
solve!
|
29
|
+
@solution
|
30
|
+
end
|
31
|
+
|
32
|
+
def solution_length
|
33
|
+
solution.flatten.join(' ').split.count
|
34
|
+
end
|
35
|
+
|
36
|
+
def pretty
|
37
|
+
solution.each_slice(3).map do |setup, correction, undo|
|
38
|
+
step = []
|
39
|
+
step << "Setup:\t#{setup}" unless setup.empty?
|
40
|
+
step << "Fix:\t#{correction}"
|
41
|
+
step << "Undo:\t#{undo}" unless undo.empty?
|
42
|
+
step.join "\n"
|
43
|
+
end.join("\n\n").strip
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def solution_for(step)
|
49
|
+
[:edge, :corner].map do |cubie|
|
50
|
+
solve_for cubie, step
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def solve_for(cubie, step)
|
55
|
+
solution = []
|
56
|
+
solution << [perform(cubie, step)] until finished_with?(cubie, step)
|
57
|
+
solution
|
58
|
+
end
|
59
|
+
|
60
|
+
def finished_with?(cubie, step)
|
61
|
+
cube.public_send "has_correct_#{cubie}_#{step}?"
|
62
|
+
end
|
63
|
+
|
64
|
+
def perform(cubie, step)
|
65
|
+
algorithms_for(cubie, step).map { |algorithm| cube.perform! algorithm }
|
66
|
+
end
|
67
|
+
|
68
|
+
def next_orientation_location_for(cubie)
|
69
|
+
incorrect_locations_for(cubie, :orientation).tap do |locations|
|
70
|
+
locations.delete(0)
|
71
|
+
end.first
|
72
|
+
end
|
73
|
+
|
74
|
+
def next_permutation_location_for(cubie)
|
75
|
+
buffer_cubie = send("permutation_buffer_#{cubie}")
|
76
|
+
|
77
|
+
if cube.public_send("#{cubie}_permuted?", buffer_cubie)
|
78
|
+
incorrect_locations_for(cubie, :permutation).first
|
79
|
+
else
|
80
|
+
cube.permuted_location_for buffer_cubie
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def permutation_buffer_edge
|
85
|
+
cube.edges[1]
|
86
|
+
end
|
87
|
+
|
88
|
+
def permutation_buffer_corner
|
89
|
+
cube.corners[0]
|
90
|
+
end
|
91
|
+
|
92
|
+
def incorrect_locations_for(cubie, step)
|
93
|
+
cube.public_send "incorrect_#{cubie}_#{step}_locations"
|
94
|
+
end
|
95
|
+
|
96
|
+
def algorithms_for(cubie, step)
|
97
|
+
location = send("next_#{step}_location_for", cubie)
|
98
|
+
setup = setup_algorithms_for(cubie, step, location)
|
99
|
+
correction = correction_algorithm_for(cubie, step)
|
100
|
+
undo = RubiksCube::Algorithms.reverse(setup)
|
101
|
+
|
102
|
+
[ setup, correction, undo ]
|
103
|
+
end
|
104
|
+
|
105
|
+
def correction_algorithm_for(cubie, step)
|
106
|
+
load_algorithms step, cubie
|
107
|
+
end
|
108
|
+
|
109
|
+
def setup_algorithms_for(cubie, step, location)
|
110
|
+
load_algorithms(step, 'setup', cubie).fetch(location)
|
111
|
+
end
|
112
|
+
|
113
|
+
def load_algorithms(*classes)
|
114
|
+
Kernel.const_get(
|
115
|
+
"RubiksCube::Algorithms::" <<
|
116
|
+
classes.map(&:capitalize).flatten.join('::')
|
117
|
+
)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
data/lib/rubiks_cube.rb
ADDED
data/rubiks_cube.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'rubiks_cube/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'rubiks_cube'
|
8
|
+
spec.version = RubiksCube::VERSION
|
9
|
+
spec.authors = ['Chris Hunt']
|
10
|
+
spec.email = ['c@chrishunt.co']
|
11
|
+
spec.description = %q{Learn how to solve the Rubik's Cube. It's easy!}
|
12
|
+
spec.summary = %q{Learn how to solve the Rubik's Cube. It's easy!}
|
13
|
+
spec.homepage = 'https://github.com/chrishunt/rubiks-cube'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'rspec'
|
24
|
+
spec.add_development_dependency 'cane-hashcheck'
|
25
|
+
end
|
@@ -0,0 +1,385 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RubiksCube::Cube do
|
4
|
+
subject { described_class.new state }
|
5
|
+
|
6
|
+
let(:state) { nil }
|
7
|
+
|
8
|
+
describe '#initialize' do
|
9
|
+
context 'when a state is provided' do
|
10
|
+
let(:state) { 'some state' }
|
11
|
+
|
12
|
+
it 'is initialized with the state' do
|
13
|
+
expect(subject.state).to eq state
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'when no state is provided' do
|
18
|
+
let(:state) { nil }
|
19
|
+
|
20
|
+
it 'is initialized with the solved state' do
|
21
|
+
expect(subject.state).to eq RubiksCube::Cube::SOLVED_STATE.join ' '
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '==' do
|
27
|
+
it 'returns true when two cubes have the same state' do
|
28
|
+
expect(subject).to eq described_class.new(state)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns false when two cubes do not have the same state' do
|
32
|
+
expect(subject).to_not eq described_class.new(state).d
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#edges' do
|
37
|
+
it 'returns all the edges' do
|
38
|
+
expect(subject.edges).to eq(
|
39
|
+
subject.state.split[0..11].map { |cubie| RubiksCube::Cubie.new cubie }
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#corners' do
|
45
|
+
it 'returns all the corners' do
|
46
|
+
expect(subject.corners).to eq(
|
47
|
+
subject.state.split[12..-1].map { |cubie| RubiksCube::Cubie.new cubie }
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#incorrect_edge_permutation_locations' do
|
53
|
+
context 'with unpermuted edges' do
|
54
|
+
let(:state) {
|
55
|
+
'UF UL UB UR FL FR BR BL DF DL DB DR UFL URF UBR ULB DLF DFR DRB DBL'
|
56
|
+
}
|
57
|
+
|
58
|
+
it 'returns the location of all unpermuted edges' do
|
59
|
+
expect(
|
60
|
+
subject.incorrect_edge_permutation_locations
|
61
|
+
).to eq [1, 3, 9, 11]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with permuted edges' do
|
66
|
+
it 'returns an empty array' do
|
67
|
+
expect(subject.incorrect_edge_permutation_locations).to eq []
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '#incorrect_corner_permutation_locations' do
|
73
|
+
context 'with unpermuted corners' do
|
74
|
+
let(:state){
|
75
|
+
'UF UR UB UL FL FR BR BL DF DR DB DL ULB UBR URF UFL DLF DFR DRB DBL'
|
76
|
+
}
|
77
|
+
|
78
|
+
it 'returns the locations of all unpermuted corners' do
|
79
|
+
expect(
|
80
|
+
subject.incorrect_corner_permutation_locations
|
81
|
+
).to eq [0, 1, 2, 3]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'with permuted corners' do
|
86
|
+
it 'returns an empty array' do
|
87
|
+
expect(subject.incorrect_corner_permutation_locations).to eq []
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#incorrect_edge_orientation_locations' do
|
93
|
+
context 'with edges that are not oriented' do
|
94
|
+
let(:state) {
|
95
|
+
'FU UR BU UL FL RF RB LB FD DR DB DL UFL URF UBR ULB DLF DFR DRB DBL'
|
96
|
+
}
|
97
|
+
|
98
|
+
it 'returns the locations of all unoriented edges' do
|
99
|
+
expect(
|
100
|
+
subject.incorrect_edge_orientation_locations
|
101
|
+
).to eq [0, 2, 5, 6, 7, 8]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'with oriented edges' do
|
106
|
+
it 'returns an empty array' do
|
107
|
+
expect(subject.incorrect_edge_orientation_locations).to eq []
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#incorrect_corner_orientation_locations' do
|
113
|
+
context 'with corners that are not oriented' do
|
114
|
+
let(:state) {
|
115
|
+
'UF UR UB UL FL FR BR BL DF DR DB DL FLU FUR UBR ULB DLF DFR DRB DBL'
|
116
|
+
}
|
117
|
+
|
118
|
+
it 'returns the locations of all unoriented corners' do
|
119
|
+
expect(subject.incorrect_corner_orientation_locations).to eq [0, 1]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'with oriented corners' do
|
124
|
+
it 'returns an empty array' do
|
125
|
+
expect(subject.incorrect_corner_orientation_locations).to eq []
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#permuted_location_for' do
|
131
|
+
RubiksCube::Cube::SOLVED_STATE.each_with_index do |cubie, location|
|
132
|
+
it "returns the correct location for the '#{cubie}' cubie" do
|
133
|
+
# Both corner and edge index begins at zero
|
134
|
+
location -= 12 if location >= 12
|
135
|
+
|
136
|
+
cubie = RubiksCube::Cubie.new cubie
|
137
|
+
|
138
|
+
expect(subject.permuted_location_for cubie).to eq location
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'when the cubie has been rotated' do
|
143
|
+
let(:cubie) { subject.corners.first }
|
144
|
+
|
145
|
+
before { cubie.rotate! }
|
146
|
+
|
147
|
+
it 'still finds the correct location' do
|
148
|
+
expect(subject.permuted_location_for cubie).to eq 0
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'does not rotate the cubie' do
|
152
|
+
original_state = cubie.state
|
153
|
+
|
154
|
+
subject.permuted_location_for cubie
|
155
|
+
|
156
|
+
expect(cubie.state).to eq original_state
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#solved?' do
|
162
|
+
it 'returns true when cube is solved' do
|
163
|
+
expect(subject).to be_solved
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'returns false when cube is not solved' do
|
167
|
+
subject.l
|
168
|
+
expect(subject).to_not be_solved
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe '#edge_permuted?' do
|
173
|
+
it 'returns true when the cubie is permuted' do
|
174
|
+
subject.u
|
175
|
+
|
176
|
+
permuted_edge = subject.edges[4]
|
177
|
+
unpermuted_edge = subject.edges[0]
|
178
|
+
|
179
|
+
expect(subject.edge_permuted? unpermuted_edge).to be_false
|
180
|
+
expect(subject.edge_permuted? permuted_edge).to be_true
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe '#corner_permuted?' do
|
185
|
+
it 'returns true when the cubie is permuted' do
|
186
|
+
subject.f
|
187
|
+
|
188
|
+
permuted_corner = subject.corners[2]
|
189
|
+
unpermuted_corner = subject.corners[1]
|
190
|
+
|
191
|
+
expect(subject.corner_permuted? unpermuted_corner).to be_false
|
192
|
+
expect(subject.corner_permuted? permuted_corner).to be_true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#has_correct_edge_permutation?' do
|
197
|
+
context 'when the edges are permuted, but corners are not' do
|
198
|
+
let(:state) {
|
199
|
+
'UF UR UB UL FL FR BR BL DF DR DB DL ULB UBR URF UFL DBL DRB DFR DLF'
|
200
|
+
}
|
201
|
+
|
202
|
+
it 'returns true' do
|
203
|
+
expect(subject).to have_correct_edge_permutation
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
context 'when the edges are not permuted, but corners are' do
|
208
|
+
let(:state) {
|
209
|
+
'UL UF UB UR FL FR BR BL DF DR DB DL UFL URF UBR ULB DLF DFR DRB DBL'
|
210
|
+
}
|
211
|
+
|
212
|
+
it 'returns false' do
|
213
|
+
expect(subject).to_not have_correct_edge_permutation
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe '#has_correct_corner_permutation?' do
|
219
|
+
context 'when the corners are permuted, but the edges are not' do
|
220
|
+
let(:state) {
|
221
|
+
'UL UF UB UR FL FR BR BL DF DR DB DL UFL URF UBR ULB DLF DFR DRB DBL'
|
222
|
+
}
|
223
|
+
|
224
|
+
it 'returns true' do
|
225
|
+
expect(subject).to have_correct_corner_permutation
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
context 'when the corners are not permuted, but the edges are permuted' do
|
230
|
+
let(:state) {
|
231
|
+
'UF UR UB UL FL FR BR BL DF DR DB DL ULB UBR URF UFL DBL DRB DFR DLF'
|
232
|
+
}
|
233
|
+
|
234
|
+
it 'returns false' do
|
235
|
+
expect(subject).to_not have_correct_corner_permutation
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe '#has_correct_edge_orientation?' do
|
241
|
+
context 'when the edges are oriented, but the corners are not' do
|
242
|
+
let(:state) {
|
243
|
+
'UF UR UB UL FL FR BR BL DF DR DB DL LUF RFU UBR ULB DLF DFR DRB DBL'
|
244
|
+
}
|
245
|
+
|
246
|
+
it 'returns true' do
|
247
|
+
expect(subject).to have_correct_edge_orientation
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
context 'when the edges are not oriented, but the corners are' do
|
252
|
+
let(:state) {
|
253
|
+
'FU UR BU UL FL FR BR BL DF DR DB DL UFL URF UBR ULB DLF DFR DRB DBL'
|
254
|
+
}
|
255
|
+
|
256
|
+
it 'returns false' do
|
257
|
+
expect(subject).to_not have_correct_edge_orientation
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe '#has_correct_corner_orientation?' do
|
263
|
+
context 'when the corners are oriented, but the edges are not' do
|
264
|
+
let(:state) {
|
265
|
+
'FU UR BU UL FL FR BR BL DF DR DB DL UFL URF UBR ULB DLF DFR DRB DBL'
|
266
|
+
}
|
267
|
+
|
268
|
+
it 'returns true' do
|
269
|
+
expect(subject).to have_correct_corner_orientation
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
context 'when the corners are not oriented, but the edges are' do
|
274
|
+
let(:state) {
|
275
|
+
'UF UR UB UL FL FR BR BL DF DR DB DL LUF RFU UBR ULB DLF DFR DRB DBL'
|
276
|
+
}
|
277
|
+
|
278
|
+
it 'returns false' do
|
279
|
+
expect(subject).to_not have_correct_corner_orientation
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe '#perform!' do
|
285
|
+
it 'performs the algorithm on the cube' do
|
286
|
+
subject.perform! "U2 D' L R F B"
|
287
|
+
|
288
|
+
expect(subject.state).to eq(
|
289
|
+
described_class.new.u.u.d.d.d.l.r.f.b.state
|
290
|
+
)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'returns the algorithm that was performed' do
|
294
|
+
algorithm = "F2 U' L"
|
295
|
+
|
296
|
+
expect(subject.perform! algorithm).to eq algorithm
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe '#undo!' do
|
301
|
+
it 'performs the algorithm in reverse on the cube' do
|
302
|
+
subject.f.f.f.b.l.l.u.u.u.r
|
303
|
+
|
304
|
+
subject.undo! "F' B L2 U' R"
|
305
|
+
|
306
|
+
expect(subject).to be_solved
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
describe 'face turns' do
|
311
|
+
shared_examples_for 'a face turn' do
|
312
|
+
it "rotates the face 90 degrees clockwise" do
|
313
|
+
subject.public_send direction
|
314
|
+
expect(subject.state).to eq expected_state
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'is chainable' do
|
318
|
+
expect(subject.public_send direction).to eq subject
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe '#r' do
|
323
|
+
let(:direction) { 'r' }
|
324
|
+
let(:expected_state) {
|
325
|
+
'UF FR UB UL FL DR UR BL DF BR DB DL UFL FRD FUR ULB DLF BDR BRU DBL'
|
326
|
+
}
|
327
|
+
|
328
|
+
it_should_behave_like 'a face turn'
|
329
|
+
end
|
330
|
+
|
331
|
+
describe '#l' do
|
332
|
+
let(:direction) { 'l' }
|
333
|
+
let(:expected_state) {
|
334
|
+
'UF UR UB BL UL FR BR DL DF DR DB FL BUL URF UBR BLD FLU DFR DRB FDL'
|
335
|
+
}
|
336
|
+
|
337
|
+
it_should_behave_like 'a face turn'
|
338
|
+
end
|
339
|
+
|
340
|
+
describe '#u' do
|
341
|
+
let(:direction) { 'u' }
|
342
|
+
let(:expected_state) {
|
343
|
+
'UR UB UL UF FL FR BR BL DF DR DB DL URF UBR ULB UFL DLF DFR DRB DBL'
|
344
|
+
}
|
345
|
+
|
346
|
+
it_should_behave_like 'a face turn'
|
347
|
+
end
|
348
|
+
|
349
|
+
describe '#d' do
|
350
|
+
let(:direction) { 'd' }
|
351
|
+
let(:expected_state) {
|
352
|
+
'UF UR UB UL FL FR BR BL DL DF DR DB UFL URF UBR ULB DBL DLF DFR DRB'
|
353
|
+
}
|
354
|
+
|
355
|
+
it_should_behave_like 'a face turn'
|
356
|
+
end
|
357
|
+
|
358
|
+
describe '#f' do
|
359
|
+
let(:direction) { 'f' }
|
360
|
+
let(:expected_state) {
|
361
|
+
'LF UR UB UL FD FU BR BL RF DR DB DL LFD LUF UBR ULB RDF RFU DRB DBL'
|
362
|
+
}
|
363
|
+
|
364
|
+
it_should_behave_like 'a face turn'
|
365
|
+
end
|
366
|
+
|
367
|
+
describe '#b' do
|
368
|
+
let(:direction) { 'b' }
|
369
|
+
let(:expected_state) {
|
370
|
+
'UF UR RB UL FL FR BD BU DF DR LB DL UFL URF RBD RUB DLF DFR LDB LBU'
|
371
|
+
}
|
372
|
+
|
373
|
+
it_should_behave_like 'a face turn'
|
374
|
+
end
|
375
|
+
|
376
|
+
describe '#m' do
|
377
|
+
let(:direction) { 'm' }
|
378
|
+
let(:expected_state) {
|
379
|
+
'BU UR BD UL FL FR BR BL FU DR FD DL UFL URF UBR ULB DLF DFR DRB DBL'
|
380
|
+
}
|
381
|
+
|
382
|
+
it_should_behave_like 'a face turn'
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RubiksCube::Cubie do
|
4
|
+
subject { described_class.new state }
|
5
|
+
|
6
|
+
let(:state) { 'UF' }
|
7
|
+
|
8
|
+
it 'is initialized with a state' do
|
9
|
+
expect(subject.state).to eq state
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '==' do
|
13
|
+
context 'when the state equals the state of the other' do
|
14
|
+
it 'returns true' do
|
15
|
+
expect(subject == described_class.new(state)).to be_true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when the state does not equal the state of the other' do
|
20
|
+
it 'returns true' do
|
21
|
+
expect(subject == described_class.new('UB')).to be_false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#to_s' do
|
27
|
+
it 'converts the cubie to a string' do
|
28
|
+
expect(subject.to_s).to eq state
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#rotate!' do
|
33
|
+
context 'with an edge piece' do
|
34
|
+
let(:state) { 'UF' }
|
35
|
+
|
36
|
+
it 'flips the cubie' do
|
37
|
+
expect(subject.rotate!.state).to eq 'FU'
|
38
|
+
expect(subject.rotate!.state).to eq state
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'with a corner piece' do
|
43
|
+
let(:state) { 'URF' }
|
44
|
+
|
45
|
+
it 'rotates the cubie once couter clockwise' do
|
46
|
+
expect(subject.rotate!.state).to eq 'FUR'
|
47
|
+
expect(subject.rotate!.state).to eq 'RFU'
|
48
|
+
expect(subject.rotate!.state).to eq state
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe '#rotate' do
|
54
|
+
it "returns a new cubie that's been rotated" do
|
55
|
+
expect(subject.rotate).to eq described_class.new(state).rotate!
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'does not modify the cubie' do
|
59
|
+
original_state = subject.state.dup
|
60
|
+
|
61
|
+
subject.rotate
|
62
|
+
|
63
|
+
expect(subject.state).to eq original_state
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe RubiksCube::TwoCycleSolution do
|
4
|
+
subject { described_class.new cube }
|
5
|
+
|
6
|
+
let(:cube) { RubiksCube::Cube.new state }
|
7
|
+
let(:state) { nil }
|
8
|
+
|
9
|
+
describe '#solve!' do
|
10
|
+
shared_examples_for 'a cube that can be solved' do
|
11
|
+
it 'solves the cube' do
|
12
|
+
subject.solve!
|
13
|
+
expect(subject).to be_solved
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'does not modify the original cube state' do
|
18
|
+
original_cube_state = cube.l.state
|
19
|
+
|
20
|
+
subject.solve!
|
21
|
+
|
22
|
+
expect(cube.state).to eq original_cube_state
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when edges need to be swapped' do
|
26
|
+
let(:state) {
|
27
|
+
'UF UL UB UR FL FR BR BL DF DR DB DL UFL UBR URF ULB DLF DFR DRB DBL'
|
28
|
+
}
|
29
|
+
|
30
|
+
it_should_behave_like 'a cube that can be solved'
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'when corners need to be swapped' do
|
34
|
+
let(:state) {
|
35
|
+
'UL UR UB UF FL FR BR BL DF DR DB DL UBR URF UFL ULB DLF DFR DRB DBL'
|
36
|
+
}
|
37
|
+
|
38
|
+
it_should_behave_like 'a cube that can be solved'
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when two edges have incorrect orientation' do
|
42
|
+
before { cube.perform! RubiksCube::Algorithms::Orientation::Edge }
|
43
|
+
|
44
|
+
it_should_behave_like 'a cube that can be solved'
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when two corners have incorrect orientation' do
|
48
|
+
before { cube.perform! RubiksCube::Algorithms::Orientation::Corner }
|
49
|
+
|
50
|
+
it_should_behave_like 'a cube that can be solved'
|
51
|
+
end
|
52
|
+
|
53
|
+
[
|
54
|
+
"U2 L' F2 U' B D' R' F2 U F' R L2 F2 L' B L R2 B' D R L' U D' R2 F'",
|
55
|
+
"L U2 R' B2 U D R' U R' B2 L F R2 L' B' R' U2 L2 R2 U F' L' U' L U'",
|
56
|
+
"F' U2 D2 F2 R' D2 B L2 F L2 D2 F U2 F B L U' D' R' F D F' L2 F' B2",
|
57
|
+
"R2 U' D2 B L2 U' R D2 L2 U2 F2 D' B' L B' D L' B2 L' F' L' B2 F2 U' L2",
|
58
|
+
"L2 R D' U2 R L' B2 U' L2 D2 B2 D' R2 L' B' U2 B R2 F2 R' D' F2 D L U",
|
59
|
+
].each do |scramble|
|
60
|
+
context "with scramble (#{scramble})" do
|
61
|
+
before { cube.perform! scramble }
|
62
|
+
|
63
|
+
it_should_behave_like 'a cube that can be solved'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#solution' do
|
68
|
+
before do
|
69
|
+
cube.perform!([
|
70
|
+
RubiksCube::Algorithms::Permutation::Edge,
|
71
|
+
RubiksCube::Algorithms::Permutation::Corner,
|
72
|
+
RubiksCube::Algorithms::Orientation::Edge,
|
73
|
+
].join ' ')
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when the cube has not been solved' do
|
77
|
+
it 'first solves the cube' do
|
78
|
+
subject.should_receive(:solve!)
|
79
|
+
subject.solution
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
context 'when the cube has been solved' do
|
84
|
+
before { subject.solve! }
|
85
|
+
|
86
|
+
it 'returns the setup, algorithm, and undo moves' do
|
87
|
+
expect(subject.solution).to eq([
|
88
|
+
"", RubiksCube::Algorithms::Permutation::Edge, "",
|
89
|
+
"M2 D L2", RubiksCube::Algorithms::Permutation::Edge, "L2 D' M2",
|
90
|
+
"R2 D' R2", RubiksCube::Algorithms::Permutation::Corner, "R2 D R2",
|
91
|
+
"", RubiksCube::Algorithms::Permutation::Corner, "",
|
92
|
+
"R B", RubiksCube::Algorithms::Orientation::Edge, "B' R'",
|
93
|
+
"", RubiksCube::Algorithms::Orientation::Edge, ""
|
94
|
+
])
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#solution_length' do
|
100
|
+
it 'returns the length of the solution' do
|
101
|
+
cube.l.r
|
102
|
+
expect(subject.solution_length).to eq 634
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'returns zero when cube already solved' do
|
106
|
+
expect(subject.solution_length).to be_zero
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rubiks_cube'
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rubiks_cube
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Hunt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-05-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: cane-hashcheck
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
description: Learn how to solve the Rubik's Cube. It's easy!
|
70
|
+
email:
|
71
|
+
- c@chrishunt.co
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- CONTRIBUTING.md
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- Rakefile
|
82
|
+
- lib/rubiks_cube.rb
|
83
|
+
- lib/rubiks_cube/algorithms.rb
|
84
|
+
- lib/rubiks_cube/corner_cubie.rb
|
85
|
+
- lib/rubiks_cube/cube.rb
|
86
|
+
- lib/rubiks_cube/cubie.rb
|
87
|
+
- lib/rubiks_cube/edge_cubie.rb
|
88
|
+
- lib/rubiks_cube/two_cycle_solution.rb
|
89
|
+
- lib/rubiks_cube/version.rb
|
90
|
+
- rubiks_cube.gemspec
|
91
|
+
- spec/rubiks_cube/algorithms_spec.rb
|
92
|
+
- spec/rubiks_cube/cube_spec.rb
|
93
|
+
- spec/rubiks_cube/cubie_spec.rb
|
94
|
+
- spec/rubiks_cube/two_cycle_solution_spec.rb
|
95
|
+
- spec/spec_helper.rb
|
96
|
+
homepage: https://github.com/chrishunt/rubiks-cube
|
97
|
+
licenses:
|
98
|
+
- MIT
|
99
|
+
metadata: {}
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
requirements: []
|
115
|
+
rubyforge_project:
|
116
|
+
rubygems_version: 2.0.3
|
117
|
+
signing_key:
|
118
|
+
specification_version: 4
|
119
|
+
summary: Learn how to solve the Rubik's Cube. It's easy!
|
120
|
+
test_files:
|
121
|
+
- spec/rubiks_cube/algorithms_spec.rb
|
122
|
+
- spec/rubiks_cube/cube_spec.rb
|
123
|
+
- spec/rubiks_cube/cubie_spec.rb
|
124
|
+
- spec/rubiks_cube/two_cycle_solution_spec.rb
|
125
|
+
- spec/spec_helper.rb
|