;;; Major mode for solving sudoku puzzles. ;;; Waider , August 2005 ;;; since google turned up no matches... ;;; ;;; Draw out your sudoku puzzle using |, + and - as box characters, ;;; then M-x sudoku-mode. This will currently just stop you from ;;; making obvious mistakes, i.e. violating the "one digit per ;;; horiz/vert/box" rule. It automatically adapts to the correct set ;;; of allowable 'digits' based on the size of the grid, up to a ;;; maximum of 6x6. At some point I may add more such as hints and ;;; solving, and possibly puzzle generation for the truly bored. (defvar sudoku-map () "Keymap for Sudoku") (if sudoku-map nil (setq sudoku-map (make-sparse-keymap)) (substitute-key-definition 'self-insert-command 'sudoku-insert sudoku-map global-map) (substitute-key-definition 'delete-backward-char 'sudoku-blank sudoku-map global-map)) (defun sudoku-check-valid(location char) "check that it is okay to insert CHAR at LOCATION" (save-excursion (goto-char location) (let ((col (current-column)) (size 0)) (goto-char (point-min)) ;; check vertical (while (not (eobp)) (move-to-column col t) (if (= char (char-after)) (progn (message "Cannot insert %c here" char) (sit-for 2) (error "Cannot insert %c here" char) )) (forward-line)) ;; check horizontal (goto-char location) (beginning-of-line) (while (not (eolp)) (if (= char (char-after)) (progn (message "Cannot insert %c here" char) (sit-for 2) (error "Cannot insert %c here" char))) (forward-char)) ;; check box: ;; first, find the top-left corner. This assumes you've boxed ;; your sudoku with | and -. (goto-char location) (search-backward "|") (forward-char) (setq col (current-column)) (while (not (= (char-after) ?-)) (forward-line -1) (move-to-column col t)) (forward-line 1) (move-to-column col t) ;; now check each row (while (not (= (char-after) ?-)) (setq size (+ size 1)) ;; and column (while (not (= (char-after) ?|)) (if (= char (char-after)) (progn (message "Cannot insert %c here" char) (sit-for 2) (error "Cannot insert %c here" char))) (forward-char 1)) (forward-line 1) (move-to-column col t)) (if (> size 6) (error "Can't handle a sudoku this big")) (let ((range (substring (if (= size 3) "123456789" "0123456789ABCDEFGHIJKLNOPQRSTUVWXYZ" ) 0 (* size size)))) (if (string-match (format "%c" char) range) () (error "Invalid char")))))) (defun sudoku-insert(n) "self-insert-char N times at location. The N is overkill." (interactive "p") ;; to satisfy the interface... (let ((char last-input-char)) (if (looking-at "[-+|]") (error "can't insert on the border")) (if (= char ? ) () (if (not (= (char-after) ? )) (error "can't insert here")) (setq char (upcase char)) (sudoku-check-valid (point) char)) (delete-char 1) (insert char))) (defun sudoku-blank(n) "replacement for delete-backward-char" (interactive "p") (backward-char 1) ;; fixme: repeat n times? (if (looking-at "[-+|]") (error "can't delete the border")) (delete-char 1) (insert " ") (backward-char 1)) (defun sudoku-mode() "Major mode for playing sudoku" (interactive) (kill-all-local-variables) (use-local-map sudoku-map) (setq major-mode 'sudoku-mode) (setq mode-name "Sudoku"))