Rubik's cube mode for emacs












12












$begingroup$


Following is a dumb implementation of Rubik's cube for Emacs. I am not well versed in writing (e)lisp, so I ask for a review and corrections.



;;   -*- lexical-binding: t; -*-
;;; rubic_cube.el
;; emulation and solution of rubic's cube in emacs

;; cube layout
(defconst rubic-cube-front-default '(" / \ "
" / \ "
" / \ / \ "
" / \_/ \ "
" / \ / \ / \ "
" / \_/ \_/ \ "
" |\_ / \ / \ /| "
" | \ / \_/ \_/ | "
" | |\_ / \ /| | "
" |\_ | \ / \_/ | _/| "
" | \| |\_ _/| |/ | "
" | |\_ | \ / | _/| | "
" |\_ | \| | |/ | _/| "
" | \| |\ | /| |/ | "
" | |\_ | \|/ | _/| | "
" \_ | \| | |/ | _/ "
" \| |\_ | _/| |/ "
" \_ | \|/ | _/ "
" \| | |/ "
" \_ | _/ "
" \|/ "))
(defconst rubic-cube-back-default '(" _/|\_ "
" / | \ "
" _/| | |\_ "
" / | _/|\_ | \ "
" _/| |/ | \| |\_ "
" / | _/| | |\_ | \ "
" | |/ | _/|\_ | \| | "
" | _/| |/ | \| |\_ | "
" |/ | _/| | |\_ | \| "
" | |/ | _/ \_ | \| | "
" | _/| |/ \| |\_ | "
" |/ | _/ \_ _/ \_ | \| "
" | |/ \_/ \| | "
" | _/ \_ / \_ _/ \_ | "
" |/ \_/ \_/ \| "
" \_ _/ \_ _/ \_ _/ "
" \ / \_/ \_/ "
" \_ _/ \_ _/ "
" \ / \_/ "
" \_ _/ "
" \_/ "))

(defvar-local rubic-cuve-back nil
"Canbas for front of rubic's cube")

(defvar-local rubic-cube-front nil
"Canvas for back of rubic's cube")

(defconst side-coord '[(0 14) (7 3) (11 17) (5 5) (1 15) (9 14)]
"Coordinates of starting points of the cube sides")

;; faces
(defface rubic-red
'((t . (:background "red")))
"Red colored cube side")
(defface rubic-orange
'((t . (:background "orange")))
"Orange colored cube side")
(defface rubic-white
'((t . (:background "antique white")))
"white colored cube side")
(defface rubic-blue
'((t . (:background "blue")))
"Blue colored cube side")
(defface rubic-yellow
'((t . (:background "yellow")))
"Yellow colored cube side")
(defface rubic-green
'((t . (:background "green")))
"green colored cube side")

(defconst rubic-faces [rubic-red
rubic-white
rubic-green
rubic-yellow
rubic-blue
rubic-orange])

;; painter functions
(defun rubic-color-painter (face)
"make function that will apply color to string"
(lambda (str beg end prn)
(add-face-text-property beg end face t str)))

(defun rubic-paint-diamond (cube-screen coord painter)
"Paint diamond shape with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) nil nil)
(apply painter (nth (incf l) cube-screen) c (1+ c) nil nil)))

(defun rubic-paint-slope-down (cube-screen coord painter)
"Paint downward slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (+ c 2) nil nil)
(apply painter (nth (incf l) cube-screen) c (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (1+ c) (+ c 3) nil nil)))

(defun rubic-paint-slope-up (cube-screen coord painter)
"Paint upwards slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) (1- c) (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (1+ c) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) c nil nil)))

(defun rubic-make-initial-cube ()
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
do (loop for j from 0 to 8
do (aset res (+ j (* i 9)) i))
finally return res))

