16
\$\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%s\n"
                    (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))
\$\endgroup\$
  • 2
    \$\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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.