Rubik's cube mode for emacs
$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))
game coordinate-system ascii-art elisp
$endgroup$
add a comment |
$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))
game coordinate-system ascii-art elisp
$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
add a comment |
$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))
game coordinate-system ascii-art elisp
$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
game coordinate-system ascii-art elisp
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
add a comment |
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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