(defun rubic-displace-diamond (coord local-number)
"Calculate displacement of the cell of top and bottom sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 2 row)))
(setq c (- c (* 4 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-downslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-upslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (- l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-get-local-number (cell-number)
(list (/ cell-number 9) (mod cell-number 9)))

(defun rubic-paint-cell (front back number color)
(destructuring-bind (side local-number) (rubic-get-local-number number)
(let ((canvas (if (< side 3) front back))
(painter (rubic-color-painter (aref rubic-faces color)))
(filler (case side
((0 5) 'rubic-paint-diamond)
((1 4) 'rubic-paint-slope-down)
((2 3) 'rubic-paint-slope-up)))
(translator (case side
((0 5) 'rubic-displace-diamond)
((1 4) 'rubic-displace-downslope)
((2 3) 'rubic-displace-upslope))))
(apply filler canvas (apply translator (aref side-coord side) local-number nil) painter nil))))


(defun rubic-paint-cube (cube-state)
(setq rubic-cube-front (mapcar #'copy-sequence rubic-cube-front-default))
(setq rubic-cube-back (mapcar #'copy-sequence rubic-cube-back-default))
(loop for i from 1 to (* 6 9) do
(rubic-paint-cell rubic-cube-front rubic-cube-back (1- i) (aref cube-state (1- i)))))

;; definitions for rotational notation
(require 'calc)
(defconst rubic-i '(cplx 0 1))
(defconst rubic-neg-i '(cplx 0 -1))

(defconst rubic-desc-rot-identity
'((0 1) (1 1) (2 1) (3 1) (4 1) (5 1)))

(defconst rubic-desc-rot-1-2
`((1 1) (5 ,rubic-i) (2 ,rubic-neg-i) (0 -1) (4 ,rubic-i) (3 ,rubic-i)))

(defconst rubic-desc-rot-1-3
`((2 ,rubic-i) (1 ,rubic-i) (5 -1) (3 ,rubic-neg-i) (0 ,rubic-i) (4 1)))

(defconst rubic-desc-rot-2-3
`((0 ,rubic-neg-i) (2 1) (3 1) (4 1) (1 1) (5 ,rubic-i)))

(defun rubic-compose-rot (rot-1 rot-2)
"Make rotation from two defined ones"
(loop for (n1 r1) in rot-1
for (n2 r2) = (nth n1 rot-2)
collect (list n2 (math-mul r1 r2))))

(defun rubic-rotate (&rest turns)
"Compose as many rotations as needed"
(reduce 'rubic-compose-rot turns))

(defconst rubicside-renumbering-clockwise
'(6 3 0 7 4 1 8 5 2))

(defun rubic-compose-subst (sub1 sub2)
(loop for i1 in sub1
for i2 = (nth i1 sub2)
collect i2))

(defun rubic-substitute (&rest subs)
(reduce 'rubic-compose-subst subs))

(defconst rubic-side-rotations
(list (cons rubic-i rubicside-renumbering-clockwise)
(cons -1 (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
(cons rubic-neg-i (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
;; we could call with 4 rotations or define a constant for identity. But therte is no need, really
(cons 1 (list 0 1 2 3 4 5 6 7 8))))

(defun rubic-expand-substitution (sub)
"Get substitution for entire cube state"
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
for (side-number rot) = (nth i sub)
for side-reorder = (cdr (assoc rot rubic-side-rotations))
for base-offset = (* i 9)
for target-offset = (* side-number 9)
do (loop for j from 0 to 8
do
(setf (aref res (+ j target-offset))
(+ base-offset (nth j side-reorder))))
finally return (append res nil)))

(defconst rubic-turn-top-substitution
(let ((temp (coerce (loop for i from 0 to (1- (* 9 6)) collect i) 'vector))
(side-offsets '((9 36) (18 9) (27 18) (36 27)))
(rotation (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise)))
(loop for i from 0 to 8 do (aset temp i (nth i rotation)))
(loop for (loc num) in side-offsets do
(loop for i from 0 to 2 do
(aset temp (+ loc i) (+ num i))))
(append temp nil)))

(defun rubic-apply-transformation (state transform)
(let ((second (copy-sequence state)))
(loop for i from 0 to (1- (length second)) do
(aset state (nth i transform) (aref second i)))))

;; definitions of common transformations
(defconst rubic-U
rubic-turn-top-substitution)

(defconst rubic-U2
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-Ui
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-F
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-F2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Fi
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-R
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-R2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-Ri
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-L
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-L2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-Li
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-B
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-B2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-Bi
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-D
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-D2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Di
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-x
(rubic-expand-substitution rubic-desc-rot-1-2))

(defconst rubic-x2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-xi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-y
(rubic-expand-substitution rubic-desc-rot-2-3))

(defconst rubic-y2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-yi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-zi
(rubic-expand-substitution rubic-desc-rot-1-3))

(defconst rubic-z2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

(defconst rubic-z
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

;; mode definitions
(defvar-local cube-state nil
"State of the cube that is being processed")

(defvar-local cube-undo (list 'undo)
"List of previously executed commands")

(defvar-local cube-redo (list 'redo)
"List of previously undone commands")

(defun rubic-center-string (str l)
(if (> (length str) l)
(substring str l)
(let* ((sl (length str))
(pad (/ (- l sl) 2))
(rem (- l pad)))
(concat (format (format "%%%ds" rem) str) (make-string pad ? )))))

(defun rubic-display-cube ()
"Draw current cube state, assuming empty buffer"
;; first, update canvasses according to the cube state
(rubic-paint-cube cube-state)
(let ((w (length (first rubic-cube-front-default)))
(h (length rubic-cube-front-default)))
(insert (format "%s%sn"
(rubic-center-string "*FRONT*" w)
(rubic-center-string "*BACK*" w)))
(insert-rectangle rubic-cube-front)
(forward-line (- (decf h)))
(move-end-of-line nil)
(insert-rectangle rubic-cube-back)))

(defun rubic-display-undo ()
"Print undo information"
(loop with line-str = "nUndo: "
for cmd in (reverse (cdr cube-undo))
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-display-redo ()
"Print undo information"
(loop with line-str = "nRedo: "
for cmd in (cdr cube-redo)
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-draw-all ()
(setq buffer-read-only nil)
(erase-buffer)
(rubic-display-cube)
(rubic-display-undo)
(rubic-display-redo)
(setq buffer-read-only t))

(defmacro rubic-define-command (transformation desc)
(let ((command-name (intern (concat (symbol-name transformation) "-command"))))
(put command-name 'name desc)
`(defun ,command-name (&optional arg)
(interactive)
(rubic-apply-transformation cube-state ,transformation)
(unless arg
(setcdr cube-redo nil)
(setcdr cube-undo (cons (quote ,command-name) (cdr cube-undo)))
(rubic-draw-all)))))

(defmacro rubic-define-commands (&rest transformations)
(let ((head (car transformations))
(command-name (cadr transformations))
(tail (cddr transformations)))
`(progn
,(when head
`(rubic-define-command ,head ,command-name))
,(when tail
`(rubic-define-commands ,@tail)))))

(rubic-define-commands rubic-U "Upper" rubic-U2 "Upper twice" rubic-Ui "Upper inverted"
rubic-F "Front" rubic-F2 "Front twice" rubic-Fi "Front inverted"
rubic-R "Right" rubic-R2 "Right twice" rubic-Ri "Right inverted"
rubic-L "Left" rubic-L2 "Left twice" rubic-Li "Left inverted"
rubic-B "Back" rubic-B2 "Back twice" rubic-Bi "Back inverted"
rubic-D "Down" rubic-D2 "Down twice" rubic-Di "Down inverted"
rubic-x "X rotation" rubic-x2 "X overturn" rubic-xi "X rotation inverted"
rubic-y "Y rotation" rubic-y2 "Y overturn" rubic-yi "Y rotation inverted"
rubic-z "Z rotation" rubic-z2 "Z overturn" rubic-zi "Z rotation inverted")

(defconst rubic-reverse-commands
'((rubic-U-command . rubic-Ui-command)
(rubic-U2-command . rubic-U2-command)
(rubic-F-command . rubic-Fi-command)
(rubic-F2-command . rubic-F2-command)
(rubic-R-command . rubic-Ri-command)
(rubic-R2-command . rubic-R2-command)
(rubic-L-command . rubic-Li-command)
(rubic-L2-command . rubic-L2-command)
(rubic-B-command . rubic-Bi-command)
(rubic-B2-command . rubic-B2-command)
(rubic-D-command . rubic-Di-command)
(rubic-D2-command . rubic-D2-command)
(rubic-x-command . rubic-xi-command)
(rubic-x2-command . rubic-x2-command)
(rubic-y-command . rubic-yi-command)
(rubic-y2-command . rubic-y2-command)
(rubic-z-command . rubic-zi-command)
(rubic-z2-command . rubic-z2-command)))

(defun rubic-reset ()
"Set cube to initial state"
(interactive)
(setq cube-state (rubic-make-initial-cube))
(setq cube-undo (list 'undo))
(setq cube-redo (list 'redo))
(rubic-draw-all))

(defun rubic-undo (&optional arg)
"Undo up to ARG commands from undo list"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-undo)
when lastcmd do
(let ((revcmd (or (cdr (assoc lastcmd rubic-reverse-commands))
(car (rassoc lastcmd rubic-reverse-commands)))))
(setcdr cube-redo (cons lastcmd (cdr cube-redo)))
(setcdr cube-undo (cddr cube-undo))
(apply revcmd '(t))))
(rubic-draw-all)))

(defun rubic-redo (&optional arg)
"Redo up to ARG commands"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-redo)
when lastcmd do
(progn
(setcdr cube-undo (cons lastcmd (cdr cube-undo)))
(setcdr cube-redo (cddr cube-redo))
(apply lastcmd '(t))))
(rubic-draw-all)))

(defvar rubic-mode-map
(let ((map (make-sparse-keymap))
(map-i (make-sparse-keymap))
(map-2 (make-sparse-keymap)))
(define-key map "u" 'rubic-U-command)
(define-key map-2 "u" 'rubic-U2-command)
(define-key map-i "u" 'rubic-Ui-command)
(define-key map "f" 'rubic-F-command)
(define-key map-2 "f" 'rubic-F2-command)
(define-key map-i "f" 'rubic-Fi-command)
(define-key map "r" 'rubic-R-command)
(define-key map-2 "r" 'rubic-R2-command)
(define-key map-i "r" 'rubic-Ri-command)
(define-key map "l" 'rubic-L-command)
(define-key map-2 "l" 'rubic-L2-command)
(define-key map-i "l" 'rubic-Li-command)
(define-key map "b" 'rubic-B-command)
(define-key map-2 "b" 'rubic-B2-command)
(define-key map-i "b" 'rubic-Bi-command)
(define-key map "d" 'rubic-D-command)
(define-key map-2 "d" 'rubic-D2-command)
(define-key map-i "d" 'rubic-Di-command)
(define-key map "x" 'rubic-x-command)
(define-key map-2 "x" 'rubic-x2-command)
(define-key map-i "x" 'rubic-xi-command)
(define-key map "y" 'rubic-y-command)
(define-key map-2 "y" 'rubic-y2-command)
(define-key map-i "y" 'rubic-yi-command)
(define-key map "z" 'rubic-z-command)
(define-key map-2 "z" 'rubic-z2-command)
(define-key map-i "z" 'rubic-zi-command)
(define-key map "g" 'rubic-reset)
(define-key map "2" map-2)
(define-key map "i" map-i)
(define-key map (kbd "M-u") 'rubic-undo)
(define-key map (kbd "M-r") 'rubic-redo)
map))

(define-derived-mode rubic-mode special-mode
"rubic's cube")

(add-hook 'rubic-mode-hook
(lambda ()
(rubic-reset)))

(defun rubic ()
"Prepare for rubic mode"
(interactive)
(switch-to-buffer "*Rubic*")
(rubic-mode))









share|improve this question











$endgroup$








  • 1




    $begingroup$
    rubik's cube.
    $endgroup$
    – internet_user
    Jan 11 '18 at 13:12








  • 1




    $begingroup$
    That's an embarassing failure on my part
    $endgroup$
    – Srv19
    Jan 11 '18 at 19:42
















12












$begingroup$


Following is a dumb implementation of Rubik's cube for Emacs. I am not well versed in writing (e)lisp, so I ask for a review and corrections.



;;   -*- lexical-binding: t; -*-
;;; rubic_cube.el
;; emulation and solution of rubic's cube in emacs

;; cube layout
(defconst rubic-cube-front-default '(" / \ "
" / \ "
" / \ / \ "
" / \_/ \ "
" / \ / \ / \ "
" / \_/ \_/ \ "
" |\_ / \ / \ /| "
" | \ / \_/ \_/ | "
" | |\_ / \ /| | "
" |\_ | \ / \_/ | _/| "
" | \| |\_ _/| |/ | "
" | |\_ | \ / | _/| | "
" |\_ | \| | |/ | _/| "
" | \| |\ | /| |/ | "
" | |\_ | \|/ | _/| | "
" \_ | \| | |/ | _/ "
" \| |\_ | _/| |/ "
" \_ | \|/ | _/ "
" \| | |/ "
" \_ | _/ "
" \|/ "))
(defconst rubic-cube-back-default '(" _/|\_ "
" / | \ "
" _/| | |\_ "
" / | _/|\_ | \ "
" _/| |/ | \| |\_ "
" / | _/| | |\_ | \ "
" | |/ | _/|\_ | \| | "
" | _/| |/ | \| |\_ | "
" |/ | _/| | |\_ | \| "
" | |/ | _/ \_ | \| | "
" | _/| |/ \| |\_ | "
" |/ | _/ \_ _/ \_ | \| "
" | |/ \_/ \| | "
" | _/ \_ / \_ _/ \_ | "
" |/ \_/ \_/ \| "
" \_ _/ \_ _/ \_ _/ "
" \ / \_/ \_/ "
" \_ _/ \_ _/ "
" \ / \_/ "
" \_ _/ "
" \_/ "))

(defvar-local rubic-cuve-back nil
"Canbas for front of rubic's cube")

(defvar-local rubic-cube-front nil
"Canvas for back of rubic's cube")

(defconst side-coord '[(0 14) (7 3) (11 17) (5 5) (1 15) (9 14)]
"Coordinates of starting points of the cube sides")

;; faces
(defface rubic-red
'((t . (:background "red")))
"Red colored cube side")
(defface rubic-orange
'((t . (:background "orange")))
"Orange colored cube side")
(defface rubic-white
'((t . (:background "antique white")))
"white colored cube side")
(defface rubic-blue
'((t . (:background "blue")))
"Blue colored cube side")
(defface rubic-yellow
'((t . (:background "yellow")))
"Yellow colored cube side")
(defface rubic-green
'((t . (:background "green")))
"green colored cube side")

(defconst rubic-faces [rubic-red
rubic-white
rubic-green
rubic-yellow
rubic-blue
rubic-orange])

;; painter functions
(defun rubic-color-painter (face)
"make function that will apply color to string"
(lambda (str beg end prn)
(add-face-text-property beg end face t str)))

(defun rubic-paint-diamond (cube-screen coord painter)
"Paint diamond shape with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) nil nil)
(apply painter (nth (incf l) cube-screen) c (1+ c) nil nil)))

(defun rubic-paint-slope-down (cube-screen coord painter)
"Paint downward slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (+ c 2) nil nil)
(apply painter (nth (incf l) cube-screen) c (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (1+ c) (+ c 3) nil nil)))

(defun rubic-paint-slope-up (cube-screen coord painter)
"Paint upwards slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) (1- c) (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (1+ c) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) c nil nil)))

(defun rubic-make-initial-cube ()
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
do (loop for j from 0 to 8
do (aset res (+ j (* i 9)) i))
finally return res))

(defun rubic-displace-diamond (coord local-number)
"Calculate displacement of the cell of top and bottom sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 2 row)))
(setq c (- c (* 4 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-downslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-upslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (- l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-get-local-number (cell-number)
(list (/ cell-number 9) (mod cell-number 9)))

(defun rubic-paint-cell (front back number color)
(destructuring-bind (side local-number) (rubic-get-local-number number)
(let ((canvas (if (< side 3) front back))
(painter (rubic-color-painter (aref rubic-faces color)))
(filler (case side
((0 5) 'rubic-paint-diamond)
((1 4) 'rubic-paint-slope-down)
((2 3) 'rubic-paint-slope-up)))
(translator (case side
((0 5) 'rubic-displace-diamond)
((1 4) 'rubic-displace-downslope)
((2 3) 'rubic-displace-upslope))))
(apply filler canvas (apply translator (aref side-coord side) local-number nil) painter nil))))


(defun rubic-paint-cube (cube-state)
(setq rubic-cube-front (mapcar #'copy-sequence rubic-cube-front-default))
(setq rubic-cube-back (mapcar #'copy-sequence rubic-cube-back-default))
(loop for i from 1 to (* 6 9) do
(rubic-paint-cell rubic-cube-front rubic-cube-back (1- i) (aref cube-state (1- i)))))

;; definitions for rotational notation
(require 'calc)
(defconst rubic-i '(cplx 0 1))
(defconst rubic-neg-i '(cplx 0 -1))

(defconst rubic-desc-rot-identity
'((0 1) (1 1) (2 1) (3 1) (4 1) (5 1)))

(defconst rubic-desc-rot-1-2
`((1 1) (5 ,rubic-i) (2 ,rubic-neg-i) (0 -1) (4 ,rubic-i) (3 ,rubic-i)))

(defconst rubic-desc-rot-1-3
`((2 ,rubic-i) (1 ,rubic-i) (5 -1) (3 ,rubic-neg-i) (0 ,rubic-i) (4 1)))

(defconst rubic-desc-rot-2-3
`((0 ,rubic-neg-i) (2 1) (3 1) (4 1) (1 1) (5 ,rubic-i)))

(defun rubic-compose-rot (rot-1 rot-2)
"Make rotation from two defined ones"
(loop for (n1 r1) in rot-1
for (n2 r2) = (nth n1 rot-2)
collect (list n2 (math-mul r1 r2))))

(defun rubic-rotate (&rest turns)
"Compose as many rotations as needed"
(reduce 'rubic-compose-rot turns))

(defconst rubicside-renumbering-clockwise
'(6 3 0 7 4 1 8 5 2))

(defun rubic-compose-subst (sub1 sub2)
(loop for i1 in sub1
for i2 = (nth i1 sub2)
collect i2))

(defun rubic-substitute (&rest subs)
(reduce 'rubic-compose-subst subs))

(defconst rubic-side-rotations
(list (cons rubic-i rubicside-renumbering-clockwise)
(cons -1 (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
(cons rubic-neg-i (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
;; we could call with 4 rotations or define a constant for identity. But therte is no need, really
(cons 1 (list 0 1 2 3 4 5 6 7 8))))

(defun rubic-expand-substitution (sub)
"Get substitution for entire cube state"
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
for (side-number rot) = (nth i sub)
for side-reorder = (cdr (assoc rot rubic-side-rotations))
for base-offset = (* i 9)
for target-offset = (* side-number 9)
do (loop for j from 0 to 8
do
(setf (aref res (+ j target-offset))
(+ base-offset (nth j side-reorder))))
finally return (append res nil)))

(defconst rubic-turn-top-substitution
(let ((temp (coerce (loop for i from 0 to (1- (* 9 6)) collect i) 'vector))
(side-offsets '((9 36) (18 9) (27 18) (36 27)))
(rotation (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise)))
(loop for i from 0 to 8 do (aset temp i (nth i rotation)))
(loop for (loc num) in side-offsets do
(loop for i from 0 to 2 do
(aset temp (+ loc i) (+ num i))))
(append temp nil)))

(defun rubic-apply-transformation (state transform)
(let ((second (copy-sequence state)))
(loop for i from 0 to (1- (length second)) do
(aset state (nth i transform) (aref second i)))))

;; definitions of common transformations
(defconst rubic-U
rubic-turn-top-substitution)

(defconst rubic-U2
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-Ui
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-F
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-F2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Fi
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-R
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-R2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-Ri
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-L
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-L2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-Li
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-B
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-B2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-Bi
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-D
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-D2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Di
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-x
(rubic-expand-substitution rubic-desc-rot-1-2))

(defconst rubic-x2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-xi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-y
(rubic-expand-substitution rubic-desc-rot-2-3))

(defconst rubic-y2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-yi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-zi
(rubic-expand-substitution rubic-desc-rot-1-3))

(defconst rubic-z2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

(defconst rubic-z
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

;; mode definitions
(defvar-local cube-state nil
"State of the cube that is being processed")

(defvar-local cube-undo (list 'undo)
"List of previously executed commands")

(defvar-local cube-redo (list 'redo)
"List of previously undone commands")

(defun rubic-center-string (str l)
(if (> (length str) l)
(substring str l)
(let* ((sl (length str))
(pad (/ (- l sl) 2))
(rem (- l pad)))
(concat (format (format "%%%ds" rem) str) (make-string pad ? )))))

(defun rubic-display-cube ()
"Draw current cube state, assuming empty buffer"
;; first, update canvasses according to the cube state
(rubic-paint-cube cube-state)
(let ((w (length (first rubic-cube-front-default)))
(h (length rubic-cube-front-default)))
(insert (format "%s%sn"
(rubic-center-string "*FRONT*" w)
(rubic-center-string "*BACK*" w)))
(insert-rectangle rubic-cube-front)
(forward-line (- (decf h)))
(move-end-of-line nil)
(insert-rectangle rubic-cube-back)))

(defun rubic-display-undo ()
"Print undo information"
(loop with line-str = "nUndo: "
for cmd in (reverse (cdr cube-undo))
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-display-redo ()
"Print undo information"
(loop with line-str = "nRedo: "
for cmd in (cdr cube-redo)
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-draw-all ()
(setq buffer-read-only nil)
(erase-buffer)
(rubic-display-cube)
(rubic-display-undo)
(rubic-display-redo)
(setq buffer-read-only t))

(defmacro rubic-define-command (transformation desc)
(let ((command-name (intern (concat (symbol-name transformation) "-command"))))
(put command-name 'name desc)
`(defun ,command-name (&optional arg)
(interactive)
(rubic-apply-transformation cube-state ,transformation)
(unless arg
(setcdr cube-redo nil)
(setcdr cube-undo (cons (quote ,command-name) (cdr cube-undo)))
(rubic-draw-all)))))

(defmacro rubic-define-commands (&rest transformations)
(let ((head (car transformations))
(command-name (cadr transformations))
(tail (cddr transformations)))
`(progn
,(when head
`(rubic-define-command ,head ,command-name))
,(when tail
`(rubic-define-commands ,@tail)))))

(rubic-define-commands rubic-U "Upper" rubic-U2 "Upper twice" rubic-Ui "Upper inverted"
rubic-F "Front" rubic-F2 "Front twice" rubic-Fi "Front inverted"
rubic-R "Right" rubic-R2 "Right twice" rubic-Ri "Right inverted"
rubic-L "Left" rubic-L2 "Left twice" rubic-Li "Left inverted"
rubic-B "Back" rubic-B2 "Back twice" rubic-Bi "Back inverted"
rubic-D "Down" rubic-D2 "Down twice" rubic-Di "Down inverted"
rubic-x "X rotation" rubic-x2 "X overturn" rubic-xi "X rotation inverted"
rubic-y "Y rotation" rubic-y2 "Y overturn" rubic-yi "Y rotation inverted"
rubic-z "Z rotation" rubic-z2 "Z overturn" rubic-zi "Z rotation inverted")

(defconst rubic-reverse-commands
'((rubic-U-command . rubic-Ui-command)
(rubic-U2-command . rubic-U2-command)
(rubic-F-command . rubic-Fi-command)
(rubic-F2-command . rubic-F2-command)
(rubic-R-command . rubic-Ri-command)
(rubic-R2-command . rubic-R2-command)
(rubic-L-command . rubic-Li-command)
(rubic-L2-command . rubic-L2-command)
(rubic-B-command . rubic-Bi-command)
(rubic-B2-command . rubic-B2-command)
(rubic-D-command . rubic-Di-command)
(rubic-D2-command . rubic-D2-command)
(rubic-x-command . rubic-xi-command)
(rubic-x2-command . rubic-x2-command)
(rubic-y-command . rubic-yi-command)
(rubic-y2-command . rubic-y2-command)
(rubic-z-command . rubic-zi-command)
(rubic-z2-command . rubic-z2-command)))

(defun rubic-reset ()
"Set cube to initial state"
(interactive)
(setq cube-state (rubic-make-initial-cube))
(setq cube-undo (list 'undo))
(setq cube-redo (list 'redo))
(rubic-draw-all))

(defun rubic-undo (&optional arg)
"Undo up to ARG commands from undo list"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-undo)
when lastcmd do
(let ((revcmd (or (cdr (assoc lastcmd rubic-reverse-commands))
(car (rassoc lastcmd rubic-reverse-commands)))))
(setcdr cube-redo (cons lastcmd (cdr cube-redo)))
(setcdr cube-undo (cddr cube-undo))
(apply revcmd '(t))))
(rubic-draw-all)))

(defun rubic-redo (&optional arg)
"Redo up to ARG commands"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-redo)
when lastcmd do
(progn
(setcdr cube-undo (cons lastcmd (cdr cube-undo)))
(setcdr cube-redo (cddr cube-redo))
(apply lastcmd '(t))))
(rubic-draw-all)))

(defvar rubic-mode-map
(let ((map (make-sparse-keymap))
(map-i (make-sparse-keymap))
(map-2 (make-sparse-keymap)))
(define-key map "u" 'rubic-U-command)
(define-key map-2 "u" 'rubic-U2-command)
(define-key map-i "u" 'rubic-Ui-command)
(define-key map "f" 'rubic-F-command)
(define-key map-2 "f" 'rubic-F2-command)
(define-key map-i "f" 'rubic-Fi-command)
(define-key map "r" 'rubic-R-command)
(define-key map-2 "r" 'rubic-R2-command)
(define-key map-i "r" 'rubic-Ri-command)
(define-key map "l" 'rubic-L-command)
(define-key map-2 "l" 'rubic-L2-command)
(define-key map-i "l" 'rubic-Li-command)
(define-key map "b" 'rubic-B-command)
(define-key map-2 "b" 'rubic-B2-command)
(define-key map-i "b" 'rubic-Bi-command)
(define-key map "d" 'rubic-D-command)
(define-key map-2 "d" 'rubic-D2-command)
(define-key map-i "d" 'rubic-Di-command)
(define-key map "x" 'rubic-x-command)
(define-key map-2 "x" 'rubic-x2-command)
(define-key map-i "x" 'rubic-xi-command)
(define-key map "y" 'rubic-y-command)
(define-key map-2 "y" 'rubic-y2-command)
(define-key map-i "y" 'rubic-yi-command)
(define-key map "z" 'rubic-z-command)
(define-key map-2 "z" 'rubic-z2-command)
(define-key map-i "z" 'rubic-zi-command)
(define-key map "g" 'rubic-reset)
(define-key map "2" map-2)
(define-key map "i" map-i)
(define-key map (kbd "M-u") 'rubic-undo)
(define-key map (kbd "M-r") 'rubic-redo)
map))

(define-derived-mode rubic-mode special-mode
"rubic's cube")

(add-hook 'rubic-mode-hook
(lambda ()
(rubic-reset)))

(defun rubic ()
"Prepare for rubic mode"
(interactive)
(switch-to-buffer "*Rubic*")
(rubic-mode))









share|improve this question











$endgroup$








  • 1




    $begingroup$
    rubik's cube.
    $endgroup$
    – internet_user
    Jan 11 '18 at 13:12








  • 1




    $begingroup$
    That's an embarassing failure on my part
    $endgroup$
    – Srv19
    Jan 11 '18 at 19:42














12












12








12





$begingroup$


Following is a dumb implementation of Rubik's cube for Emacs. I am not well versed in writing (e)lisp, so I ask for a review and corrections.



;;   -*- lexical-binding: t; -*-
;;; rubic_cube.el
;; emulation and solution of rubic's cube in emacs

;; cube layout
(defconst rubic-cube-front-default '(" / \ "
" / \ "
" / \ / \ "
" / \_/ \ "
" / \ / \ / \ "
" / \_/ \_/ \ "
" |\_ / \ / \ /| "
" | \ / \_/ \_/ | "
" | |\_ / \ /| | "
" |\_ | \ / \_/ | _/| "
" | \| |\_ _/| |/ | "
" | |\_ | \ / | _/| | "
" |\_ | \| | |/ | _/| "
" | \| |\ | /| |/ | "
" | |\_ | \|/ | _/| | "
" \_ | \| | |/ | _/ "
" \| |\_ | _/| |/ "
" \_ | \|/ | _/ "
" \| | |/ "
" \_ | _/ "
" \|/ "))
(defconst rubic-cube-back-default '(" _/|\_ "
" / | \ "
" _/| | |\_ "
" / | _/|\_ | \ "
" _/| |/ | \| |\_ "
" / | _/| | |\_ | \ "
" | |/ | _/|\_ | \| | "
" | _/| |/ | \| |\_ | "
" |/ | _/| | |\_ | \| "
" | |/ | _/ \_ | \| | "
" | _/| |/ \| |\_ | "
" |/ | _/ \_ _/ \_ | \| "
" | |/ \_/ \| | "
" | _/ \_ / \_ _/ \_ | "
" |/ \_/ \_/ \| "
" \_ _/ \_ _/ \_ _/ "
" \ / \_/ \_/ "
" \_ _/ \_ _/ "
" \ / \_/ "
" \_ _/ "
" \_/ "))

(defvar-local rubic-cuve-back nil
"Canbas for front of rubic's cube")

(defvar-local rubic-cube-front nil
"Canvas for back of rubic's cube")

(defconst side-coord '[(0 14) (7 3) (11 17) (5 5) (1 15) (9 14)]
"Coordinates of starting points of the cube sides")

;; faces
(defface rubic-red
'((t . (:background "red")))
"Red colored cube side")
(defface rubic-orange
'((t . (:background "orange")))
"Orange colored cube side")
(defface rubic-white
'((t . (:background "antique white")))
"white colored cube side")
(defface rubic-blue
'((t . (:background "blue")))
"Blue colored cube side")
(defface rubic-yellow
'((t . (:background "yellow")))
"Yellow colored cube side")
(defface rubic-green
'((t . (:background "green")))
"green colored cube side")

(defconst rubic-faces [rubic-red
rubic-white
rubic-green
rubic-yellow
rubic-blue
rubic-orange])

;; painter functions
(defun rubic-color-painter (face)
"make function that will apply color to string"
(lambda (str beg end prn)
(add-face-text-property beg end face t str)))

(defun rubic-paint-diamond (cube-screen coord painter)
"Paint diamond shape with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) nil nil)
(apply painter (nth (incf l) cube-screen) c (1+ c) nil nil)))

(defun rubic-paint-slope-down (cube-screen coord painter)
"Paint downward slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (+ c 2) nil nil)
(apply painter (nth (incf l) cube-screen) c (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (1+ c) (+ c 3) nil nil)))

(defun rubic-paint-slope-up (cube-screen coord painter)
"Paint upwards slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) (1- c) (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (1+ c) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) c nil nil)))

(defun rubic-make-initial-cube ()
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
do (loop for j from 0 to 8
do (aset res (+ j (* i 9)) i))
finally return res))

(defun rubic-displace-diamond (coord local-number)
"Calculate displacement of the cell of top and bottom sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 2 row)))
(setq c (- c (* 4 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-downslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-upslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (- l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-get-local-number (cell-number)
(list (/ cell-number 9) (mod cell-number 9)))

(defun rubic-paint-cell (front back number color)
(destructuring-bind (side local-number) (rubic-get-local-number number)
(let ((canvas (if (< side 3) front back))
(painter (rubic-color-painter (aref rubic-faces color)))
(filler (case side
((0 5) 'rubic-paint-diamond)
((1 4) 'rubic-paint-slope-down)
((2 3) 'rubic-paint-slope-up)))
(translator (case side
((0 5) 'rubic-displace-diamond)
((1 4) 'rubic-displace-downslope)
((2 3) 'rubic-displace-upslope))))
(apply filler canvas (apply translator (aref side-coord side) local-number nil) painter nil))))


(defun rubic-paint-cube (cube-state)
(setq rubic-cube-front (mapcar #'copy-sequence rubic-cube-front-default))
(setq rubic-cube-back (mapcar #'copy-sequence rubic-cube-back-default))
(loop for i from 1 to (* 6 9) do
(rubic-paint-cell rubic-cube-front rubic-cube-back (1- i) (aref cube-state (1- i)))))

;; definitions for rotational notation
(require 'calc)
(defconst rubic-i '(cplx 0 1))
(defconst rubic-neg-i '(cplx 0 -1))

(defconst rubic-desc-rot-identity
'((0 1) (1 1) (2 1) (3 1) (4 1) (5 1)))

(defconst rubic-desc-rot-1-2
`((1 1) (5 ,rubic-i) (2 ,rubic-neg-i) (0 -1) (4 ,rubic-i) (3 ,rubic-i)))

(defconst rubic-desc-rot-1-3
`((2 ,rubic-i) (1 ,rubic-i) (5 -1) (3 ,rubic-neg-i) (0 ,rubic-i) (4 1)))

(defconst rubic-desc-rot-2-3
`((0 ,rubic-neg-i) (2 1) (3 1) (4 1) (1 1) (5 ,rubic-i)))

(defun rubic-compose-rot (rot-1 rot-2)
"Make rotation from two defined ones"
(loop for (n1 r1) in rot-1
for (n2 r2) = (nth n1 rot-2)
collect (list n2 (math-mul r1 r2))))

(defun rubic-rotate (&rest turns)
"Compose as many rotations as needed"
(reduce 'rubic-compose-rot turns))

(defconst rubicside-renumbering-clockwise
'(6 3 0 7 4 1 8 5 2))

(defun rubic-compose-subst (sub1 sub2)
(loop for i1 in sub1
for i2 = (nth i1 sub2)
collect i2))

(defun rubic-substitute (&rest subs)
(reduce 'rubic-compose-subst subs))

(defconst rubic-side-rotations
(list (cons rubic-i rubicside-renumbering-clockwise)
(cons -1 (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
(cons rubic-neg-i (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
;; we could call with 4 rotations or define a constant for identity. But therte is no need, really
(cons 1 (list 0 1 2 3 4 5 6 7 8))))

(defun rubic-expand-substitution (sub)
"Get substitution for entire cube state"
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
for (side-number rot) = (nth i sub)
for side-reorder = (cdr (assoc rot rubic-side-rotations))
for base-offset = (* i 9)
for target-offset = (* side-number 9)
do (loop for j from 0 to 8
do
(setf (aref res (+ j target-offset))
(+ base-offset (nth j side-reorder))))
finally return (append res nil)))

(defconst rubic-turn-top-substitution
(let ((temp (coerce (loop for i from 0 to (1- (* 9 6)) collect i) 'vector))
(side-offsets '((9 36) (18 9) (27 18) (36 27)))
(rotation (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise)))
(loop for i from 0 to 8 do (aset temp i (nth i rotation)))
(loop for (loc num) in side-offsets do
(loop for i from 0 to 2 do
(aset temp (+ loc i) (+ num i))))
(append temp nil)))

(defun rubic-apply-transformation (state transform)
(let ((second (copy-sequence state)))
(loop for i from 0 to (1- (length second)) do
(aset state (nth i transform) (aref second i)))))

;; definitions of common transformations
(defconst rubic-U
rubic-turn-top-substitution)

(defconst rubic-U2
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-Ui
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-F
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-F2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Fi
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-R
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-R2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-Ri
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-L
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-L2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-Li
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-B
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-B2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-Bi
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-D
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-D2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Di
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-x
(rubic-expand-substitution rubic-desc-rot-1-2))

(defconst rubic-x2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-xi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-y
(rubic-expand-substitution rubic-desc-rot-2-3))

(defconst rubic-y2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-yi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-zi
(rubic-expand-substitution rubic-desc-rot-1-3))

(defconst rubic-z2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

(defconst rubic-z
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

;; mode definitions
(defvar-local cube-state nil
"State of the cube that is being processed")

(defvar-local cube-undo (list 'undo)
"List of previously executed commands")

(defvar-local cube-redo (list 'redo)
"List of previously undone commands")

(defun rubic-center-string (str l)
(if (> (length str) l)
(substring str l)
(let* ((sl (length str))
(pad (/ (- l sl) 2))
(rem (- l pad)))
(concat (format (format "%%%ds" rem) str) (make-string pad ? )))))

(defun rubic-display-cube ()
"Draw current cube state, assuming empty buffer"
;; first, update canvasses according to the cube state
(rubic-paint-cube cube-state)
(let ((w (length (first rubic-cube-front-default)))
(h (length rubic-cube-front-default)))
(insert (format "%s%sn"
(rubic-center-string "*FRONT*" w)
(rubic-center-string "*BACK*" w)))
(insert-rectangle rubic-cube-front)
(forward-line (- (decf h)))
(move-end-of-line nil)
(insert-rectangle rubic-cube-back)))

(defun rubic-display-undo ()
"Print undo information"
(loop with line-str = "nUndo: "
for cmd in (reverse (cdr cube-undo))
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-display-redo ()
"Print undo information"
(loop with line-str = "nRedo: "
for cmd in (cdr cube-redo)
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-draw-all ()
(setq buffer-read-only nil)
(erase-buffer)
(rubic-display-cube)
(rubic-display-undo)
(rubic-display-redo)
(setq buffer-read-only t))

(defmacro rubic-define-command (transformation desc)
(let ((command-name (intern (concat (symbol-name transformation) "-command"))))
(put command-name 'name desc)
`(defun ,command-name (&optional arg)
(interactive)
(rubic-apply-transformation cube-state ,transformation)
(unless arg
(setcdr cube-redo nil)
(setcdr cube-undo (cons (quote ,command-name) (cdr cube-undo)))
(rubic-draw-all)))))

(defmacro rubic-define-commands (&rest transformations)
(let ((head (car transformations))
(command-name (cadr transformations))
(tail (cddr transformations)))
`(progn
,(when head
`(rubic-define-command ,head ,command-name))
,(when tail
`(rubic-define-commands ,@tail)))))

(rubic-define-commands rubic-U "Upper" rubic-U2 "Upper twice" rubic-Ui "Upper inverted"
rubic-F "Front" rubic-F2 "Front twice" rubic-Fi "Front inverted"
rubic-R "Right" rubic-R2 "Right twice" rubic-Ri "Right inverted"
rubic-L "Left" rubic-L2 "Left twice" rubic-Li "Left inverted"
rubic-B "Back" rubic-B2 "Back twice" rubic-Bi "Back inverted"
rubic-D "Down" rubic-D2 "Down twice" rubic-Di "Down inverted"
rubic-x "X rotation" rubic-x2 "X overturn" rubic-xi "X rotation inverted"
rubic-y "Y rotation" rubic-y2 "Y overturn" rubic-yi "Y rotation inverted"
rubic-z "Z rotation" rubic-z2 "Z overturn" rubic-zi "Z rotation inverted")

(defconst rubic-reverse-commands
'((rubic-U-command . rubic-Ui-command)
(rubic-U2-command . rubic-U2-command)
(rubic-F-command . rubic-Fi-command)
(rubic-F2-command . rubic-F2-command)
(rubic-R-command . rubic-Ri-command)
(rubic-R2-command . rubic-R2-command)
(rubic-L-command . rubic-Li-command)
(rubic-L2-command . rubic-L2-command)
(rubic-B-command . rubic-Bi-command)
(rubic-B2-command . rubic-B2-command)
(rubic-D-command . rubic-Di-command)
(rubic-D2-command . rubic-D2-command)
(rubic-x-command . rubic-xi-command)
(rubic-x2-command . rubic-x2-command)
(rubic-y-command . rubic-yi-command)
(rubic-y2-command . rubic-y2-command)
(rubic-z-command . rubic-zi-command)
(rubic-z2-command . rubic-z2-command)))

(defun rubic-reset ()
"Set cube to initial state"
(interactive)
(setq cube-state (rubic-make-initial-cube))
(setq cube-undo (list 'undo))
(setq cube-redo (list 'redo))
(rubic-draw-all))

(defun rubic-undo (&optional arg)
"Undo up to ARG commands from undo list"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-undo)
when lastcmd do
(let ((revcmd (or (cdr (assoc lastcmd rubic-reverse-commands))
(car (rassoc lastcmd rubic-reverse-commands)))))
(setcdr cube-redo (cons lastcmd (cdr cube-redo)))
(setcdr cube-undo (cddr cube-undo))
(apply revcmd '(t))))
(rubic-draw-all)))

(defun rubic-redo (&optional arg)
"Redo up to ARG commands"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-redo)
when lastcmd do
(progn
(setcdr cube-undo (cons lastcmd (cdr cube-undo)))
(setcdr cube-redo (cddr cube-redo))
(apply lastcmd '(t))))
(rubic-draw-all)))

(defvar rubic-mode-map
(let ((map (make-sparse-keymap))
(map-i (make-sparse-keymap))
(map-2 (make-sparse-keymap)))
(define-key map "u" 'rubic-U-command)
(define-key map-2 "u" 'rubic-U2-command)
(define-key map-i "u" 'rubic-Ui-command)
(define-key map "f" 'rubic-F-command)
(define-key map-2 "f" 'rubic-F2-command)
(define-key map-i "f" 'rubic-Fi-command)
(define-key map "r" 'rubic-R-command)
(define-key map-2 "r" 'rubic-R2-command)
(define-key map-i "r" 'rubic-Ri-command)
(define-key map "l" 'rubic-L-command)
(define-key map-2 "l" 'rubic-L2-command)
(define-key map-i "l" 'rubic-Li-command)
(define-key map "b" 'rubic-B-command)
(define-key map-2 "b" 'rubic-B2-command)
(define-key map-i "b" 'rubic-Bi-command)
(define-key map "d" 'rubic-D-command)
(define-key map-2 "d" 'rubic-D2-command)
(define-key map-i "d" 'rubic-Di-command)
(define-key map "x" 'rubic-x-command)
(define-key map-2 "x" 'rubic-x2-command)
(define-key map-i "x" 'rubic-xi-command)
(define-key map "y" 'rubic-y-command)
(define-key map-2 "y" 'rubic-y2-command)
(define-key map-i "y" 'rubic-yi-command)
(define-key map "z" 'rubic-z-command)
(define-key map-2 "z" 'rubic-z2-command)
(define-key map-i "z" 'rubic-zi-command)
(define-key map "g" 'rubic-reset)
(define-key map "2" map-2)
(define-key map "i" map-i)
(define-key map (kbd "M-u") 'rubic-undo)
(define-key map (kbd "M-r") 'rubic-redo)
map))

(define-derived-mode rubic-mode special-mode
"rubic's cube")

(add-hook 'rubic-mode-hook
(lambda ()
(rubic-reset)))

(defun rubic ()
"Prepare for rubic mode"
(interactive)
(switch-to-buffer "*Rubic*")
(rubic-mode))









share|improve this question











$endgroup$




Following is a dumb implementation of Rubik's cube for Emacs. I am not well versed in writing (e)lisp, so I ask for a review and corrections.



;;   -*- lexical-binding: t; -*-
;;; rubic_cube.el
;; emulation and solution of rubic's cube in emacs

;; cube layout
(defconst rubic-cube-front-default '(" / \ "
" / \ "
" / \ / \ "
" / \_/ \ "
" / \ / \ / \ "
" / \_/ \_/ \ "
" |\_ / \ / \ /| "
" | \ / \_/ \_/ | "
" | |\_ / \ /| | "
" |\_ | \ / \_/ | _/| "
" | \| |\_ _/| |/ | "
" | |\_ | \ / | _/| | "
" |\_ | \| | |/ | _/| "
" | \| |\ | /| |/ | "
" | |\_ | \|/ | _/| | "
" \_ | \| | |/ | _/ "
" \| |\_ | _/| |/ "
" \_ | \|/ | _/ "
" \| | |/ "
" \_ | _/ "
" \|/ "))
(defconst rubic-cube-back-default '(" _/|\_ "
" / | \ "
" _/| | |\_ "
" / | _/|\_ | \ "
" _/| |/ | \| |\_ "
" / | _/| | |\_ | \ "
" | |/ | _/|\_ | \| | "
" | _/| |/ | \| |\_ | "
" |/ | _/| | |\_ | \| "
" | |/ | _/ \_ | \| | "
" | _/| |/ \| |\_ | "
" |/ | _/ \_ _/ \_ | \| "
" | |/ \_/ \| | "
" | _/ \_ / \_ _/ \_ | "
" |/ \_/ \_/ \| "
" \_ _/ \_ _/ \_ _/ "
" \ / \_/ \_/ "
" \_ _/ \_ _/ "
" \ / \_/ "
" \_ _/ "
" \_/ "))

(defvar-local rubic-cuve-back nil
"Canbas for front of rubic's cube")

(defvar-local rubic-cube-front nil
"Canvas for back of rubic's cube")

(defconst side-coord '[(0 14) (7 3) (11 17) (5 5) (1 15) (9 14)]
"Coordinates of starting points of the cube sides")

;; faces
(defface rubic-red
'((t . (:background "red")))
"Red colored cube side")
(defface rubic-orange
'((t . (:background "orange")))
"Orange colored cube side")
(defface rubic-white
'((t . (:background "antique white")))
"white colored cube side")
(defface rubic-blue
'((t . (:background "blue")))
"Blue colored cube side")
(defface rubic-yellow
'((t . (:background "yellow")))
"Yellow colored cube side")
(defface rubic-green
'((t . (:background "green")))
"green colored cube side")

(defconst rubic-faces [rubic-red
rubic-white
rubic-green
rubic-yellow
rubic-blue
rubic-orange])

;; painter functions
(defun rubic-color-painter (face)
"make function that will apply color to string"
(lambda (str beg end prn)
(add-face-text-property beg end face t str)))

(defun rubic-paint-diamond (cube-screen coord painter)
"Paint diamond shape with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (+ c 3) nil nil)
(apply painter (nth (incf l) cube-screen) c (1+ c) nil nil)))

(defun rubic-paint-slope-down (cube-screen coord painter)
"Paint downward slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) c (+ c 2) nil nil)
(apply painter (nth (incf l) cube-screen) c (+ c 3) t nil)
(apply painter (nth (incf l) cube-screen) (1+ c) (+ c 3) nil nil)))

(defun rubic-paint-slope-up (cube-screen coord painter)
"Paint upwards slope with provided paint function"
(let ((l (first coord))
(c (second coord)))
(apply painter (nth l cube-screen) (1- c) (1+ c) nil nil)
(apply painter (nth (incf l) cube-screen) (- c 2) (1+ c) t nil)
(apply painter (nth (incf l) cube-screen) (- c 2) c nil nil)))

(defun rubic-make-initial-cube ()
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
do (loop for j from 0 to 8
do (aset res (+ j (* i 9)) i))
finally return res))

(defun rubic-displace-diamond (coord local-number)
"Calculate displacement of the cell of top and bottom sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 2 row)))
(setq c (- c (* 4 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-downslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (+ l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-displace-upslope (coord local-number)
"Calculate displacements of te cell of front and left sides"
(let ((l (first coord))
(c (second coord))
(row (/ local-number 3))
(col (mod local-number 3)))
(setq l (+ l (* 3 row)))
(setq l (- l (* 2 col)))
(setq c (+ c (* 4 col)))
(list l c)))

(defun rubic-get-local-number (cell-number)
(list (/ cell-number 9) (mod cell-number 9)))

(defun rubic-paint-cell (front back number color)
(destructuring-bind (side local-number) (rubic-get-local-number number)
(let ((canvas (if (< side 3) front back))
(painter (rubic-color-painter (aref rubic-faces color)))
(filler (case side
((0 5) 'rubic-paint-diamond)
((1 4) 'rubic-paint-slope-down)
((2 3) 'rubic-paint-slope-up)))
(translator (case side
((0 5) 'rubic-displace-diamond)
((1 4) 'rubic-displace-downslope)
((2 3) 'rubic-displace-upslope))))
(apply filler canvas (apply translator (aref side-coord side) local-number nil) painter nil))))


(defun rubic-paint-cube (cube-state)
(setq rubic-cube-front (mapcar #'copy-sequence rubic-cube-front-default))
(setq rubic-cube-back (mapcar #'copy-sequence rubic-cube-back-default))
(loop for i from 1 to (* 6 9) do
(rubic-paint-cell rubic-cube-front rubic-cube-back (1- i) (aref cube-state (1- i)))))

;; definitions for rotational notation
(require 'calc)
(defconst rubic-i '(cplx 0 1))
(defconst rubic-neg-i '(cplx 0 -1))

(defconst rubic-desc-rot-identity
'((0 1) (1 1) (2 1) (3 1) (4 1) (5 1)))

(defconst rubic-desc-rot-1-2
`((1 1) (5 ,rubic-i) (2 ,rubic-neg-i) (0 -1) (4 ,rubic-i) (3 ,rubic-i)))

(defconst rubic-desc-rot-1-3
`((2 ,rubic-i) (1 ,rubic-i) (5 -1) (3 ,rubic-neg-i) (0 ,rubic-i) (4 1)))

(defconst rubic-desc-rot-2-3
`((0 ,rubic-neg-i) (2 1) (3 1) (4 1) (1 1) (5 ,rubic-i)))

(defun rubic-compose-rot (rot-1 rot-2)
"Make rotation from two defined ones"
(loop for (n1 r1) in rot-1
for (n2 r2) = (nth n1 rot-2)
collect (list n2 (math-mul r1 r2))))

(defun rubic-rotate (&rest turns)
"Compose as many rotations as needed"
(reduce 'rubic-compose-rot turns))

(defconst rubicside-renumbering-clockwise
'(6 3 0 7 4 1 8 5 2))

(defun rubic-compose-subst (sub1 sub2)
(loop for i1 in sub1
for i2 = (nth i1 sub2)
collect i2))

(defun rubic-substitute (&rest subs)
(reduce 'rubic-compose-subst subs))

(defconst rubic-side-rotations
(list (cons rubic-i rubicside-renumbering-clockwise)
(cons -1 (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
(cons rubic-neg-i (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise))
;; we could call with 4 rotations or define a constant for identity. But therte is no need, really
(cons 1 (list 0 1 2 3 4 5 6 7 8))))

(defun rubic-expand-substitution (sub)
"Get substitution for entire cube state"
(loop with res = (make-vector (* 9 6) 0)
for i from 0 to 5
for (side-number rot) = (nth i sub)
for side-reorder = (cdr (assoc rot rubic-side-rotations))
for base-offset = (* i 9)
for target-offset = (* side-number 9)
do (loop for j from 0 to 8
do
(setf (aref res (+ j target-offset))
(+ base-offset (nth j side-reorder))))
finally return (append res nil)))

(defconst rubic-turn-top-substitution
(let ((temp (coerce (loop for i from 0 to (1- (* 9 6)) collect i) 'vector))
(side-offsets '((9 36) (18 9) (27 18) (36 27)))
(rotation (rubic-substitute rubicside-renumbering-clockwise
rubicside-renumbering-clockwise
rubicside-renumbering-clockwise)))
(loop for i from 0 to 8 do (aset temp i (nth i rotation)))
(loop for (loc num) in side-offsets do
(loop for i from 0 to 2 do
(aset temp (+ loc i) (+ num i))))
(append temp nil)))

(defun rubic-apply-transformation (state transform)
(let ((second (copy-sequence state)))
(loop for i from 0 to (1- (length second)) do
(aset state (nth i transform) (aref second i)))))

;; definitions of common transformations
(defconst rubic-U
rubic-turn-top-substitution)

(defconst rubic-U2
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-Ui
(rubic-substitute rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution))

(defconst rubic-F
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-F2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Fi
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-2)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-R
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-R2
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-Ri
(rubic-substitute (rubic-expand-substitution rubic-desc-rot-1-3)
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))))

(defconst rubic-L
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-L2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-Li
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-3)))

(defconst rubic-B
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-B2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-Bi
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution rubic-desc-rot-1-2)))

(defconst rubic-D
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-D2
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-Di
(rubic-substitute (rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))
rubic-turn-top-substitution
rubic-turn-top-substitution
rubic-turn-top-substitution
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2))))

(defconst rubic-x
(rubic-expand-substitution rubic-desc-rot-1-2))

(defconst rubic-x2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-xi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-2
rubic-desc-rot-1-2
rubic-desc-rot-1-2)))

(defconst rubic-y
(rubic-expand-substitution rubic-desc-rot-2-3))

(defconst rubic-y2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-yi
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-2-3
rubic-desc-rot-2-3
rubic-desc-rot-2-3)))

(defconst rubic-zi
(rubic-expand-substitution rubic-desc-rot-1-3))

(defconst rubic-z2
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

(defconst rubic-z
(rubic-expand-substitution
(rubic-rotate rubic-desc-rot-1-3
rubic-desc-rot-1-3
rubic-desc-rot-1-3)))

;; mode definitions
(defvar-local cube-state nil
"State of the cube that is being processed")

(defvar-local cube-undo (list 'undo)
"List of previously executed commands")

(defvar-local cube-redo (list 'redo)
"List of previously undone commands")

(defun rubic-center-string (str l)
(if (> (length str) l)
(substring str l)
(let* ((sl (length str))
(pad (/ (- l sl) 2))
(rem (- l pad)))
(concat (format (format "%%%ds" rem) str) (make-string pad ? )))))

(defun rubic-display-cube ()
"Draw current cube state, assuming empty buffer"
;; first, update canvasses according to the cube state
(rubic-paint-cube cube-state)
(let ((w (length (first rubic-cube-front-default)))
(h (length rubic-cube-front-default)))
(insert (format "%s%sn"
(rubic-center-string "*FRONT*" w)
(rubic-center-string "*BACK*" w)))
(insert-rectangle rubic-cube-front)
(forward-line (- (decf h)))
(move-end-of-line nil)
(insert-rectangle rubic-cube-back)))

(defun rubic-display-undo ()
"Print undo information"
(loop with line-str = "nUndo: "
for cmd in (reverse (cdr cube-undo))
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-display-redo ()
"Print undo information"
(loop with line-str = "nRedo: "
for cmd in (cdr cube-redo)
for i = 1 then (1+ i)
do (progn
(setq line-str (concat line-str (format "%d. %s " i (get cmd 'name))))
(when (> (length line-str) fill-column)
(insert line-str)
(setq line-str (concat "n" (make-string 6 ? )))))
finally (insert line-str)))

(defun rubic-draw-all ()
(setq buffer-read-only nil)
(erase-buffer)
(rubic-display-cube)
(rubic-display-undo)
(rubic-display-redo)
(setq buffer-read-only t))

(defmacro rubic-define-command (transformation desc)
(let ((command-name (intern (concat (symbol-name transformation) "-command"))))
(put command-name 'name desc)
`(defun ,command-name (&optional arg)
(interactive)
(rubic-apply-transformation cube-state ,transformation)
(unless arg
(setcdr cube-redo nil)
(setcdr cube-undo (cons (quote ,command-name) (cdr cube-undo)))
(rubic-draw-all)))))

(defmacro rubic-define-commands (&rest transformations)
(let ((head (car transformations))
(command-name (cadr transformations))
(tail (cddr transformations)))
`(progn
,(when head
`(rubic-define-command ,head ,command-name))
,(when tail
`(rubic-define-commands ,@tail)))))

(rubic-define-commands rubic-U "Upper" rubic-U2 "Upper twice" rubic-Ui "Upper inverted"
rubic-F "Front" rubic-F2 "Front twice" rubic-Fi "Front inverted"
rubic-R "Right" rubic-R2 "Right twice" rubic-Ri "Right inverted"
rubic-L "Left" rubic-L2 "Left twice" rubic-Li "Left inverted"
rubic-B "Back" rubic-B2 "Back twice" rubic-Bi "Back inverted"
rubic-D "Down" rubic-D2 "Down twice" rubic-Di "Down inverted"
rubic-x "X rotation" rubic-x2 "X overturn" rubic-xi "X rotation inverted"
rubic-y "Y rotation" rubic-y2 "Y overturn" rubic-yi "Y rotation inverted"
rubic-z "Z rotation" rubic-z2 "Z overturn" rubic-zi "Z rotation inverted")

(defconst rubic-reverse-commands
'((rubic-U-command . rubic-Ui-command)
(rubic-U2-command . rubic-U2-command)
(rubic-F-command . rubic-Fi-command)
(rubic-F2-command . rubic-F2-command)
(rubic-R-command . rubic-Ri-command)
(rubic-R2-command . rubic-R2-command)
(rubic-L-command . rubic-Li-command)
(rubic-L2-command . rubic-L2-command)
(rubic-B-command . rubic-Bi-command)
(rubic-B2-command . rubic-B2-command)
(rubic-D-command . rubic-Di-command)
(rubic-D2-command . rubic-D2-command)
(rubic-x-command . rubic-xi-command)
(rubic-x2-command . rubic-x2-command)
(rubic-y-command . rubic-yi-command)
(rubic-y2-command . rubic-y2-command)
(rubic-z-command . rubic-zi-command)
(rubic-z2-command . rubic-z2-command)))

(defun rubic-reset ()
"Set cube to initial state"
(interactive)
(setq cube-state (rubic-make-initial-cube))
(setq cube-undo (list 'undo))
(setq cube-redo (list 'redo))
(rubic-draw-all))

(defun rubic-undo (&optional arg)
"Undo up to ARG commands from undo list"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-undo)
when lastcmd do
(let ((revcmd (or (cdr (assoc lastcmd rubic-reverse-commands))
(car (rassoc lastcmd rubic-reverse-commands)))))
(setcdr cube-redo (cons lastcmd (cdr cube-redo)))
(setcdr cube-undo (cddr cube-undo))
(apply revcmd '(t))))
(rubic-draw-all)))

(defun rubic-redo (&optional arg)
"Redo up to ARG commands"
(interactive "p")
(let ((num (or arg 1)))
(loop repeat num
for lastcmd = (cadr cube-redo)
when lastcmd do
(progn
(setcdr cube-undo (cons lastcmd (cdr cube-undo)))
(setcdr cube-redo (cddr cube-redo))
(apply lastcmd '(t))))
(rubic-draw-all)))

(defvar rubic-mode-map
(let ((map (make-sparse-keymap))
(map-i (make-sparse-keymap))
(map-2 (make-sparse-keymap)))
(define-key map "u" 'rubic-U-command)
(define-key map-2 "u" 'rubic-U2-command)
(define-key map-i "u" 'rubic-Ui-command)
(define-key map "f" 'rubic-F-command)
(define-key map-2 "f" 'rubic-F2-command)
(define-key map-i "f" 'rubic-Fi-command)
(define-key map "r" 'rubic-R-command)
(define-key map-2 "r" 'rubic-R2-command)
(define-key map-i "r" 'rubic-Ri-command)
(define-key map "l" 'rubic-L-command)
(define-key map-2 "l" 'rubic-L2-command)
(define-key map-i "l" 'rubic-Li-command)
(define-key map "b" 'rubic-B-command)
(define-key map-2 "b" 'rubic-B2-command)
(define-key map-i "b" 'rubic-Bi-command)
(define-key map "d" 'rubic-D-command)
(define-key map-2 "d" 'rubic-D2-command)
(define-key map-i "d" 'rubic-Di-command)
(define-key map "x" 'rubic-x-command)
(define-key map-2 "x" 'rubic-x2-command)
(define-key map-i "x" 'rubic-xi-command)
(define-key map "y" 'rubic-y-command)
(define-key map-2 "y" 'rubic-y2-command)
(define-key map-i "y" 'rubic-yi-command)
(define-key map "z" 'rubic-z-command)
(define-key map-2 "z" 'rubic-z2-command)
(define-key map-i "z" 'rubic-zi-command)
(define-key map "g" 'rubic-reset)
(define-key map "2" map-2)
(define-key map "i" map-i)
(define-key map (kbd "M-u") 'rubic-undo)
(define-key map (kbd "M-r") 'rubic-redo)
map))

(define-derived-mode rubic-mode special-mode
"rubic's cube")

(add-hook 'rubic-mode-hook
(lambda ()
(rubic-reset)))

(defun rubic ()
"Prepare for rubic mode"
(interactive)
(switch-to-buffer "*Rubic*")
(rubic-mode))






game coordinate-system ascii-art elisp






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 16 hours ago









Toby Speight

23.8k639112




23.8k639112










asked Jan 11 '18 at 12:30









Srv19Srv19

23016




23016








  • 1




    $begingroup$
    rubik's cube.
    $endgroup$
    – internet_user
    Jan 11 '18 at 13:12








  • 1




    $begingroup$
    That's an embarassing failure on my part
    $endgroup$
    – Srv19
    Jan 11 '18 at 19:42














  • 1




    $begingroup$
    rubik's cube.
    $endgroup$
    – internet_user
    Jan 11 '18 at 13:12








  • 1




    $begingroup$
    That's an embarassing failure on my part
    $endgroup$
    – Srv19
    Jan 11 '18 at 19:42








1




1




$begingroup$
rubik's cube.
$endgroup$
– internet_user
Jan 11 '18 at 13:12






$begingroup$
rubik's cube.
$endgroup$
– internet_user
Jan 11 '18 at 13:12






1




1




$begingroup$
That's an embarassing failure on my part
$endgroup$
– Srv19
Jan 11 '18 at 19:42




$begingroup$
That's an embarassing failure on my part
$endgroup$
– Srv19
Jan 11 '18 at 19:42










0






active

oldest

votes











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184842%2frubiks-cube-mode-for-emacs%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























0






active

oldest

votes








0






active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f184842%2frubiks-cube-mode-for-emacs%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Сан-Квентин

Алькесар

Josef Freinademetz