25143
|
1 ;;; 5x5.el -- Simple little puzzle game.
|
|
2
|
|
3 ;; Copyright (C) 1999 Free Software Foundationm, Inc.
|
|
4
|
|
5 ;; Author: Dave Pearson <davep@hagbard.demon.co.uk>
|
|
6 ;; Maintainer: Dave Pearson <davep@hagbard.demon.co.uk>
|
|
7 ;; Created: 1998-10-03
|
|
8 ;; Version: $Revision: 1.15 $
|
|
9 ;; Keywords: games puzzles
|
|
10
|
|
11 ;; This file is part of GNU Emacs.
|
|
12
|
|
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
|
|
14 ;; it under the terms of the GNU General Public License as published by
|
|
15 ;; the Free Software Foundation; either version 2, or (at your option)
|
|
16 ;; any later version.
|
|
17
|
|
18 ;; GNU Emacs is distributed in the hope that it will be useful,
|
|
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
21 ;; GNU General Public License for more details.
|
|
22
|
|
23 ;; You should have received a copy of the GNU General Public License
|
|
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
|
|
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
26 ;; Boston, MA 02111-1307, USA.
|
|
27
|
|
28 ;;; Commentary:
|
|
29
|
|
30 ;; The aim of 5x5 is to fill in all the squares. If you need any more of an
|
|
31 ;; explanation you probably shouldn't play the game.
|
|
32
|
|
33 ;;; TODO:
|
|
34
|
|
35 ;; o The code for updating the grid needs to be re-done. At the moment it
|
|
36 ;; simply re-draws the grid every time a move is made.
|
|
37 ;;
|
|
38 ;; o Look into starting up the display with colour. gamegrid.el looks
|
|
39 ;; interesting, perhaps that is the way to go?
|
|
40
|
|
41 ;;; Thanks:
|
|
42
|
|
43 ;; Ralf Fassel <ralf@akutech.de> for his help and introduction to writing an
|
|
44 ;; emacs mode.
|
|
45 ;;
|
|
46 ;; Pascal Q. Porcupine <joshagam@cs.nmsu.edu> for inspiring the animated
|
|
47 ;; solver.
|
|
48
|
|
49 ;; Things we need.
|
|
50
|
|
51 (eval-when-compile
|
|
52 (require 'cl))
|
|
53
|
|
54 ;; If customize isn't available just use defvar instead.
|
|
55 (eval-and-compile
|
|
56 (unless (fboundp 'defgroup)
|
|
57 (defmacro defgroup (&rest rest) nil)
|
|
58 (defmacro defcustom (symbol init docstring &rest rest)
|
|
59 `(defvar ,symbol ,init ,docstring))))
|
|
60
|
|
61 ;; Customize options.
|
|
62
|
|
63 (defgroup 5x5 nil
|
|
64 "5x5 - Silly little puzzle game."
|
|
65 :group 'games
|
|
66 :prefix "5x5-")
|
|
67
|
|
68 (defcustom 5x5-grid-size 5
|
|
69 "*Size of the playing area."
|
|
70 :type 'integer
|
|
71 :group '5x5)
|
|
72
|
|
73 (defcustom 5x5-x-scale 4
|
|
74 "*X scaling factor for drawing the grid."
|
|
75 :type 'integer
|
|
76 :group '5x5)
|
|
77
|
|
78 (defcustom 5x5-y-scale 3
|
|
79 "*Y scaling factor for drawing the grid."
|
|
80 :type 'integer
|
|
81 :group '5x5)
|
|
82
|
|
83 (defcustom 5x5-animate-delay .01
|
|
84 "*Delay in seconds when animating a solution crack."
|
|
85 :type 'number
|
|
86 :group '5x5)
|
|
87
|
|
88 (defcustom 5x5-hassle-me t
|
|
89 "*Should 5x5 ask you when you want to do a destructive operation?"
|
|
90 :type 'boolean
|
|
91 :group '5x5)
|
|
92
|
|
93 (defcustom 5x5-mode-hook nil
|
|
94 "*Hook run on starting 5x5."
|
|
95 :type 'hook
|
|
96 :group '5x5)
|
|
97
|
|
98 ;; Non-customize variables.
|
|
99
|
|
100 (defvar 5x5-grid nil
|
|
101 "5x5 grid contents.")
|
|
102
|
|
103 (defvar 5x5-x-pos 2
|
|
104 "X position of cursor.")
|
|
105
|
|
106 (defvar 5x5-y-pos 2
|
|
107 "Y position of cursor.")
|
|
108
|
|
109 (defvar 5x5-moves 0
|
|
110 "Moves made.")
|
|
111
|
|
112 (defvar 5x5-cracking nil
|
|
113 "Are we in cracking mode?")
|
|
114
|
|
115 (defvar 5x5-buffer-name "*5x5*"
|
|
116 "Name of the 5x5 play buffer.")
|
|
117
|
|
118 (defvar 5x5-mode-map nil
|
|
119 "Local keymap for the 5x5 game.")
|
|
120
|
|
121 ;; Keymap.
|
|
122
|
|
123 (unless 5x5-mode-map
|
|
124 (let ((map (make-sparse-keymap)))
|
|
125 (suppress-keymap map t)
|
|
126 (define-key map "?" #'describe-mode)
|
|
127 (define-key map "\r" #'5x5-flip-current)
|
|
128 (define-key map " " #'5x5-flip-current)
|
|
129 (define-key map [up] #'5x5-up)
|
|
130 (define-key map [down] #'5x5-down)
|
|
131 (define-key map [left] #'5x5-left)
|
|
132 (define-key map [tab] #'5x5-right)
|
|
133 (define-key map [right] #'5x5-right)
|
|
134 (define-key map [(control a)] #'5x5-bol)
|
|
135 (define-key map [(control e)] #'5x5-eol)
|
|
136 (define-key map [home] #'5x5-bol)
|
|
137 (define-key map [end] #'5x5-eol)
|
|
138 (define-key map [prior] #'5x5-first)
|
|
139 (define-key map [next] #'5x5-last)
|
|
140 (define-key map "r" #'5x5-randomize)
|
|
141 (define-key map [(control c) (control r)] #'5x5-crack-randomly)
|
|
142 (define-key map [(control c) (control c)] #'5x5-crack-mutating-current)
|
|
143 (define-key map [(control c) (control b)] #'5x5-crack-mutating-best)
|
|
144 (define-key map [(control c) (control x)] #'5x5-crack-xor-mutate)
|
|
145 (define-key map "n" #'5x5-new-game)
|
|
146 (define-key map "q" #'5x5-quit-game)
|
|
147 (setq 5x5-mode-map map)))
|
|
148
|
|
149 ;; Menu definition.
|
|
150
|
|
151 (easy-menu-define 5x5-mode-menu 5x5-mode-map "5x5 menu."
|
|
152 '("5x5"
|
|
153 ["New game" 5x5-new-game t]
|
|
154 ["Random game" 5x5-randomize t]
|
|
155 ["Quit game" 5x5-quit-game t]
|
|
156 "---"
|
|
157 ["Crack randomly" 5x5-crack-randomly t]
|
|
158 ["Crack mutating current" 5x5-crack-mutating-current t]
|
|
159 ["Crack mutating best" 5x5-crack-mutating-best t]
|
|
160 ["Crack with xor mutate" 5x5-crack-xor-mutate t]))
|
|
161
|
|
162 ;; Gameplay functions.
|
|
163
|
|
164 (put '5x5-mode 'mode-class 'special)
|
|
165
|
|
166 (defun 5x5-mode ()
|
|
167 "A mode for playing `5x5'
|
|
168
|
|
169 The key bindings for 5x5-mode are:
|
|
170
|
|
171 \\{5x5-mode-map}"
|
|
172 (kill-all-local-variables)
|
|
173 (use-local-map 5x5-mode-map)
|
|
174 (setq major-mode '5x5-mode
|
|
175 mode-name "5x5")
|
|
176 (run-hooks '5x5-mode-hook)
|
|
177 (setq buffer-read-only t
|
|
178 truncate-lines t)
|
|
179 (buffer-disable-undo (current-buffer)))
|
|
180
|
|
181 ;;;###autoload
|
|
182 (defun 5x5 (&optional size)
|
|
183 "Play 5x5.
|
|
184
|
|
185 The object of 5x5 is very simple, by moving around the grid and flipping
|
|
186 squares you must fill the grid.
|
|
187
|
|
188 5x5 keyboard bindings are:
|
|
189 \\<5x5-mode-map>
|
|
190 Flip \\[5x5-flip-current]
|
|
191 Move up \\[5x5-up]
|
|
192 Move down \\[5x5-down]
|
|
193 Move left \\[5x5-left]
|
|
194 Move right \\[5x5-right]
|
|
195 Start new game \\[5x5-new-game]
|
|
196 New game with random grid \\[5x5-randomize]
|
|
197 Random cracker \\[5x5-crack-randomly]
|
|
198 Mutate current cracker \\[5x5-crack-mutating-current]
|
|
199 Mutaue best cracker \\[5x5-crack-mutating-best]
|
|
200 Mutate xor cracker \\[5x5-crack-xor-mutate]
|
|
201 Quit current game \\[5x5-quit-game]"
|
|
202
|
|
203 (interactive "P")
|
|
204 (setq 5x5-cracking nil)
|
|
205 (when size
|
|
206 (setq 5x5-grid-size size))
|
|
207 (switch-to-buffer 5x5-buffer-name)
|
|
208 (if (or (not 5x5-grid) (not (= 5x5-grid-size (length (aref 5x5-grid 0)))))
|
|
209 (5x5-new-game))
|
|
210 (5x5-draw-grid (list 5x5-grid))
|
|
211 (5x5-position-cursor)
|
|
212 (5x5-mode))
|
|
213
|
|
214 (defun 5x5-new-game ()
|
|
215 "Start a new game of `5x5'."
|
|
216 (interactive)
|
|
217 (when (if (interactive-p) (5x5-y-or-n-p "Start a new game? ") t)
|
|
218 (setq 5x5-x-pos (/ 5x5-grid-size 2)
|
|
219 5x5-y-pos (/ 5x5-grid-size 2)
|
|
220 5x5-moves 0
|
|
221 5x5-grid (5x5-make-move (5x5-make-new-grid) 5x5-y-pos 5x5-x-pos))
|
|
222 (when (interactive-p)
|
|
223 (5x5-draw-grid (list 5x5-grid))
|
|
224 (5x5-position-cursor))))
|
|
225
|
|
226 (defun 5x5-quit-game ()
|
|
227 "Quit the current game of `5x5'."
|
|
228 (interactive)
|
|
229 (kill-buffer 5x5-buffer-name))
|
|
230
|
|
231 (defun 5x5-make-new-grid ()
|
|
232 "Create and return a new `5x5' grid structure."
|
|
233 (let ((grid (make-vector 5x5-grid-size nil)))
|
|
234 (loop for y from 0 to (1- 5x5-grid-size) do
|
|
235 (aset grid y (make-vector 5x5-grid-size nil)))
|
|
236 grid))
|
|
237
|
|
238 (defun 5x5-cell (grid y x)
|
|
239 "Return the value of the cell in GRID at location X,Y."
|
|
240 (aref (aref grid y) x))
|
|
241
|
|
242 (defun 5x5-set-cell (grid y x value)
|
|
243 "Set the value of cell X,Y in GRID to VALUE."
|
|
244 (aset (aref grid y) x value))
|
|
245
|
|
246 (defun 5x5-flip-cell (grid y x)
|
|
247 "Flip the value of cell X,Y in GRID."
|
|
248 (5x5-set-cell grid y x (not (5x5-cell grid y x))))
|
|
249
|
|
250 (defun 5x5-copy-grid (grid)
|
|
251 "Make a new copy of GRID."
|
|
252 (let ((copy (5x5-make-new-grid)))
|
|
253 (loop for y from 0 to (1- 5x5-grid-size) do
|
|
254 (loop for x from 0 to (1- 5x5-grid-size) do
|
|
255 (5x5-set-cell copy y x (5x5-cell grid y x))))
|
|
256 copy))
|
|
257
|
|
258 (defun 5x5-make-move (grid row col)
|
|
259 "Make a move on GRID at row ROW and column COL."
|
|
260 (5x5-flip-cell grid row col)
|
|
261 (if (> row 0)
|
|
262 (5x5-flip-cell grid (1- row) col))
|
|
263 (if (< row (- 5x5-grid-size 1))
|
|
264 (5x5-flip-cell grid (1+ row) col))
|
|
265 (if (> col 0)
|
|
266 (5x5-flip-cell grid row (1- col)))
|
|
267 (if (< col (- 5x5-grid-size 1))
|
|
268 (5x5-flip-cell grid row (1+ col)))
|
|
269 grid)
|
|
270
|
|
271 (defun 5x5-row-value (row)
|
|
272 "Get the \"on-value\" for grid row ROW."
|
|
273 (loop for y from 0 to (1- 5x5-grid-size) sum (if (aref row y) 1 0)))
|
|
274
|
|
275 (defun 5x5-grid-value (grid)
|
|
276 "Get the \"on-value\" for grid GRID."
|
|
277 (loop for y from 0 to (1- 5x5-grid-size) sum (5x5-row-value (aref grid y))))
|
|
278
|
|
279 (defun 5x5-draw-grid-end ()
|
|
280 "Draw the top/bottom of the grid"
|
|
281 (insert "+")
|
|
282 (loop for x from 0 to (1- 5x5-grid-size) do
|
|
283 (insert "-" (make-string 5x5-x-scale ?-)))
|
|
284 (insert "-+ "))
|
|
285
|
|
286 (defun 5x5-draw-grid (grids)
|
|
287 "Draw the grids GRIDS into the current buffer."
|
|
288 (let ((buffer-read-only nil))
|
|
289 (erase-buffer)
|
|
290 (loop for grid in grids do (5x5-draw-grid-end))
|
|
291 (insert "\n")
|
|
292 (loop for y from 0 to (1- 5x5-grid-size) do
|
|
293 (loop for lines from 0 to (1- 5x5-y-scale) do
|
|
294 (loop for grid in grids do
|
|
295 (loop for x from 0 to (1- 5x5-grid-size) do
|
|
296 (insert (if (zerop x) "| " " ")
|
|
297 (make-string 5x5-x-scale
|
|
298 (if (5x5-cell grid y x) ?# ?.))))
|
|
299 (insert " | "))
|
|
300 (insert "\n")))
|
|
301 (loop for grid in grids do (5x5-draw-grid-end))
|
|
302 (insert "\n")
|
|
303 (insert (format "On: %d Moves: %d" (5x5-grid-value (car grids)) 5x5-moves))))
|
|
304
|
|
305 (defun 5x5-position-cursor ()
|
|
306 "Position the cursor on the grid."
|
|
307 (goto-line (+ (* 5x5-y-pos 5x5-y-scale) 2))
|
|
308 (goto-char (+ (point) (* 5x5-x-pos 5x5-x-scale) (+ 5x5-x-pos 1) 1)))
|
|
309
|
|
310 (defun 5x5-made-move ()
|
|
311 "Keep track of how many moves have been made."
|
|
312 (incf 5x5-moves))
|
|
313
|
|
314 (defun 5x5-make-random-grid ()
|
|
315 "Make a random grid."
|
|
316 (let ((grid (5x5-make-new-grid)))
|
|
317 (loop for y from 0 to (1- 5x5-grid-size) do
|
|
318 (loop for x from 0 to (1- 5x5-grid-size) do
|
|
319 (if (zerop (random 2))
|
|
320 (5x5-flip-cell grid y x))))
|
|
321 grid))
|
|
322
|
|
323 ;; Cracker functions.
|
|
324
|
|
325 ;;;###autoload
|
|
326 (defun 5x5-crack-randomly ()
|
|
327 "Attempt to crack 5x5 using random solutions."
|
|
328 (interactive)
|
|
329 (5x5-crack #'5x5-make-random-solution))
|
|
330
|
|
331 ;;;###autoload
|
|
332 (defun 5x5-crack-mutating-current ()
|
|
333 "Attempt to crack 5x5 by mutating the current solution."
|
|
334 (interactive)
|
|
335 (5x5-crack #'5x5-make-mutate-current))
|
|
336
|
|
337 ;;;###autoload
|
|
338 (defun 5x5-crack-mutating-best ()
|
|
339 "Attempt to crack 5x5 by mutating the best solution."
|
|
340 (interactive)
|
|
341 (5x5-crack #'5x5-make-mutate-best))
|
|
342
|
|
343 ;;;###autoload
|
|
344 (defun 5x5-crack-xor-mutate ()
|
|
345 "Attempt to crack 5x5 by xor the current and best solution and then
|
|
346 mutating the result."
|
|
347 (interactive)
|
|
348 (5x5-crack #'5x5-make-xor-with-mutation))
|
|
349
|
|
350 ;;;###autoload
|
|
351 (defun 5x5-crack (breeder)
|
|
352 "Attempt to find a solution for 5x5.
|
|
353
|
|
354 5x5-crack takes the argument BREEDER which should be a function that takes
|
|
355 two parameters, the first will be a grid vector array that is the current
|
|
356 solution and the second will be the best solution so far. The function
|
|
357 should return a grid vector array that is the new solution."
|
|
358
|
|
359 (interactive "aBreeder function: ")
|
|
360 (5x5)
|
|
361 (setq 5x5-cracking t)
|
|
362 (let* ((best-solution (5x5-make-random-grid))
|
|
363 (current-solution best-solution)
|
|
364 (best-result (5x5-make-new-grid))
|
|
365 (current-result (5x5-make-new-grid))
|
|
366 (target (* 5x5-grid-size 5x5-grid-size)))
|
|
367 (while (and (< (5x5-grid-value best-result) target)
|
|
368 (not (input-pending-p)))
|
|
369 (setq current-result (5x5-play-solution current-solution best-solution))
|
|
370 (if (> (5x5-grid-value current-result) (5x5-grid-value best-result))
|
|
371 (setq best-solution current-solution
|
|
372 best-result current-result))
|
|
373 (setq current-solution (funcall breeder
|
|
374 (5x5-copy-grid current-solution)
|
|
375 (5x5-copy-grid best-solution)))))
|
|
376 (setq 5x5-cracking nil))
|
|
377
|
|
378 (defun 5x5-make-random-solution (&rest ignore)
|
|
379 "Make a random solution."
|
|
380 (5x5-make-random-grid))
|
|
381
|
|
382 (defun 5x5-make-mutate-current (current best)
|
|
383 "Mutate the current solution."
|
|
384 (5x5-mutate-solution current))
|
|
385
|
|
386 (defun 5x5-make-mutate-best (current best)
|
|
387 "Mutate the best solution."
|
|
388 (5x5-mutate-solution best))
|
|
389
|
|
390 (defun 5x5-make-xor-with-mutation (current best)
|
|
391 "xor current and best solution then mutate the result."
|
|
392 (let ((xored (5x5-make-new-grid)))
|
|
393 (loop for y from 0 to (1- 5x5-grid-size) do
|
|
394 (loop for x from 0 to (1- 5x5-grid-size) do
|
|
395 (5x5-set-cell xored y x
|
|
396 (5x5-xor (5x5-cell current y x)
|
|
397 (5x5-cell best y x)))))
|
|
398 (5x5-mutate-solution xored)))
|
|
399
|
|
400 (defun 5x5-mutate-solution (solution)
|
|
401 "Randomly flip bits in the solution."
|
|
402 (loop for y from 0 to (1- 5x5-grid-size) do
|
|
403 (loop for x from 0 to (1- 5x5-grid-size) do
|
|
404 (if (= (random (/ (* 5x5-grid-size 5x5-grid-size) 2))
|
|
405 (/ (/ (* 5x5-grid-size 5x5-grid-size) 2) 2))
|
|
406 (5x5-flip-cell solution y x))))
|
|
407 solution)
|
|
408
|
|
409 (defun 5x5-play-solution (solution best)
|
|
410 "Play a solution on an empty grid. This destroys the current game in
|
|
411 progress because it is an animated attempt."
|
|
412 (5x5-new-game)
|
|
413 (loop for y from 0 to (1- 5x5-grid-size) do
|
|
414 (loop for x from 0 to (1- 5x5-grid-size) do
|
|
415 (setq 5x5-y-pos y
|
|
416 5x5-x-pos x)
|
|
417 (if (5x5-cell solution y x)
|
|
418 (5x5-flip-current))
|
|
419 (5x5-draw-grid (list 5x5-grid solution best))
|
|
420 (5x5-position-cursor)
|
|
421 (sit-for 5x5-animate-delay)))
|
|
422 5x5-grid)
|
|
423
|
|
424 ;; Keyboard response functions.
|
|
425
|
|
426 (defun 5x5-flip-current ()
|
|
427 "Make a move on the current cursor location."
|
|
428 (interactive)
|
|
429 (setq 5x5-grid (5x5-make-move 5x5-grid 5x5-y-pos 5x5-x-pos))
|
|
430 (5x5-made-move)
|
|
431 (unless 5x5-cracking
|
|
432 (5x5-draw-grid (list 5x5-grid)))
|
|
433 (5x5-position-cursor)
|
|
434 (when (= (5x5-grid-value 5x5-grid) (* 5x5-grid-size 5x5-grid-size))
|
|
435 (beep)
|
|
436 (message "You win!")))
|
|
437
|
|
438 (defun 5x5-up ()
|
|
439 "Move up."
|
|
440 (interactive)
|
|
441 (unless (zerop 5x5-y-pos)
|
|
442 (decf 5x5-y-pos)
|
|
443 (5x5-position-cursor)))
|
|
444
|
|
445 (defun 5x5-down ()
|
|
446 "Move down."
|
|
447 (interactive)
|
|
448 (unless (= 5x5-y-pos (1- 5x5-grid-size))
|
|
449 (incf 5x5-y-pos)
|
|
450 (5x5-position-cursor)))
|
|
451
|
|
452 (defun 5x5-left ()
|
|
453 "Move left."
|
|
454 (interactive)
|
|
455 (unless (zerop 5x5-x-pos)
|
|
456 (decf 5x5-x-pos)
|
|
457 (5x5-position-cursor)))
|
|
458
|
|
459 (defun 5x5-right ()
|
|
460 "Move right."
|
|
461 (interactive)
|
|
462 (unless (= 5x5-x-pos (1- 5x5-grid-size))
|
|
463 (incf 5x5-x-pos)
|
|
464 (5x5-position-cursor)))
|
|
465
|
|
466 (defun 5x5-bol ()
|
|
467 "Move to beginning of line."
|
|
468 (interactive)
|
|
469 (setq 5x5-x-pos 0)
|
|
470 (5x5-position-cursor))
|
|
471
|
|
472 (defun 5x5-eol ()
|
|
473 "Move to end of line."
|
|
474 (interactive)
|
|
475 (setq 5x5-x-pos (1- 5x5-grid-size))
|
|
476 (5x5-position-cursor))
|
|
477
|
|
478 (defun 5x5-first ()
|
|
479 "Move to the first cell."
|
|
480 (interactive)
|
|
481 (setq 5x5-x-pos 0
|
|
482 5x5-y-pos 0)
|
|
483 (5x5-position-cursor))
|
|
484
|
|
485 (defun 5x5-last ()
|
|
486 "Move to the last cell."
|
|
487 (interactive)
|
|
488 (setq 5x5-x-pos (1- 5x5-grid-size)
|
|
489 5x5-y-pos (1- 5x5-grid-size))
|
|
490 (5x5-position-cursor))
|
|
491
|
|
492 (defun 5x5-randomize ()
|
|
493 "Randomize the grid."
|
|
494 (interactive)
|
|
495 (when (5x5-y-or-n-p "Start a new game with a random grid? ")
|
|
496 (setq 5x5-x-pos (/ 5x5-grid-size 2)
|
|
497 5x5-y-pos (/ 5x5-grid-size 2)
|
|
498 5x5-moves 0
|
|
499 5x5-grid (5x5-make-random-grid))
|
|
500 (unless 5x5-cracking
|
|
501 (5x5-draw-grid (list 5x5-grid)))
|
|
502 (5x5-position-cursor)))
|
|
503
|
|
504 ;; Support functions
|
|
505
|
|
506 (defun 5x5-xor (x y)
|
|
507 "Boolean exclusive-or of X and Y."
|
|
508 (and (or x y) (not (and x y))))
|
|
509
|
|
510 (defun 5x5-y-or-n-p (prompt)
|
|
511 "5x5 wrapper for y-or-n-p which respects the 5x5-hassle-me setting."
|
|
512 (if 5x5-hassle-me
|
|
513 (y-or-n-p prompt)
|
|
514 t))
|
|
515
|
|
516 (provide '5x5)
|
|
517
|
|
518 ;;; 5x5.el ends here
|