aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Belaïche2011-05-23 11:46:41 -0300
committerStefan Monnier2011-05-23 11:46:41 -0300
commitb776bc70b7ef7d5fb88d4e66a75c9215fa2fb6a3 (patch)
tree746bd5907dccde01893e93fe35019cc190620f3b
parent7de88b6e91083d81c92bc70f311d94db8ae0f7e7 (diff)
downloademacs-b776bc70b7ef7d5fb88d4e66a75c9215fa2fb6a3.tar.gz
emacs-b776bc70b7ef7d5fb88d4e66a75c9215fa2fb6a3.zip
* lisp/play/5x5.el: I/ Add an arithmetic solver to suggest positions to
click on. II/ Make 5x5 multisession. III/ Ensure that random grids always have a solution in grid size = 5 cases. (5x5-mode-map): Add keybinding to function `5x5-solve-suggest'. (5x5-solver-output, 5x5-log-buffer): New vars. (5x5-grid, 5x5-x-pos, 5x5-y-pos, 5x5-moves, 5x5-cracking): Make these variables buffer local to achieve 5x5 multi-session-ness. (5x5): Set 5x5-grid-size only if SIZE is non-negative. (5x5-grid-to-vec, 5x5-vec-to-grid, 5x5-log-init, 5x5-log, 5x5-solver) (5x5-solve-suggest): New funs. (5x5-randomize): Use 5x5-make-move instead of 5x5-flip-cell to randomize a grid so that we ensure that there is always a solution. (5x5-make-random-grid): Allow other movement than flipping.
-rw-r--r--lisp/ChangeLog16
-rw-r--r--lisp/play/5x5.el391
2 files changed, 388 insertions, 19 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 95cae40aebe..7844240186e 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,19 @@
12011-05-23 Vincent Belaïche <vincentb1@users.sourceforge.net>
2
3 * play/5x5.el: I/ Add an arithmetic solver to suggest positions to
4 click on. II/ Make 5x5 multisession. III/ Ensure that random grids
5 always have a solution in grid size = 5 cases.
6 (5x5-mode-map): Add keybinding to function `5x5-solve-suggest'.
7 (5x5-solver-output, 5x5-log-buffer): New vars.
8 (5x5-grid, 5x5-x-pos, 5x5-y-pos, 5x5-moves, 5x5-cracking):
9 Make these variables buffer local to achieve 5x5 multi-session-ness.
10 (5x5): Set 5x5-grid-size only if SIZE is non-negative.
11 (5x5-grid-to-vec, 5x5-vec-to-grid, 5x5-log-init, 5x5-log, 5x5-solver)
12 (5x5-solve-suggest): New funs.
13 (5x5-randomize): Use 5x5-make-move instead of 5x5-flip-cell to
14 randomize a grid so that we ensure that there is always a solution.
15 (5x5-make-random-grid): Allow other movement than flipping.
16
12011-05-23 Kevin Ryde <user42@zip.com.au> 172011-05-23 Kevin Ryde <user42@zip.com.au>
2 18
3 * emacs-lisp/advice.el (ad-read-advised-function): 19 * emacs-lisp/advice.el (ad-read-advised-function):
diff --git a/lisp/play/5x5.el b/lisp/play/5x5.el
index 46c3c867304..a5f585d4d86 100644
--- a/lisp/play/5x5.el
+++ b/lisp/play/5x5.el
@@ -1,4 +1,4 @@
1;;; 5x5.el --- simple little puzzle game 1;;; 5x5.el --- simple little puzzle game -*- coding: utf-8 -*-
2 2
3;; Copyright (C) 1999-2011 Free Software Foundation, Inc. 3;; Copyright (C) 1999-2011 Free Software Foundation, Inc.
4 4
@@ -24,15 +24,15 @@
24 24
25;;; Commentary: 25;;; Commentary:
26 26
27;; The aim of 5x5 is to fill in all the squares. If you need any more of an 27;; The aim of 5x5 is to fill in all the squares. If you need any more of an
28;; explanation you probably shouldn't play the game. 28;; explanation you probably shouldn't play the game.
29 29
30;;; TODO: 30;;; TODO:
31 31
32;; o The code for updating the grid needs to be re-done. At the moment it 32;; o The code for updating the grid needs to be re-done. At the moment it
33;; simply re-draws the grid every time a move is made. 33;; simply re-draws the grid every time a move is made.
34;; 34;;
35;; o Look into tarting up the display with color. gamegrid.el looks 35;; o Look into tarting up the display with color. gamegrid.el looks
36;; interesting, perhaps that is the way to go? 36;; interesting, perhaps that is the way to go?
37 37
38;;; Thanks: 38;;; Thanks:
@@ -41,7 +41,10 @@
41;; emacs mode. 41;; emacs mode.
42;; 42;;
43;; Pascal Q. Porcupine <joshagam@cs.nmsu.edu> for inspiring the animated 43;; Pascal Q. Porcupine <joshagam@cs.nmsu.edu> for inspiring the animated
44;; solver. 44;; cracker.
45;;
46;; Vincent Belaïche <vincentb1@users.sourceforge.net> & Jay P. Belanger
47;; <jay.p.belanger@gmail.com> for the math solver.
45 48
46;;; Code: 49;;; Code:
47 50
@@ -89,19 +92,25 @@
89 92
90;; Non-customize variables. 93;; Non-customize variables.
91 94
92(defvar 5x5-grid nil 95(defmacro 5x5-defvar-local (var value doc)
96 "Define VAR to VALUE with documentation DOC and make it buffer local."
97 `(progn
98 (defvar ,var ,value ,doc)
99 (make-variable-buffer-local (quote ,var))))
100
101(5x5-defvar-local 5x5-grid nil
93 "5x5 grid contents.") 102 "5x5 grid contents.")
94 103
95(defvar 5x5-x-pos 2 104(5x5-defvar-local 5x5-x-pos 2
96 "X position of cursor.") 105 "X position of cursor.")
97 106
98(defvar 5x5-y-pos 2 107(5x5-defvar-local 5x5-y-pos 2
99 "Y position of cursor.") 108 "Y position of cursor.")
100 109
101(defvar 5x5-moves 0 110(5x5-defvar-local 5x5-moves 0
102 "Moves made.") 111 "Moves made.")
103 112
104(defvar 5x5-cracking nil 113(5x5-defvar-local 5x5-cracking nil
105 "Are we in cracking mode?") 114 "Are we in cracking mode?")
106 115
107(defvar 5x5-buffer-name "*5x5*" 116(defvar 5x5-buffer-name "*5x5*"
@@ -134,10 +143,28 @@
134 (define-key map [(control c) (control b)] #'5x5-crack-mutating-best) 143 (define-key map [(control c) (control b)] #'5x5-crack-mutating-best)
135 (define-key map [(control c) (control x)] #'5x5-crack-xor-mutate) 144 (define-key map [(control c) (control x)] #'5x5-crack-xor-mutate)
136 (define-key map "n" #'5x5-new-game) 145 (define-key map "n" #'5x5-new-game)
146 (define-key map "s" #'5x5-solve-suggest)
137 (define-key map "q" #'5x5-quit-game) 147 (define-key map "q" #'5x5-quit-game)
138 map) 148 map)
139 "Local keymap for the 5x5 game.") 149 "Local keymap for the 5x5 game.")
140 150
151(5x5-defvar-local 5x5-solver-output nil
152 "List that is is the output of artihmetic solver.
153
154This list L is such that
155
156L = (M S_1 S_2 ... S_N)
157
158M is the move count when the solve output was stored.
159
160S_1 ... S_N are all the solutions ordered from least to greatest
161number of strokes. S_1 is the solution to be displayed.
162
163Each solution S_1, ..., S_N is a a list (STROKE-COUNT GRID) where
164STROKE-COUNT is to number of strokes to achieve the solution and
165GRID is the grid of positions to click.")
166
167
141;; Menu definition. 168;; Menu definition.
142 169
143(easy-menu-define 5x5-mode-menu 5x5-mode-map "5x5 menu." 170(easy-menu-define 5x5-mode-menu 5x5-mode-map "5x5 menu."
@@ -146,6 +173,7 @@
146 ["Random game" 5x5-randomize t] 173 ["Random game" 5x5-randomize t]
147 ["Quit game" 5x5-quit-game t] 174 ["Quit game" 5x5-quit-game t]
148 "---" 175 "---"
176 ["Use Calc solver" 5x5-solve-suggest t]
149 ["Crack randomly" 5x5-crack-randomly t] 177 ["Crack randomly" 5x5-crack-randomly t]
150 ["Crack mutating current" 5x5-crack-mutating-current t] 178 ["Crack mutating current" 5x5-crack-mutating-current t]
151 ["Crack mutating best" 5x5-crack-mutating-best t] 179 ["Crack mutating best" 5x5-crack-mutating-best t]
@@ -158,7 +186,7 @@
158(defun 5x5-mode () 186(defun 5x5-mode ()
159 "A mode for playing `5x5'. 187 "A mode for playing `5x5'.
160 188
161The key bindings for 5x5-mode are: 189The key bindings for `5x5-mode' are:
162 190
163\\{5x5-mode-map}" 191\\{5x5-mode-map}"
164 (kill-all-local-variables) 192 (kill-all-local-variables)
@@ -194,14 +222,14 @@ Quit current game \\[5x5-quit-game]"
194 222
195 (interactive "P") 223 (interactive "P")
196 (setq 5x5-cracking nil) 224 (setq 5x5-cracking nil)
197 (when size
198 (setq 5x5-grid-size size))
199 (switch-to-buffer 5x5-buffer-name) 225 (switch-to-buffer 5x5-buffer-name)
226 (5x5-mode)
227 (when (natnump size)
228 (setq 5x5-grid-size size))
200 (if (or (not 5x5-grid) (not (= 5x5-grid-size (length (aref 5x5-grid 0))))) 229 (if (or (not 5x5-grid) (not (= 5x5-grid-size (length (aref 5x5-grid 0)))))
201 (5x5-new-game)) 230 (5x5-new-game))
202 (5x5-draw-grid (list 5x5-grid)) 231 (5x5-draw-grid (list 5x5-grid))
203 (5x5-position-cursor) 232 (5x5-position-cursor))
204 (5x5-mode))
205 233
206(defun 5x5-new-game () 234(defun 5x5-new-game ()
207 "Start a new game of `5x5'." 235 "Start a new game of `5x5'."
@@ -277,10 +305,11 @@ Quit current game \\[5x5-quit-game]"
277 305
278(defun 5x5-draw-grid (grids) 306(defun 5x5-draw-grid (grids)
279 "Draw the grids GRIDS into the current buffer." 307 "Draw the grids GRIDS into the current buffer."
280 (let ((buffer-read-only nil)) 308 (let ((inhibit-read-only t) grid-org)
281 (erase-buffer) 309 (erase-buffer)
282 (loop for grid in grids do (5x5-draw-grid-end)) 310 (loop for grid in grids do (5x5-draw-grid-end))
283 (insert "\n") 311 (insert "\n")
312 (setq grid-org (point))
284 (loop for y from 0 to (1- 5x5-grid-size) do 313 (loop for y from 0 to (1- 5x5-grid-size) do
285 (loop for lines from 0 to (1- 5x5-y-scale) do 314 (loop for lines from 0 to (1- 5x5-y-scale) do
286 (loop for grid in grids do 315 (loop for grid in grids do
@@ -290,6 +319,23 @@ Quit current game \\[5x5-quit-game]"
290 (if (5x5-cell grid y x) ?# ?.)))) 319 (if (5x5-cell grid y x) ?# ?.))))
291 (insert " | ")) 320 (insert " | "))
292 (insert "\n"))) 321 (insert "\n")))
322 (when 5x5-solver-output
323 (if (= (car 5x5-solver-output) 5x5-moves)
324 (save-excursion
325 (goto-char grid-org)
326 (beginning-of-line (+ 1 (/ 5x5-y-scale 2)))
327 (let ((solution-grid (cdadr 5x5-solver-output)))
328 (dotimes (y 5x5-grid-size)
329 (save-excursion
330 (forward-char (+ 1 (/ (1+ 5x5-x-scale) 2)))
331 (dotimes (x 5x5-grid-size)
332 (when (5x5-cell solution-grid y x)
333 (insert-char ?O 1)
334 (delete-char 1)
335 (backward-char))
336 (forward-char (1+ 5x5-x-scale))))
337 (forward-line 5x5-y-scale))))
338 (setq 5x5-solver-output nil)))
293 (loop for grid in grids do (5x5-draw-grid-end)) 339 (loop for grid in grids do (5x5-draw-grid-end))
294 (insert "\n") 340 (insert "\n")
295 (insert (format "On: %d Moves: %d" (5x5-grid-value (car grids)) 5x5-moves)))) 341 (insert (format "On: %d Moves: %d" (5x5-grid-value (car grids)) 5x5-moves))))
@@ -304,13 +350,14 @@ Quit current game \\[5x5-quit-game]"
304 "Keep track of how many moves have been made." 350 "Keep track of how many moves have been made."
305 (incf 5x5-moves)) 351 (incf 5x5-moves))
306 352
307(defun 5x5-make-random-grid () 353(defun 5x5-make-random-grid (&optional move)
308 "Make a random grid." 354 "Make a random grid."
355 (setq move (or move (symbol-function '5x5-flip-cell)))
309 (let ((grid (5x5-make-new-grid))) 356 (let ((grid (5x5-make-new-grid)))
310 (loop for y from 0 to (1- 5x5-grid-size) do 357 (loop for y from 0 to (1- 5x5-grid-size) do
311 (loop for x from 0 to (1- 5x5-grid-size) do 358 (loop for x from 0 to (1- 5x5-grid-size) do
312 (if (zerop (random 2)) 359 (if (zerop (random 2))
313 (5x5-flip-cell grid y x)))) 360 (funcall move grid y x))))
314 grid)) 361 grid))
315 362
316;; Cracker functions. 363;; Cracker functions.
@@ -415,6 +462,312 @@ in progress because it is an animated attempt."
415 (sit-for 5x5-animate-delay)))) 462 (sit-for 5x5-animate-delay))))
416 5x5-grid) 463 5x5-grid)
417 464
465;; Arithmetic solver
466;;===========================================================================
467(defun 5x5-grid-to-vec (grid)
468 "Convert GRID to an equivalent Calc matrix of (mod X 2) forms
469where X is 1 for setting a position, and 0 for unsetting a
470position."
471 (cons 'vec
472 (mapcar (lambda (y)
473 (cons 'vec
474 (mapcar (lambda (x)
475 (if x '(mod 1 2) '(mod 0 2)))
476 y)))
477 grid)))
478
479(defun 5x5-vec-to-grid (grid-matrix)
480 "Convert a grid matrix GRID-MATRIX in Calc format to a grid in
4815x5 format. See function `5x5-grid-to-vec'."
482 (apply
483 'vector
484 (mapcar
485 (lambda (x)
486 (apply
487 'vector
488 (mapcar
489 (lambda (y) (/= (cadr y) 0))
490 (cdr x))))
491 (cdr grid-matrix))))
492
493(if nil; set to t to enable solver logging
494 (progn
495 (defvar 5x5-log-buffer nil)
496 (defun 5x5-log-init ()
497 (if (buffer-live-p 5x5-log-buffer)
498 (with-current-buffer 5x5-log-buffer (erase-buffer))
499 (setq 5x5-log-buffer (get-buffer-create "*5x5 LOG*"))))
500
501 (defun 5x5-log (name value)
502 "Debug purpuse only.
503
504Log a matrix VALUE of (mod B 2) forms, only B is output and
505Scilab matrix notation is used. VALUE is returned so that it is
506easy to log a value with minimal rewrite of code."
507 (when (buffer-live-p 5x5-log-buffer)
508 (let* ((unpacked-value
509 (math-map-vec
510 (lambda (row) (math-map-vec 'cadr row))
511 value))
512 (calc-vector-commas "")
513 (calc-matrix-brackets '(C O))
514 (value-to-log (math-format-value unpacked-value)))
515 (with-current-buffer 5x5-log-buffer
516 (insert name ?= value-to-log ?\n))))
517 value))
518 (defmacro 5x5-log-init ())
519 (defmacro 5x5-log (name value) value))
520
521(defun 5x5-solver (grid)
522 "Return a list of solutions for GRID.
523
524Given some grid GRID, the returned a list of solution LIST is
525sorted from least Hamming weight to geatest one.
526
527 LIST = (SOLUTION-1 ... SOLUTION-N)
528
529Each solution SOLUTION-I is a cons cell (HW . G) where HW is the
530Hamming weight of the solution --- ie the number of strokes to
531achieves it --- and G is the grid of positions to click in order
532to complete the 5x5.
533
534Solutions are sorted from least to greatest Hamming weight."
535 (require 'calc-ext)
536 (flet ((5x5-mat-mode-2
537 (a)
538 (math-map-vec
539 (lambda (y)
540 (math-map-vec
541 (lambda (x) `(mod ,x 2))
542 y))
543 a)))
544 (let* (calc-command-flags
545 (grid-size-squared (* 5x5-grid-size 5x5-grid-size))
546
547 ;; targetv is the vector the origine of which is org="current
548 ;; grid" and the end of which is dest="all ones".
549 (targetv
550 (5x5-log
551 "b"
552 (let (
553 ;; org point is the current grid
554 (org (calcFunc-arrange (5x5-grid-to-vec grid)
555 1))
556
557 ;; end point of game is the all ones matrix
558 (dest (calcFunc-cvec '(mod 1 2) grid-size-squared 1)))
559 (math-sub dest org))))
560
561 ;; transferm is the transfer matrix, ie it is the 25x25
562 ;; matrix applied everytime a flip is carried out where a
563 ;; flip is defined by a 25x1 Dirac vector --- ie all zeros
564 ;; but 1 in the position that is flipped.
565 (transferm
566 (5x5-log
567 "a"
568 ;; transfer-grid is not a play grid, but this is the
569 ;; transfer matrix in the format of a vector of vectors, we
570 ;; do it this way because random access in vectors is
571 ;; faster. The motivation is just speed as we build it
572 ;; element by element, but that could have been created
573 ;; using only Calc primitives. Probably that would be a
574 ;; better idea to use Calc with some vector manipulation
575 ;; rather than going this way...
576 (5x5-grid-to-vec (let ((transfer-grid
577 (let ((5x5-grid-size grid-size-squared))
578 (5x5-make-new-grid))))
579 (dotimes (i 5x5-grid-size)
580 (dotimes (j 5x5-grid-size)
581 ;; k0 = flattened flip position corresponding
582 ;; to (i, j) on the grid.
583 (let* ((k0 (+ (* 5 i) j)))
584 ;; cross center
585 (5x5-set-cell transfer-grid k0 k0 t)
586 ;; Cross top.
587 (and
588 (> i 0)
589 (5x5-set-cell transfer-grid
590 (- k0 5x5-grid-size) k0 t))
591 ;; Cross bottom.
592 (and
593 (< (1+ i) 5x5-grid-size)
594 (5x5-set-cell transfer-grid
595 (+ k0 5x5-grid-size) k0 t))
596 ;; Cross left.
597 (and
598 (> j 0)
599 (5x5-set-cell transfer-grid (1- k0) k0 t))
600 ;; Cross right.
601 (and
602 (< (1+ j) 5x5-grid-size)
603 (5x5-set-cell transfer-grid
604 (1+ k0) k0 t)))))
605 transfer-grid))))
606 ;; TODO: this is hard-coded for grid-size = 5, make it generic.
607 (transferm-kernel-size
608 (if (= 5x5-grid-size 5) 2
609 (error "Transfer matrix rank not known for grid-size != 5")))
610
611 ;; TODO: this is hard-coded for grid-size = 5, make it generic.
612 ;;
613 ;; base-change is a 25x25 matrix, where topleft submatrix
614 ;; 23x25 is a diagonal of 1, and the two last columns are a
615 ;; base of kernel of transferm.
616 ;;
617 ;; base-change must be by construction inversible.
618 (base-change
619 (5x5-log
620 "p"
621 (let ((id (5x5-mat-mode-2 (calcFunc-diag 1 grid-size-squared))))
622 (setcdr (last id (1+ transferm-kernel-size))
623 (cdr (5x5-mat-mode-2
624 '(vec (vec 0 1 1 1 0 1 0 1 0 1 1 1 0 1
625 1 1 0 1 0 1 0 1 1 1 0)
626 (vec 1 1 0 1 1 0 0 0 0 0 1 1 0 1
627 1 0 0 0 0 0 1 1 0 1 1)))))
628 (calcFunc-trn id))))
629
630 (inv-base-change
631 (5x5-log "invp"
632 (calcFunc-inv base-change)))
633
634 ;; B:= targetv
635 ;; A:= transferm
636 ;; P:= base-change
637 ;; P^-1 := inv-base-change
638 ;; X := solution
639
640 ;; B = A * X
641 ;; P^-1 * B = P^-1 * A * P * P^-1 * X
642 ;; CX = P^-1 * X
643 ;; CA = P^-1 * A * P
644 ;; CB = P^-1 * B
645 ;; CB = CA * CX
646 ;; CX = CA^-1 * CB
647 ;; X = P * CX
648 (ctransferm
649 (5x5-log
650 "ca"
651 (math-mul
652 inv-base-change
653 (math-mul transferm base-change)))); CA
654 (ctarget
655 (5x5-log
656 "cb"
657 (math-mul inv-base-change targetv))); CB
658 (row-1 (math-make-intv 3 1 transferm-kernel-size)) ; 1..2
659 (row-2 (math-make-intv 1 transferm-kernel-size
660 grid-size-squared)); 3..25
661 (col-1 (math-make-intv 3 1 (- grid-size-squared
662 transferm-kernel-size))); 1..23
663 (col-2 (math-make-intv 1 (- grid-size-squared
664 transferm-kernel-size)
665 grid-size-squared)); 24..25
666 (ctransferm-1-: (calcFunc-mrow ctransferm row-1))
667 (ctransferm-1-1 (calcFunc-mcol ctransferm-1-: col-1))
668
669 ;; By construction ctransferm-:-2 = 0, so ctransferm-1-2 = 0
670 ;; and ctransferm-2-2 = 0.
671
672 ;;(ctransferm-1-2 (calcFunc-mcol ctransferm-1-: col-2))
673 (ctransferm-2-: (calcFunc-mrow ctransferm row-2))
674 (ctransferm-2-1
675 (5x5-log
676 "ca_2_1"
677 (calcFunc-mcol ctransferm-2-: col-1)))
678
679 ;; By construction ctransferm-2-2 = 0.
680 ;;
681 ;;(ctransferm-2-2 (calcFunc-mcol ctransferm-2-: col-2))
682
683 (ctarget-1 (calcFunc-mrow ctarget row-1))
684 (ctarget-2 (calcFunc-mrow ctarget row-2))
685
686 ;; ctarget-1(2x1) = ctransferm-1-1(2x23) *cx-1(23x1)
687 ;; + ctransferm-1-2(2x2) *cx-2(2x1);
688 ;; ctarget-2(23x1) = ctransferm-2-1(23x23)*cx-1(23x1)
689 ;; + ctransferm-2-2(23x2)*cx-2(2x1);
690 ;; By construction:
691 ;;
692 ;; ctransferm-1-2 == zeros(2,2) and ctransferm-2-2 == zeros(23,2)
693 ;;
694 ;; So:
695 ;;
696 ;; ctarget-2 = ctransferm-2-1*cx-1
697 ;;
698 ;; So:
699 ;;
700 ;; cx-1 = inv-ctransferm-2-1 * ctarget-2
701 (cx-1 (math-mul (calcFunc-inv ctransferm-2-1) ctarget-2))
702
703 ;; Any cx-2 can do, so there are 2^{transferm-kernel-size} solutions.
704 (solution-list
705 ;; Within solution-list each element is a cons cell:
706 ;;
707 ;; (HW . SOL)
708 ;;
709 ;; where HW is the Hamming weight of solution, and SOL is
710 ;; the solution in the form of a grid.
711 (sort
712 (cdr
713 (math-map-vec
714 (lambda (cx-2)
715 ;; Compute `solution' in the form of a 25x1 matrix of
716 ;; (mod B 2) forms --- with B = 0 or 1 --- and
717 ;; return (HW . SOL) where HW is the Hamming weight
718 ;; of solution and SOL a grid.
719 (let ((solution (math-mul
720 base-change
721 (calcFunc-vconcat cx-1 cx-2)))); X = P * CX
722 (cons
723 ;; The Hamming Weight is computed by matrix reduction
724 ;; with an ad-hoc operator.
725 (math-reduce-vec
726 ;; (cadadr '(vec (mod x 2))) => x
727 (lambda (r x) (+ (if (integerp r) r (cadadr r))
728 (cadadr x)))
729 solution); car
730 (5x5-vec-to-grid
731 (calcFunc-arrange solution 5x5-grid-size));cdr
732 )))
733 ;; A (2^K) x K matrix, where K is the dimension of kernel
734 ;; of transfer matrix --- i.e. K=2 in if the grid is 5x5
735 ;; --- for I from 0 to K-1, each row rI correspond to the
736 ;; binary representation of number I, that is to say row
737 ;; rI is a 1xK vector:
738 ;; [ n{I,0} n{I,1} ... n{I,K-1} ]
739 ;; such that:
740 ;; I = sum for J=0..K-1 of 2^(n{I,J})
741 (let ((calc-number-radix 2)
742 (calc-leading-zeros t)
743 (calc-word-size transferm-kernel-size))
744 (math-map-vec
745 (lambda (x)
746 (cons 'vec
747 (mapcar (lambda (x) `(vec (mod ,(logand x 1) 2)))
748 (substring (math-format-number x)
749 (- transferm-kernel-size)))))
750 (calcFunc-index (math-pow 2 transferm-kernel-size) 0))) ))
751 ;; Sort solutions according to respective Hamming weight.
752 (lambda (x y) (< (car x) (car y)))
753 )))
754 (message "5x5 Solution computation done.")
755 solution-list)))
756
757(defun 5x5-solve-suggest (&optional n)
758 "Suggest to the user where to click.
759
760Argument N is ignored."
761 ;; For the time being n is ignored, the idea was to use some numeric
762 ;; argument to show a limited amount of positions.
763 (interactive "P")
764 (5x5-log-init)
765 (let ((solutions (5x5-solver 5x5-grid)))
766 (setq 5x5-solver-output
767 (cons 5x5-moves solutions)))
768 (5x5-draw-grid (list 5x5-grid))
769 (5x5-position-cursor))
770
418;; Keyboard response functions. 771;; Keyboard response functions.
419 772
420(defun 5x5-flip-current () 773(defun 5x5-flip-current ()
@@ -490,7 +843,7 @@ in progress because it is an animated attempt."
490 (setq 5x5-x-pos (/ 5x5-grid-size 2) 843 (setq 5x5-x-pos (/ 5x5-grid-size 2)
491 5x5-y-pos (/ 5x5-grid-size 2) 844 5x5-y-pos (/ 5x5-grid-size 2)
492 5x5-moves 0 845 5x5-moves 0
493 5x5-grid (5x5-make-random-grid)) 846 5x5-grid (5x5-make-random-grid (symbol-function '5x5-make-move)))
494 (unless 5x5-cracking 847 (unless 5x5-cracking
495 (5x5-draw-grid (list 5x5-grid))) 848 (5x5-draw-grid (list 5x5-grid)))
496 (5x5-position-cursor))) 849 (5x5-position-cursor)))