├── .gitignore
├── CoreRubiksCube.playground
├── Contents.swift
├── Sources
│ └── CoreRubiksCube.swift
├── contents.xcplayground
└── playground.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.swp
3 | *~.nib
4 | build/
5 | */build/*
6 | *.pbxuser
7 | *.perspective
8 | *.perspectivev3
9 | *.mode1v3
10 | *.mode2v3
11 | xcuserdata/
12 | DerivedData
13 | *.xccheckout
14 | *.lock
15 | *.moved-aside
16 | .Trashes
17 | ._*
18 |
--------------------------------------------------------------------------------
/CoreRubiksCube.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //: Playground - noun: a place where people can play
2 |
3 | import Cocoa
4 |
5 |
6 | let cube = Cube()
7 |
8 | print(cube)
9 |
10 | assert(cube.makeFront(.counterclockwise).makeFront(.clockwise) == cube)
11 | assert(cube.makeBack(.counterclockwise).makeBack(.clockwise) == cube)
12 | assert(cube.makeUp(.counterclockwise).makeUp(.clockwise) == cube)
13 | assert(cube.makeDown(.counterclockwise).makeDown(.clockwise) == cube)
14 | assert(cube.makeLeft(.counterclockwise).makeLeft(.clockwise) == cube)
15 | assert(cube.makeRight(.counterclockwise).makeRight(.clockwise) == cube)
16 |
17 | assert(cube.makeFront(.double).makeFront(.double) == cube)
18 | assert(cube.makeBack(.double).makeBack(.double) == cube)
19 | assert(cube.makeUp(.double).makeUp(.double) == cube)
20 | assert(cube.makeDown(.double).makeDown(.double) == cube)
21 | assert(cube.makeLeft(.double).makeLeft(.double) == cube)
22 | assert(cube.makeRight(.double).makeRight(.double) == cube)
23 |
24 | assert(cube.makeMove(Movement.front(.clockwise)).makeMove(Movement.front(.counterclockwise)) == cube)
25 | assert(cube.makeMove(Movement.back(.clockwise)).makeMove(Movement.back(.counterclockwise)) == cube)
26 | assert(cube.makeMove(Movement.up(.clockwise)).makeMove(Movement.up(.counterclockwise)) == cube)
27 | assert(cube.makeMove(Movement.down(.clockwise)).makeMove(Movement.down(.counterclockwise)) == cube)
28 | assert(cube.makeMove(Movement.left(.clockwise)).makeMove(Movement.left(.counterclockwise)) == cube)
29 | assert(cube.makeMove(Movement.right(.clockwise)).makeMove(Movement.right(.counterclockwise)) == cube)
30 |
31 | assert(cube.makeMove(Movement.front(.double)).makeMove(Movement.front(.double)) == cube)
32 | assert(cube.makeMove(Movement.back(.double)).makeMove(Movement.back(.double)) == cube)
33 | assert(cube.makeMove(Movement.up(.double)).makeMove(Movement.up(.double)) == cube)
34 | assert(cube.makeMove(Movement.down(.double)).makeMove(Movement.down(.double)) == cube)
35 | assert(cube.makeMove(Movement.left(.double)).makeMove(Movement.left(.double)) == cube)
36 | assert(cube.makeMove(Movement.right(.double)).makeMove(Movement.right(.double)) == cube)
37 |
38 |
39 | let moves: [Movement] = [
40 | .front(.clockwise), .back(.clockwise),
41 | .up(.clockwise), .down(.clockwise),
42 | .left(.clockwise), .right(.clockwise),
43 | .front(.counterclockwise), .back(.counterclockwise),
44 | .up(.counterclockwise), .down(.counterclockwise),
45 | .left(.counterclockwise), .right(.counterclockwise),
46 | .front(.double), .back(.double),
47 | .up(.double), .down(.double),
48 | .left(.double), .right(.double)
49 | ]
50 |
51 | assert(cube.makeMoves(moves).reverseMoves(moves) == cube)
52 |
53 |
--------------------------------------------------------------------------------
/CoreRubiksCube.playground/Sources/CoreRubiksCube.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CoreRubiksCube.swift
3 | // CoreRubiksCube
4 | //
5 | // The MIT License (MIT)
6 | //
7 | // Copyright (c) 2016 Electricwoods LLC, Kaz Yoshikawa.
8 | //
9 | // Permission is hereby granted, free of charge, to any person obtaining a copy
10 | // of this software and associated documentation files (the "Software"), to deal
11 | // in the Software without restriction, including without limitation the rights
12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | // copies of the Software, and to permit persons to whom the Software is
14 | // furnished to do so, subject to the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be included in
17 | // all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 | // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | // THE SOFTWARE.
26 |
27 | import Foundation
28 |
29 |
30 | // Overview
31 | // --------
32 | // This code is for implementing Rubik's Cube's model and it's behavior. It is
33 | // not intended for providing any graphical interface or solver related code.
34 | // It is however, provides basic functionality to turn faces, to reverse
35 | // turns, and to examine the state of the cube.
36 | //
37 | // Xcode 9.2, Swift 4
38 |
39 | // Face:
40 | // A Rubik's Cube has six faces. In order to identify specific face, each face has
41 | // its own unique name. We assume, face will not move around, instead any faces
42 | // can be turned or spined, and each surfaces stay the same place.
43 | //
44 |
45 | public enum Face {
46 | case front
47 | case back
48 | case up
49 | case down
50 | case left
51 | case right
52 | }
53 |
54 |
55 | // Tile:
56 | // Tile represent a single piece of tile of a surface. Each surface has
57 | // 3x3 (9) tiles. In order to identify each tiles of the cube, each tile
58 | // has own unique identifier as follows. The naming idea id taking from
59 | // this site http://iamthecu.be.
60 | //
61 | //
62 | // |U18|U19|U20| :
63 | // |U10|U11|U12| : +-----+
64 | // |U01|U02|U03| : | U |
65 | // |L18|L10|L01|F01|F02|F03|R03|R12|R20|B20|B19|B18| : +-----+-----+-----+-----+
66 | // |L21|L13|L04|F04|F05|F06|R06|R14|R23|B23|B22|B21| : | L | F | R | B |
67 | // |L24|L15|L07|F07|F08|F09|R09|R17|R16|B26|B25|B24| : +-----+-----+-----+-----+
68 | // |D07|D08|D09| : | D |
69 | // |D15|D16|D17| : +-----+
70 | // |D24|D25|D26| :
71 | // ** Figure 1 **
72 |
73 | public enum Tile {
74 | case F01, F02, F03, F06, F09, F08, F07, F04, F05 // front
75 | case U18, U19, U20, U12, U03, U02, U01, U10, U11 // up
76 | case R03, R12, R20, R23, R26, R17, R09, R06, R14 // right
77 | case B24, B25, B26, B23, B20, B19, B18, B21, B22 // back
78 | case D07, D08, D09, D17, D26, D25, D24, D15, D16 // down
79 | case L18, L10, L01, L04, L07, L15, L24, L21, L13 // left
80 | }
81 |
82 | // Turn:
83 | // Each surface can be turned in either `clockwise`, `counterclockwise` or `double` spins.
84 |
85 | public enum Turn {
86 | case clockwise
87 | case counterclockwise
88 | case `double`
89 |
90 | public func reversed() -> Turn {
91 | switch self {
92 | case .clockwise: return .counterclockwise
93 | case .counterclockwise: return .clockwise
94 | case .double: return .double
95 | }
96 | }
97 | }
98 |
99 | // Movement:
100 | // A cube can be turn any faces, `Movement` specifies which face to make turn.
101 | // It has an associated value with it.
102 |
103 | public enum Movement {
104 | case front(Turn)
105 | case back(Turn)
106 | case up(Turn)
107 | case down(Turn)
108 | case left(Turn)
109 | case right(Turn)
110 | }
111 |
112 | // Surface:
113 | // A `Surface` specifies all tiles on a face. In order to specify a tile on a face,
114 | // we assign `a` to `i` for each positions of tiles. All positions apply to all faces
115 | // in figure 1 including `back` face which can be controversial.
116 | //
117 | // +---+---+---+
118 | // | a | b | c |
119 | // +---+---+---+
120 | // | d | e | f |
121 | // +---+---+---+
122 | // | g | h | i |
123 | // +---+---+---+
124 | // ** Figure 2 **
125 |
126 | public struct Surface: CustomStringConvertible, Equatable {
127 | public let (a, b, c): (Tile, Tile, Tile)
128 | public let (d, e, f): (Tile, Tile, Tile)
129 | public let (g, h, i): (Tile, Tile, Tile)
130 |
131 | init(_ a: Tile, _ b: Tile, _ c: Tile, _ d: Tile, _ e: Tile, _ f: Tile, _ g: Tile, _ h: Tile, _ i: Tile) {
132 | (self.a, self.b, self.c) = (a, b, c)
133 | (self.d, self.e, self.f) = (d, e, f)
134 | (self.g, self.h, self.i) = (g, h, i)
135 | }
136 |
137 | init(face: Face) {
138 | switch (face) {
139 | case .front: (a, b, c, d, e, f, g, h, i) = (.F01, .F02, .F03, .F04, .F05, .F06, .F07, .F08, .F09)
140 | case .back: (a, b, c, d, e, f, g, h, i) = (.B20, .B19, .B18, .B23, .B22, .B21, .B26, .B25, .B24)
141 | case .up: (a, b, c, d, e, f, g, h, i) = (.U18, .U19, .U20, .U10, .U11, .U12, .U01, .U02, .U03)
142 | case .down: (a, b, c, d, e, f, g, h, i) = (.D07, .D08, .D09, .D15, .D16, .D17, .D24, .D25, .D26)
143 | case .left: (a, b, c, d, e, f, g, h, i) = (.L18, .L10, .L01, .L21, .L13, .L04, .L24, .L15, .L07)
144 | case .right: (a, b, c, d, e, f, g, h, i) = (.R03, .R12, .R20, .R06, .R14, .R23, .R09, .R17, .R26)
145 | }
146 | }
147 |
148 | public var description: String {
149 | return [[a, b, c], [d, e, f], [g, h, i]].map { $0.map { String(describing: $0) }.joined(separator: "|") }.joined(separator: "\n")
150 | }
151 |
152 | func turn(_ turn: Turn) -> Surface {
153 | switch turn {
154 | case .clockwise: return Surface(g, d, a, h, e, b, i, f, c)
155 | case .counterclockwise: return Surface(c, f, i, b, e, h, a, d, g)
156 | case .double: return Surface(i, h, g, f, e, d, c, b, a)
157 | }
158 | }
159 |
160 | // accessors to pick three tiles in a row
161 | var abc: (Tile, Tile, Tile) { return (a, b, c) }
162 | var cba: (Tile, Tile, Tile) { return (c, b, a) }
163 | var ghi: (Tile, Tile, Tile) { return (g, h, i) }
164 | var ihg: (Tile, Tile, Tile) { return (i, h, g) }
165 | var adg: (Tile, Tile, Tile) { return (a, d, g) }
166 | var gda: (Tile, Tile, Tile) { return (g, d, a) }
167 | var cfi: (Tile, Tile, Tile) { return (c, f, i) }
168 | var ifc: (Tile, Tile, Tile) { return (i, f, c) }
169 |
170 | // returns a surface replaced by a row with other row
171 | func replaced(abc: (a: Tile, b: Tile, c: Tile)) -> Surface {
172 | return Surface(abc.a, abc.b, abc.c, d, e, f, g, h, i)
173 | }
174 | func replaced(ghi: (g: Tile, h: Tile, i: Tile)) -> Surface {
175 | return Surface(a, b, c, d, e, f, ghi.g, ghi.h, ghi.i)
176 | }
177 | func replaced(adg: (a: Tile, d: Tile, g: Tile)) -> Surface {
178 | return Surface(adg.a, b, c, adg.d, e, f, adg.g, h, i)
179 | }
180 | func replaced(cfi: (c: Tile, f: Tile, i: Tile)) -> Surface {
181 | return Surface(a, b, cfi.c, d, e, cfi.f, g, h, cfi.i)
182 | }
183 |
184 | // to conform Equatable
185 | public static func == (lhs: Surface, rhs: Surface) -> Bool {
186 | return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c &&
187 | lhs.d == rhs.d && lhs.e == rhs.e && lhs.f == rhs.f &&
188 | lhs.g == rhs.g && lhs.h == rhs.h && lhs.i == rhs.i
189 | }
190 | }
191 |
192 | // Cube:
193 | // `Cube` represnet a complete tiles of all faces
194 | //
195 |
196 | public struct Cube: CustomStringConvertible, Equatable {
197 | public let front: Surface
198 | public let back: Surface
199 | public let up: Surface
200 | public let down: Surface
201 | public let left: Surface
202 | public let right: Surface
203 |
204 |
205 | public init(front: Surface, back: Surface, up: Surface, down: Surface, left: Surface, right: Surface) {
206 | self.front = front
207 | self.back = back
208 | self.up = up
209 | self.down = down
210 | self.left = left
211 | self.right = right
212 | }
213 |
214 | public init() {
215 | front = Surface(face: .front)
216 | back = Surface(face: .back)
217 | up = Surface(face: .up)
218 | down = Surface(face: .down)
219 | left = Surface(face: .left)
220 | right = Surface(face: .right)
221 | }
222 |
223 | // accessor to retrieve a specific surface for the face
224 | public func surface(face: Face) -> Surface {
225 | switch (face) {
226 | case .front: return front
227 | case .back: return back
228 | case .up: return up
229 | case .down: return down
230 | case .left: return left
231 | case .right: return right
232 | }
233 | }
234 |
235 | // mostly debuging purpose
236 | public var description: String {
237 | let (f, b, u, d, l, r) = (front, back, up, down, left, right)
238 | return ([
239 | [ nil, nil, nil, u.a, u.b, u.c, nil, nil, nil, nil, nil, nil ],
240 | [ nil, nil, nil, u.d, u.e, u.f, nil, nil, nil, nil, nil, nil ],
241 | [ nil, nil, nil, u.g, u.h, u.i, nil, nil, nil, nil, nil, nil ],
242 | [ l.a, l.b, l.c, f.a, f.b, f.c, r.a, r.b, r.c, b.a, b.b, b.c ],
243 | [ l.d, l.e, l.f, f.d, f.e, f.f, r.d, r.e, r.f, b.d, b.e, b.f ],
244 | [ l.g, l.h, l.i, f.g, f.h, f.i, r.g, r.h, r.i, b.g, b.h, b.i ],
245 | [ nil, nil, nil, d.a, d.b, d.c, nil, nil, nil, nil, nil, nil ],
246 | [ nil, nil, nil, d.d, d.e, d.f, nil, nil, nil, nil, nil, nil ],
247 | [ nil, nil, nil, d.g, d.h, d.i, nil, nil, nil, nil, nil, nil ]
248 | ] as [[Tile?]])
249 | .map { "|" + $0.map { $0 != nil ? String(describing: $0!) + "|" : " |" }.joined() }.joined(separator: "\n")
250 | }
251 |
252 | // make a turn on fornt face
253 | public func makeFront(_ turn: Turn) -> Cube {
254 | let f = front.turn(turn)
255 | switch turn {
256 | case .clockwise:
257 | let u = up.replaced(ghi: left.ifc)
258 | let r = right.replaced(adg: up.ghi)
259 | let d = down.replaced(abc: right.gda)
260 | let l = left.replaced(cfi: down.abc)
261 | return Cube(front: f, back: back, up: u, down: d, left: l, right: r)
262 | case .counterclockwise:
263 | let u = up.replaced(ghi: right.adg)
264 | let r = right.replaced(adg: down.cba)
265 | let d = down.replaced(abc: left.cfi)
266 | let l = left.replaced(cfi: up.ihg)
267 | return Cube(front: f, back: back, up: u, down: d, left: l, right: r)
268 | case .double:
269 | let u = up.replaced(ghi: down.cba)
270 | let r = right.replaced(adg: left.ifc)
271 | let d = down.replaced(abc: up.ihg)
272 | let l = left.replaced(cfi: right.gda)
273 | return Cube(front: f, back: back, up: u, down: d, left: l, right: r)
274 | }
275 | }
276 |
277 | // make a turn on back face
278 | public func makeBack(_ turn: Turn) -> Cube {
279 | let b = back.turn(turn)
280 | switch turn {
281 | case .clockwise:
282 | let u = up.replaced(abc: right.cfi)
283 | let r = right.replaced(cfi: down.ihg)
284 | let d = down.replaced(ghi: left.adg)
285 | let l = left.replaced(adg: up.cba)
286 | return Cube(front: front, back: b, up: u, down: d, left: l, right: r)
287 | case .counterclockwise:
288 | let u = up.replaced(abc: left.gda)
289 | let r = right.replaced(cfi: up.abc)
290 | let d = down.replaced(ghi: right.ifc)
291 | let l = left.replaced(adg: down.ghi)
292 | return Cube(front: front, back: b, up: u, down: d, left: l, right: r)
293 | case .double:
294 | let u = up.replaced(abc: down.ihg)
295 | let r = right.replaced(cfi: left.gda)
296 | let d = down.replaced(ghi: up.cba)
297 | let l = left.replaced(adg: right.ifc)
298 | return Cube(front: front, back: b, up: u, down: d, left: l, right: r)
299 | }
300 | }
301 |
302 | // make a turn on up face
303 | public func makeUp(_ turn: Turn) -> Cube {
304 | let u = up.turn(turn)
305 | switch turn {
306 | case .clockwise:
307 | let f = front.replaced(abc: right.abc)
308 | let l = left.replaced(abc: front.abc)
309 | let b = back.replaced(abc: left.abc)
310 | let r = right.replaced(abc: back.abc)
311 | return Cube(front: f, back: b, up: u, down: down, left: l, right: r)
312 | case .counterclockwise:
313 | let f = front.replaced(abc: left.abc)
314 | let l = left.replaced(abc: back.abc)
315 | let b = back.replaced(abc: right.abc)
316 | let r = right.replaced(abc: front.abc)
317 | return Cube(front: f, back: b, up: u, down: down, left: l, right: r)
318 | case .double:
319 | let f = front.replaced(abc: back.abc)
320 | let l = left.replaced(abc: right.abc)
321 | let b = back.replaced(abc: front.abc)
322 | let r = right.replaced(abc: left.abc)
323 | return Cube(front: f, back: b, up: u, down: down, left: l, right: r)
324 | }
325 | }
326 |
327 | // make a turn on down face
328 | public func makeDown(_ turn: Turn) -> Cube {
329 | let d = down.turn(turn)
330 | switch turn {
331 | case .clockwise:
332 | let f = front.replaced(ghi: left.ghi)
333 | let l = left.replaced(ghi: back.ghi)
334 | let b = back.replaced(ghi: right.ghi)
335 | let r = right.replaced(ghi: front.ghi)
336 | return Cube(front: f, back: b, up: up, down: d, left: l, right: r)
337 | case .counterclockwise:
338 | let f = front.replaced(ghi: right.ghi)
339 | let l = left.replaced(ghi: front.ghi)
340 | let b = back.replaced(ghi: left.ghi)
341 | let r = right.replaced(ghi: back.ghi)
342 | return Cube(front: f, back: b, up: up, down: d, left: l, right: r)
343 | case .double:
344 | let f = front.replaced(ghi: back.ghi)
345 | let l = left.replaced(ghi: right.ghi)
346 | let b = back.replaced(ghi: front.ghi)
347 | let r = right.replaced(ghi: left.ghi)
348 | return Cube(front: f, back: b, up: up, down: d, left: l, right: r)
349 | }
350 | }
351 |
352 | // make a turn on right face
353 | public func makeRight(_ turn: Turn) -> Cube {
354 | let r = right.turn(turn)
355 | switch turn {
356 | case .clockwise:
357 | let f = front.replaced(cfi: down.cfi)
358 | let u = up.replaced(cfi: front.cfi)
359 | let b = back.replaced(adg: up.ifc)
360 | let d = down.replaced(cfi: back.gda)
361 | return Cube(front: f, back: b, up: u, down: d, left: left, right: r)
362 | case .counterclockwise:
363 | let f = front.replaced(cfi: up.cfi)
364 | let u = up.replaced(cfi: back.gda)
365 | let b = back.replaced(adg: down.ifc)
366 | let d = down.replaced(cfi: front.cfi)
367 | return Cube(front: f, back: b, up: u, down: d, left: left, right: r)
368 | case .double:
369 | let f = front.replaced(cfi: back.gda)
370 | let u = up.replaced(cfi: down.cfi)
371 | let b = back.replaced(adg: front.ifc)
372 | let d = down.replaced(cfi: up.cfi)
373 | return Cube(front: f, back: b, up: u, down: d, left: left, right: r)
374 | }
375 | }
376 |
377 | // make a turn on left face
378 | public func makeLeft(_ turn: Turn) -> Cube {
379 | let l = left.turn(turn)
380 | switch turn {
381 | case .clockwise:
382 | let f = front.replaced(adg: up.adg)
383 | let u = up.replaced(adg: back.ifc)
384 | let b = back.replaced(cfi: down.gda)
385 | let d = down.replaced(adg: front.adg)
386 | return Cube(front: f, back: b, up: u, down: d, left: l, right: right)
387 | case .counterclockwise:
388 | let f = front.replaced(adg: down.adg)
389 | let u = up.replaced(adg: front.adg)
390 | let b = back.replaced(cfi: up.gda)
391 | let d = down.replaced(adg: back.ifc)
392 | return Cube(front: f, back: b, up: u, down: d, left: l, right: right)
393 | case .double:
394 | let f = front.replaced(adg: back.ifc)
395 | let u = up.replaced(adg: down.adg)
396 | let b = back.replaced(cfi: front.gda)
397 | let d = down.replaced(adg: up.adg)
398 | return Cube(front: f, back: b, up: u, down: d, left: l, right: right)
399 | }
400 | }
401 |
402 | // make a single turn
403 | public func makeMove(_ movement: Movement) -> Cube {
404 | switch movement {
405 | case .front(let turn): return makeFront(turn)
406 | case .back(let turn): return makeBack(turn)
407 | case .up(let turn): return makeUp(turn)
408 | case .down(let turn): return makeDown(turn)
409 | case .left(let turn): return makeLeft(turn)
410 | case .right(let turn): return makeRight(turn)
411 | }
412 | }
413 |
414 | // reverse a single turn
415 | public func reverseMove(_ movement: Movement) -> Cube {
416 | switch movement {
417 | case .front(let turn): return makeFront(turn.reversed())
418 | case .back(let turn): return makeBack(turn.reversed())
419 | case .up(let turn): return makeUp(turn.reversed())
420 | case .down(let turn): return makeDown(turn.reversed())
421 | case .left(let turn): return makeLeft(turn.reversed())
422 | case .right(let turn): return makeRight(turn.reversed())
423 | }
424 | }
425 |
426 | // make a sequence of turns
427 | public func makeMoves(_ movements: [Movement]) -> Cube {
428 | var cube = self
429 | for movement in movements {
430 | cube = cube.makeMove(movement)
431 | }
432 | return cube
433 | }
434 |
435 | // reverse a sequence of turns
436 | public func reverseMoves(_ movements: [Movement]) -> Cube {
437 | var cube = self
438 | for movement in movements.reversed() {
439 | cube = cube.reverseMove(movement)
440 | }
441 | return cube
442 | }
443 |
444 | // to conform Equatable
445 | public static func == (lhs: Cube, rhs: Cube) -> Bool {
446 | return lhs.front == rhs.front && lhs.back == rhs.back &&
447 | lhs.up == rhs.up && lhs.down == rhs.down &&
448 | lhs.left == rhs.left && lhs.right == rhs.right
449 | }
450 | }
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
--------------------------------------------------------------------------------
/CoreRubiksCube.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/CoreRubiksCube.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CoreRubiksCube.playground/playground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Core Rubik's Cube
2 |
3 |
4 | 
5 | 
6 | 
7 |
8 |
9 |
10 | Core Rublik's Cube is a piece of code to implement basic implementation of Rubik's Cube. It does not offer any graphical user interface nor feature to solve the cube. It does, however, provide turn faces or to reverse those turns to find the state of the cube programmatically.
11 |
12 | ### Usage
13 |
14 | You may instantiate a cube with initialized positions, and print it as follows.
15 |
16 | ```.swift
17 | let cube1 = Cube()
18 | print(cube1)
19 | ```
20 |
21 | The cube's state should be printed to console as follows. As you can see, each tile has it's own unique identifier on it.
22 |
23 | ```
24 | | | | |U18|U19|U20| | | | | | |
25 | | | | |U10|U11|U12| | | | | | |
26 | | | | |U01|U02|U03| | | | | | |
27 | |L18|L10|L01|F01|F02|F03|R03|R12|R20|B20|B19|B18|
28 | |L21|L13|L04|F04|F05|F06|R06|R14|R23|B23|B22|B21|
29 | |L24|L15|L07|F07|F08|F09|R09|R17|R26|B26|B25|B24|
30 | | | | |D07|D08|D09| | | | | | |
31 | | | | |D15|D16|D17| | | | | | |
32 | | | | |D24|D25|D26| | | | | | |
33 | ```
34 |
35 | For getting some ideas about faces on a cube, here is the image of the unfolded faces of a cube. F, B, U, D, L and R are stands for front, back, up, down, left and right. They are commonly used for Rubik's Cube community.
36 |
37 | ```
38 | +---+
39 | | U |
40 | +---+---+---+---+
41 | | L | F | R | B |
42 | +---+---+---+---+
43 | | D |
44 | +---+
45 | ```
46 |
47 | Then you may turn front face counter clockwise and print as follows.
48 |
49 | ```.swift
50 | let cube2 = cube1.makeFront(.counterclockwise)
51 | print(cube2)
52 | ```
53 | You will find front face and it's related cubelets are rotated counter clockwise.
54 |
55 |
56 | ```
57 | | | | |U18|U19|U20| | | | | | |
58 | | | | |U10|U11|U12| | | | | | |
59 | | | | |R03|R06|R09| | | | | | |
60 | |L18|L10|U03|F03|F06|F09|D09|R12|R20|B20|B19|B18|
61 | |L21|L13|U02|F02|F05|F08|D08|R14|R23|B23|B22|B21|
62 | |L24|L15|U01|F01|F04|F07|D07|R17|R26|B26|B25|B24|
63 | | | | |L01|L04|L07| | | | | | |
64 | | | | |D15|D16|D17| | | | | | |
65 | | | | |D24|D25|D26| | | | | | |
66 | ```
67 |
68 | You may examine any surface by accessing `front`, `back`, `up`, `down`, `left` and `right` properties. Here is the code to print `front` surface of the cube.
69 |
70 | ```.swift
71 | print(cube.front)
72 | ```
73 | You can find 9 identifiers from a surface, and each identifier represent an unique tile of a cube.
74 |
75 | ```
76 | F01|F02|F03
77 | F04|F05|F06
78 | F07|F08|F09
79 | ```
80 |
81 | All tiles on a cube are defined as enum as follows.
82 |
83 | ```.swift
84 | public enum Tile {
85 | case F01, F02, F03, F06, F09, F08, F07, F04, F05 // front
86 | case U18, U19, U20, U12, U03, U02, U01, U10, U11 // up
87 | case R03, R12, R20, R23, R26, R17, R09, R06, R14 // right
88 | case B24, B25, B26, B23, B20, B19, B18, B21, B22 // back
89 | case D07, D08, D09, D17, D26, D25, D24, D15, D16 // down
90 | case L18, L10, L01, L04, L07, L15, L24, L21, L13 // left
91 | }
92 | ```
93 |
94 | Tile positions on a surface are described as follows.
95 |
96 | ```
97 | +---+---+---+
98 | | a | b | c |
99 | +---+---+---+
100 | | d | e | f |
101 | +---+---+---+
102 | | g | h | i |
103 | +---+---+---+
104 | ```
105 |
106 | So, you can access to any position of a surface by accessing `a`, `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h` and `i` properties.
107 |
108 | ```.swift
109 | cube.front.g // F07
110 | cube.up.b // U19
111 | cube.back.a // B20
112 | ```
113 |
114 | You may make a turn of any surface of a cube. `Cube` provides some method to make a single rotation of any face of a cube. Those methods do not make any changes of the instance itself, rather they return a new instance with made rotation given by parameter `Turn`.
115 |
116 | ```.swift
117 | public func makeFront(_ turn: Turn) -> Cube
118 | public func makeBack(_ turn: Turn) -> Cube
119 | public func makeUp(_ turn: Turn) -> Cube
120 | public func makeDown(_ turn: Turn) -> Cube
121 | public func makeleft(_ turn: Turn) -> Cube
122 | public func makeRight(_ turn: Turn) -> Cube
123 | ```
124 |
125 | Turn describe which direction to make a turn either `clockwise`, `counterclockwise` or `double`. `Double` turns a surface twice in the same direction, therefore, regardless clockwise or counter clockwise, the results are the same.
126 |
127 | ```.swift
128 | public enum Turn {
129 | case clockwise
130 | case counterclockwise
131 | case `double`
132 | }
133 | ```
134 |
135 | You may provide a sequence of `Movement` which describes face and turn direction to perform multiple turns in once just like following example.
136 |
137 |
138 | ```.swift
139 | let moves: [Movement] =
140 | [
141 | .front(turn: .clockwise),
142 | .back(turn: .clockwise),
143 | .left(turn: .counterclockwise),
144 | .right(turn: .counterclockwise),
145 | .up(turn: .double),
146 | .down(turn: .double)
147 | ]
148 | let cube3 = cube.makeMoves(moves)
149 | ```
150 |
151 | You may perform the same sequence backward to reverse the operation.
152 |
153 | ```.swift
154 | let cube4 = cube3.reverseMoves(moves)
155 | ```
156 |
157 | Since, `Cube` conforms to `Equatable` protocol, you may make sure reversing operation actually work.
158 |
159 | ```.swift
160 | cube4 == cube // true
161 | ```
162 |
163 | ### Types
164 |
165 | | Type | Description |
166 | |:--------------|:------------|
167 | | Face | Specifies a face direction of cube |
168 | | Surface | Specifies a face of cube that contains tiles |
169 | | Tile | A suface of a cubelet. A surface contains 3x3, 9 `Tile`s. |
170 | | Turn | A turn direction either `clockwise`, `counterclockwise`, or `double` |
171 | | Movement | A single turn action which face and which turn direction |
172 | | Cube | A whole cube with six surfaces |
173 |
174 |
175 | ### Why did I do this?
176 |
177 | Good question, but I do not have a good answer for that question.
178 |
179 |
180 | ### Environment
181 |
182 | ```
183 | Version 11.4.1 (11E503a)
184 | Apple Swift version 5.2.2 (swiftlang-1103.0.32.6 clang-1103.0.32.51)
185 | Target: x86_64-apple-darwin19.4.0
186 | ```
187 |
188 |
--------------------------------------------------------------------------------