Mercurial > hg > xemacs-beta
comparison lisp/games/mine.el @ 98:0d2f883870bc r20-1b1
Import from CVS: tag r20-1b1
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:13:56 +0200 |
parents | 8fc7fe29b841 |
children | 1917ad0d78d7 |
comparison
equal
deleted
inserted
replaced
97:498bf5da1c90 | 98:0d2f883870bc |
---|---|
1 ;;; mine.el --- Mine game for GNU Emacs | |
2 | |
3 ;; Author: Jacques Duthen <duthen@cegelec-red.fr> | |
4 ;; Keywords: games | |
5 ;; Time-stamp: <97/01/20 14:37:36 duthen> | |
6 ;; Version: 1.17 | |
7 | |
8 (defconst mine-version-number "1.17" "Emacs Mine version number.") | |
9 (defconst mine-version (format "Emacs Mine v%s by Jacques Duthen © 1997" | |
10 mine-version-number) | |
11 "Full Emacs Mine version number.") | |
12 | |
13 ;; This file is not yet part of GNU Emacs. | |
14 | |
15 ;; GNU Emacs is free software; you can redistribute it and/or modify | |
16 ;; it under the terms of the GNU General Public License as published by | |
17 ;; the Free Software Foundation; either version 2, or (at your option) | |
18 ;; any later version. | |
19 | |
20 ;; GNU Emacs is distributed in the hope that it will be useful, | |
21 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
23 ;; GNU General Public License for more details. | |
24 | |
25 ;; You should have received a copy of the GNU General Public License | |
26 ;; along with GNU Emacs; see the file COPYING. If not, write to the | |
27 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
28 ;; Boston, MA 02111-1307, USA. | |
29 | |
30 ;;; Commentary: | |
31 | |
32 ;; The object of this classical game is to locate the hidden mines. | |
33 ;; To do this, you hit the squares on the game board that do not | |
34 ;; contain mines, and you mark the squares that do contain mines. | |
35 | |
36 ;; The number of hidden mines remaining in the mine field is indicated | |
37 ;; inside the buffer. Every time you mark a square as a mine, this | |
38 ;; number decreases by one, even if you incorrectly mark a square. | |
39 | |
40 ;; To hit a square: Point to the square, and click the left button. | |
41 ;; If the square is a mine, you loose. | |
42 ;; If the square isn't a mine, a number appears, which represents | |
43 ;; the number of mines in the surrounding eight squares. | |
44 | |
45 ;; To mark a square as a mine: Point to the square, and click | |
46 ;; the right button. | |
47 | |
48 ;; To play Mine, compile it if you want, load it, and type `M-x mine'. | |
49 | |
50 ;; To get help and doc, see the functions `mine' and `mine-help' | |
51 ;; (ie. type `?' in the *Mine* buffer or type `C-h f mine') | |
52 | |
53 ;; This module has been developed and tested with GNU Emacs 19.31.1, | |
54 ;; but it should run with any GNU Emacs 19.* (at least with versions | |
55 ;; superior to 19.31). | |
56 | |
57 ;; This module has not been tested (yet) with XEmacs. It may or may | |
58 ;; not run (can anybody tell me?). | |
59 | |
60 ;; Send any comment or bug report (do you expect to find any? ;-) to me: | |
61 ;; duthen@cegelec-red.fr (Jacques Duthen) | |
62 | |
63 ;; Good luck. | |
64 | |
65 ;; 1.17 Thanks to Vladimir Alexiev <vladimir@cs.ualberta.ca>. | |
66 ;; Fix bug: (void-function unless), add minimal support for xemacs. | |
67 ;; (mine-xemacs-p): Added. | |
68 ;; (event-point): New function. | |
69 ;; (mine-mouse-hit, mine-mouse-mark): Use (interactive "@e") and `event-point' | |
70 ;; (mine-init-mode-map): Support xemacs mouse binding. | |
71 ;; (mine-make-face): Support xemacs get-face. | |
72 ;; (mine-goto): Support `auto-show-make-point-visible' as well as | |
73 ;; `hscroll-point-visible'. | |
74 | |
75 ;; 1.16 Initial released version. | |
76 | |
77 ;;; Code: | |
78 | |
79 (defvar mine-xemacs-p (string-match "XEmacs\\|Lucid" emacs-version)) | |
80 | |
81 ;;; ================================================================ | |
82 ;;; User Variables: | |
83 | |
84 ;;; -1- size | |
85 | |
86 ;;; The mine field is a rectangle (mine-xmax x mine-ymax), which is | |
87 ;;; duplicated to fill a bigger rectangle periodically tiled with the | |
88 ;;; smaller one, the period being (mine-xmax x mine-ymax). | |
89 | |
90 (defvar mine-xmax 16 "*The logical width of the mine field.") | |
91 (defvar mine-ymax 24 "*The logical height of the mine field.") | |
92 | |
93 (defvar mine-mines-% 16 | |
94 "*Percentage (between 0 and 100) of mines in the mine field.") | |
95 | |
96 (defvar mine-torus 't | |
97 "*Non-nil (the default) to play the game on a periodic board (a torus).") | |
98 | |
99 (defvar mine-nb-tiles-x 2 | |
100 "*Number of duplications in the x direction, when `mine-torus' is non-nil. | |
101 Indicate the number of times the original mine field is duplicated | |
102 in the x direction. | |
103 It's better looking when it's an integer. | |
104 nil means fill exactly the whole window. | |
105 0 means fill the whole window with the biggest integer that fits. | |
106 a negative number means use exactly the opposite number. If it's | |
107 too big, the rows are truncated by emacs. Automatic horizontal | |
108 scrolling will occur if you move to an invisible point. | |
109 a positive float means limit to the window width if needed. | |
110 a positive integer means limit to the window width if needed, | |
111 with the biggest possible integer value anyway. | |
112 ") | |
113 | |
114 (defvar mine-nb-tiles-y 2 | |
115 "*Number of duplications in the y direction, when `mine-torus' is non-nil. | |
116 Indicate the number of times the original mine field is duplicated | |
117 in the y direction. | |
118 It's better looking when it's an integer. | |
119 nil means fill exactly the whole window. | |
120 0 means fill the whole window with the biggest integer that fits. | |
121 a negative number means use exactly the opposite number. If it's | |
122 too big, the rows will be simply scrolled up or down by emacs. | |
123 a positive float means limit to the window height if needed. | |
124 a positive integer means limit to the window height if needed, | |
125 with the biggest possible integer value anyway. | |
126 ") | |
127 | |
128 ;;; -2- square characters | |
129 | |
130 ;;; All these characters may be changed but the first three ones | |
131 ;;; `unmarked' `marked' `zero' must differ from each other. | |
132 | |
133 (defvar mine-char-unmarked ?- | |
134 "*Character for a square not yet marked nor hit.") | |
135 (defvar mine-char-marked ?@ | |
136 "*Character for a square marked as containing a mine.") | |
137 (defvar mine-char-zero ?\ | |
138 "*Character for a square hit with no adjacent mine.") | |
139 | |
140 (defvar mine-char-pad ?\ | |
141 "*Character to pad in the x direction or nil (not yet implemented).") | |
142 (defvar mine-char-not-found ?o | |
143 "*Character for a square marked but with no mine.") | |
144 (defvar mine-char-bogus ?x | |
145 "*Character for a square not marked but with a mine.") | |
146 | |
147 ;;; -3- colors | |
148 | |
149 (defvar mine-colorp (if window-system 't 'nil) | |
150 "*Non-nil means with colors. Nil means in black and white.") | |
151 | |
152 (defvar mine-colors nil | |
153 "*Set this variable to override the colors defined by | |
154 `mine-default-colors' (use the same format).") | |
155 | |
156 (defconst mine-default-colors | |
157 '((mine-face-unmarked . "LightBlue") | |
158 (mine-face-marked . "Red") | |
159 (0 . nil) | |
160 (1 . "Cyan") | |
161 (2 . "Green") | |
162 (3 . "Yellow") | |
163 (4 . "Orange") | |
164 (5 . "OrangeRed") | |
165 (6 . "Red") | |
166 (7 . "Red") | |
167 (8 . "Red") | |
168 (mine-face-pad . nil) | |
169 (mine-face-not-found . "Red") | |
170 (mine-face-bogus . "Red") | |
171 ) | |
172 "A-list of default colors for Mine faces. Don't change its value. | |
173 You can override these settings with `mine-colors' using the same format.") | |
174 | |
175 ;;; -4- redisplay | |
176 | |
177 (defvar mine-level 2 | |
178 "*Redisplay speed. 0 is the slowest redisplay, 5 is the fastest one. | |
179 0 means redisplay when every single square changes. | |
180 1 means redisplay when one square and its periodic images change. | |
181 2 means redisplay every `mine-count1-max' change. | |
182 3 means redisplay every `mine-count1-max'*`mine-count2-max' change. | |
183 -1 or nil means redisplay only when all the changes are done. | |
184 ") | |
185 | |
186 (defvar mine-count1-max 16 | |
187 "*See `mine-level'. | |
188 Redisplay when the number of empty squares which have changed | |
189 is greater than `mine-count1-max'. | |
190 8 means redisplay each time 8 squares have been changed. | |
191 -1 means redisplay only when all the changes are done.") | |
192 | |
193 (defvar mine-count2-max 4 | |
194 "*See `mine-level'. | |
195 Redisplay when the number of empty squares which have changed | |
196 is greater than `mine-count1-max'. | |
197 8 means redisplay each time 8 squares have been changed. | |
198 -1 means redisplay only when all the changes are done.") | |
199 | |
200 (defvar mine-hscroll-step 4 | |
201 "*Local value for `hscroll-step'") | |
202 | |
203 (defvar mine-mode-hook nil | |
204 "*Hook called by `mine-mode-hook'.") | |
205 | |
206 ;;; ================================================================ | |
207 ;;; Internal variables: | |
208 | |
209 (defvar mine-user-variables | |
210 '("Size" | |
211 mine-xmax mine-ymax mine-mines-% | |
212 mine-torus mine-nb-tiles-x mine-nb-tiles-y | |
213 "Square characters" | |
214 mine-char-unmarked mine-char-marked mine-char-zero | |
215 mine-char-pad mine-char-not-found mine-char-bogus | |
216 "Colors" | |
217 mine-colorp mine-colors | |
218 "Redisplay" | |
219 mine-level mine-count1-max mine-count2-max | |
220 "Scrolling" | |
221 mine-hscroll-step | |
222 "Hook" | |
223 mine-mode-hook)) | |
224 | |
225 (defvar mine-user-commands | |
226 '("Help" | |
227 mine mine-help mine-help-bindings mine-help-variables | |
228 "Mouse control" | |
229 mine-mouse-hit mine-mouse-mark | |
230 "Move" | |
231 mine-left mine-right mine-up mine-down | |
232 mine-bol mine-eol mine-top mine-bottom | |
233 "Hit and mark" | |
234 mine-hit-curpoint mine-mark-curpoint | |
235 "Quit" | |
236 mine-quit)) | |
237 | |
238 ;; pad x factor == (if mine-char-pad 2 1) | |
239 (defvar mine-padx*) | |
240 | |
241 (defvar mine-width) | |
242 (defvar mine-height) | |
243 | |
244 ;; (x y) of current point | |
245 (defvar mine-x) ;; 1 <= mine-x <= mine-width | |
246 (defvar mine-y) ;; 1 <= mine-y <= mine-height | |
247 | |
248 ;; limits of the playable part of the board | |
249 (defvar mine-point-min) | |
250 (defvar mine-point-max) | |
251 | |
252 (defvar mine-point-remaining-mines) | |
253 (defvar mine-point-mines-hit) | |
254 | |
255 (defvar mine-mode-map nil) | |
256 | |
257 (defvar mine-real-mines) | |
258 | |
259 (defvar mine-nb-remaining-mines) | |
260 (defvar mine-nb-remaining-marks) | |
261 (defvar mine-nb-mines-hit) | |
262 | |
263 (defvar mine-faces) | |
264 | |
265 ;;; This variable is more special rather than global. | |
266 (defvar mine-adjacent-points) | |
267 | |
268 (defvar mine-count1) | |
269 (defvar mine-count2) | |
270 | |
271 ;;; ================================================================ | |
272 ;;; Macros (stolen from "cl.el" (soon in "subr.el" (thanks to rms))) | |
273 | |
274 (eval-when-compile | |
275 (or (fboundp 'when) | |
276 (defmacro when (cond &rest body) | |
277 "(when COND BODY...): if COND yields non-nil, do BODY, else return nil." | |
278 (list 'if cond (cons 'progn body))))) | |
279 | |
280 ;;; ================================================================ | |
281 ;;; User commands | |
282 | |
283 ;;;###autoload | |
284 (defun mine (num) | |
285 "Play Mine. Optional prefix argument is the number of mines. | |
286 | |
287 To play Mine, type `\\[mine]' or `\\[universal-argument] NUM \\[mine]'. | |
288 | |
289 An optional prefix argument specifies the number of mines to be hidden | |
290 in the field. If no prefix argument is given, a percentage | |
291 `mine-mines-%' of the field will contain mines. | |
292 | |
293 What is Mine?\\<mine-mode-map> | |
294 | |
295 Mine is a classical game of hide and seek played on a rectangular grid | |
296 containing `mine-xmax' by `mine-ymax' squares (the mine field). | |
297 | |
298 Your opponent (Emacs, in this case) has hidden several mines within | |
299 this field. The object of the game is to find every hidden mine. | |
300 | |
301 When you're sure a square does NOT contain a mine, you can hit it: | |
302 move the mouse over the square and press `\\[mine-mouse-hit]' or | |
303 move the cursor with the usual keys and press `\\[mine-hit-curpoint]'. | |
304 | |
305 If the square is a mine, you loose. | |
306 If the square isn't a mine, a number appears which represents | |
307 the number of mines in the surrounding eight squares. | |
308 | |
309 When you think a square DOES contain a mine, you can mark it: | |
310 move the mouse over the square and press `\\[mine-mouse-mark]' or | |
311 move the cursor with the usual keys and press `\\[mine-mark-curpoint]'. | |
312 | |
313 The number of hidden mines remaining in the mine field is indicated | |
314 inside the buffer. Every time you mark a square as a mine, this | |
315 number decreases by one, even if you incorrectly mark a square. | |
316 | |
317 If `mine-torus' is non-nil (the default), the Mine game is played over | |
318 a periodic field (like a torus). Each mine is hidden periodically | |
319 over the mine board `mine-nb-tiles-x' times in the x direction and | |
320 `mine-nb-tiles-y' times in the y direction. | |
321 | |
322 If `mine-colorp' is non-nil (the default, if the system allows it), | |
323 the game is displayed with colors. The colors can be chosen with the | |
324 variable `mine-colors'. | |
325 | |
326 If the redisplay is not fast enough, increase `mine-level'. If you | |
327 want to see a smoother (slower) redisplay, decrease `mine-level', | |
328 `mine-count1-max' and `mine-count2-max'. | |
329 | |
330 You can get help on `mine-mode' and its key bindings by pressing `\\[mine-help]' | |
331 while in the *Mine* buffer. | |
332 " | |
333 (interactive "P") | |
334 (switch-to-buffer "*Mine*") | |
335 (mine-mode) | |
336 (setq buffer-read-only 't) | |
337 (buffer-disable-undo (current-buffer)) | |
338 (setq mine-nb-remaining-mines | |
339 (or num (round (/ (* mine-xmax mine-ymax mine-mines-%) 100))) | |
340 mine-nb-remaining-marks mine-nb-remaining-mines) | |
341 (if (> mine-nb-remaining-mines (* mine-xmax mine-ymax)) | |
342 (error "Too many mines: %d" mine-nb-remaining-mines)) | |
343 (mine-init-faces) | |
344 (setq mine-real-mines (mine-init-mines mine-nb-remaining-mines)) | |
345 (setq mine-nb-mines-hit 0) | |
346 (mine-init-board) | |
347 (mine-reset-counters) | |
348 (mine-update-remaining-mines) | |
349 (setq hscroll-step mine-hscroll-step) | |
350 ;; initial position | |
351 (setq mine-x 1) | |
352 (setq mine-y 1) | |
353 (mine-goto mine-x mine-y) | |
354 ) | |
355 | |
356 ;; Mine mode is suitable only for specially formatted data. | |
357 (put 'mine-mode 'mode-class 'special) | |
358 | |
359 (defun mine-mode () | |
360 "Major mode for playing Mine. To learn how to play Mine, see `mine'. | |
361 | |
362 If you have a mouse, you can do:\\<mine-mode-map> | |
363 | |
364 `\\[mine-mouse-hit]' -- hit point | |
365 `\\[mine-mouse-mark]' -- mark or unmark a mine at point | |
366 | |
367 If you don't have a mouse, you can move the cursor over the mine | |
368 field with the usual mnemonic keys and: | |
369 | |
370 `\\[mine-hit-curpoint]' -- hit point | |
371 `\\[mine-mark-curpoint]' -- mark or unmark a mine at point | |
372 | |
373 `\\[mine-quit]' -- give up and see the hidden mines | |
374 | |
375 You can get help with: | |
376 | |
377 `\\[mine-help-variables]' -- get help on Mine variables | |
378 `\\[mine-help-bindings]' -- get help on Mine bindings | |
379 | |
380 \\{mine-mode-map} | |
381 " | |
382 (interactive) | |
383 (kill-all-local-variables) | |
384 (make-local-variable 'hscroll-step) | |
385 (use-local-map mine-mode-map) | |
386 (setq truncate-lines 't) | |
387 (setq major-mode 'mine-mode) | |
388 (setq mode-name "Mine") | |
389 (run-hooks 'mine-mode-hook) | |
390 ) | |
391 | |
392 ;;;###autoload | |
393 (defun mine-version () | |
394 "Return string describing the current version of Mine. | |
395 When called interactively, displays the version." | |
396 (interactive) | |
397 (if (interactive-p) | |
398 (message (mine-version)) | |
399 mine-version)) | |
400 | |
401 ;;;###autoload | |
402 (defun mine-help () | |
403 "*Get help on `mine-mode'." | |
404 (interactive) | |
405 (save-excursion | |
406 (switch-to-buffer "*Mine*") | |
407 (mine-mode) | |
408 (describe-mode))) | |
409 | |
410 (defun mine-help-variables () | |
411 "*Get help on Mine variables." | |
412 (interactive) | |
413 (save-excursion | |
414 (switch-to-buffer "*Mine*") | |
415 (mine-mode) | |
416 (apropos-symbols mine-user-variables 't))) | |
417 | |
418 (defun mine-help-bindings () | |
419 "*Get help on Mine bindings." | |
420 (interactive) | |
421 (save-excursion | |
422 (switch-to-buffer "*Mine*") | |
423 (mine-mode) | |
424 (apropos-symbols mine-user-commands 't))) | |
425 | |
426 (defun mine-print-settings () | |
427 "*Print the current Mine settings (value of all the user variables)." | |
428 (interactive) | |
429 (with-output-to-temp-buffer "*scratch*" | |
430 (mine-print-variables mine-user-variables))) | |
431 | |
432 ;;; ================================================================ | |
433 ;;; Click events - nop hit mark | |
434 | |
435 ;;; [jack] The elisp manual says: | |
436 ;;; If you want to take action as soon as a button is pressed, | |
437 ;;; you need to handle "button-down" events. | |
438 ;;; The global map (cf. `mouse.el') has, by default, the binding: | |
439 ;;; (define-key global-map [down-mouse-1] 'mouse-drag-region) | |
440 ;;; It seems that this function "eats" the final event [mouse-1]. | |
441 ;;; So, we need a local binding for [down-mouse-1] which shadows | |
442 ;;; the global one and prevents `mouse-drag-region' from being called. | |
443 ;;; Hence, in `mine-init-mode-map' I use the following binding: | |
444 ;;; (define-key mine-mode-map [down-mouse-1] 'mine-mouse-nop) | |
445 ;;; I found a better binding in "apropos.el" | |
446 ;;; (define-key mine-mode-map [down-mouse-1] nil) | |
447 ;;; but, as it does not work, let's go back to nop... | |
448 | |
449 (or (fboundp 'event-point) | |
450 (defun event-point (event) | |
451 (posn-point (event-end event)))) | |
452 | |
453 (defun mine-mouse-nop (event) | |
454 "Nop" | |
455 (interactive "e")) | |
456 | |
457 (defun mine-mouse-hit (event) | |
458 "Move point to the position clicked on with the mouse and hit this point." | |
459 (interactive "@e") | |
460 (if (mine-goto-point (event-point event)) | |
461 (mine-hit-curpoint) | |
462 (mine-message 'mine-msg-click-precisely))) | |
463 | |
464 (defun mine-mouse-mark (event) | |
465 "Move point to the position clicked on with the mouse and mark or unmark | |
466 this point." | |
467 (interactive "@e") | |
468 (if (mine-goto-point (event-point event)) | |
469 (mine-mark-curpoint) | |
470 (mine-message 'mine-msg-click-precisely))) | |
471 | |
472 ;;; ================================================================ | |
473 ;;; Key events - hit mark quit | |
474 | |
475 (defun mine-hit-curpoint () | |
476 "Hit point" | |
477 (interactive) | |
478 (mine-reset-counters) | |
479 (let ((c (following-char))) | |
480 (save-excursion | |
481 (cond | |
482 ((eq c mine-char-marked) | |
483 (mine-message 'mine-msg-unmark-before-hit)) | |
484 ((not (eq c mine-char-unmarked)) | |
485 (mine-message 'mine-msg-point-already-hit)) | |
486 ((mine-mine-at-point-p (point) 'slowp) | |
487 (setq mine-nb-mines-hit (1+ mine-nb-mines-hit)) | |
488 (mine-update-mines-hit) | |
489 (mine-message 'mine-msg-loose) | |
490 (mine-quit)) | |
491 (t ;; the real job... | |
492 (let* ((x.y (mine-top-left (mine-point-to-x.y (point)))) | |
493 (pxy (cons (point) x.y)) | |
494 (mine-adjacent-points (list pxy))) ; special variable | |
495 (while mine-adjacent-points | |
496 (setq pxy (car mine-adjacent-points) | |
497 mine-adjacent-points (cdr mine-adjacent-points)) | |
498 (mine-deep-hit pxy)))))))) | |
499 | |
500 (defun mine-mark-curpoint () | |
501 "Mark or unmark current position" | |
502 (interactive) | |
503 (mine-reset-counters) | |
504 (let ((c (following-char))) | |
505 (save-excursion | |
506 (cond | |
507 ((eq c mine-char-unmarked) | |
508 (mine-mark-board (point)) | |
509 (setq mine-nb-remaining-marks | |
510 (1- mine-nb-remaining-marks)) | |
511 (if (mine-mine-at-point-p (point) 'slowp) | |
512 (setq mine-nb-remaining-mines | |
513 (1- mine-nb-remaining-mines)))) | |
514 ((eq c mine-char-marked) | |
515 (mine-unmark-board (point)) | |
516 (setq mine-nb-remaining-marks | |
517 (1+ mine-nb-remaining-marks)) | |
518 (if (mine-mine-at-point-p (point) 'slowp) | |
519 (setq mine-nb-remaining-mines | |
520 (1+ mine-nb-remaining-mines)))) | |
521 (t | |
522 (mine-message 'mine-msg-cannot-mark))) | |
523 (mine-update-remaining-mines)))) | |
524 | |
525 (defun mine-quit () | |
526 "*Display hidden and bogus mines." | |
527 (interactive) | |
528 (when (y-or-n-p "Do you want to see the remaining and bogus mines? ") | |
529 (mine-show-bogus-mines))) | |
530 | |
531 (defun mine-show-bogus-mines () | |
532 (mine-reset-counters) | |
533 (let ((nrb 0) (nbb 0) | |
534 (x.y (cons nil nil)) | |
535 (y 1) x | |
536 point c) | |
537 (while (<= y mine-ymax) | |
538 (setq x 1) | |
539 (setcdr x.y y) | |
540 (while (<= x mine-xmax) | |
541 (setq point (mine-xy-to-point x y) | |
542 c (char-after point)) | |
543 (cond | |
544 ((eq c mine-char-unmarked) | |
545 (setcar x.y x) | |
546 (when (mine-mine-at-xy-p x.y) | |
547 (setq nrb (1+ nrb)) | |
548 (mine-update-board point mine-char-not-found 'mine-face-not-found))) | |
549 ((eq c mine-char-marked) | |
550 (setcar x.y x) | |
551 (when (not (mine-mine-at-xy-p x.y)) | |
552 (setq nbb (1+ nbb)) | |
553 (mine-update-board point mine-char-bogus 'mine-face-bogus)))) | |
554 (setq x (1+ x))) | |
555 (setq y (1+ y))) | |
556 (mine-update-bogus-mines nrb nbb))) | |
557 | |
558 ;;; ================================================================ | |
559 ;;; Key events - moves | |
560 | |
561 (defun mine-left () | |
562 "Move left" | |
563 (interactive) | |
564 (setq mine-x (1- mine-x)) | |
565 (when (<= mine-x 0) | |
566 (while (<= mine-x mine-width) | |
567 (setq mine-x (+ mine-x mine-xmax))) | |
568 (setq mine-x (- mine-x mine-xmax))) | |
569 (mine-goto mine-x mine-y)) | |
570 | |
571 (defun mine-right () | |
572 "Move right" | |
573 (interactive) | |
574 (setq mine-x (1+ mine-x)) | |
575 (when (> mine-x mine-width) | |
576 (while (>= mine-x 0) | |
577 (setq mine-x (- mine-x mine-xmax))) | |
578 (setq mine-x (+ mine-x mine-xmax))) | |
579 (mine-goto mine-x mine-y)) | |
580 | |
581 (defun mine-up () | |
582 "Move up" | |
583 (interactive) | |
584 (setq mine-y (1- mine-y)) | |
585 (when (<= mine-y 0) | |
586 (while (<= mine-y mine-height) | |
587 (setq mine-y (+ mine-y mine-ymax))) | |
588 (setq mine-y (- mine-y mine-ymax))) | |
589 (mine-goto mine-x mine-y)) | |
590 | |
591 (defun mine-down () | |
592 "Move down" | |
593 (interactive) | |
594 (setq mine-y (1+ mine-y)) | |
595 (when (> mine-y mine-height) | |
596 (while (>= mine-y 0) | |
597 (setq mine-y (- mine-y mine-ymax))) | |
598 (setq mine-y (+ mine-y mine-ymax))) | |
599 (mine-goto mine-x mine-y)) | |
600 | |
601 | |
602 (defun mine-bol () | |
603 "Move to the beginning of the row" | |
604 (interactive) | |
605 (setq mine-x 1) | |
606 (mine-goto mine-x mine-y)) | |
607 | |
608 (defun mine-eol () | |
609 "Move to the end of the row" | |
610 (interactive) | |
611 (setq mine-x mine-width) | |
612 (mine-goto mine-x mine-y)) | |
613 | |
614 (defun mine-top () | |
615 "Move to the top of the column" | |
616 (interactive) | |
617 (setq mine-y 1) | |
618 (mine-goto mine-x mine-y)) | |
619 | |
620 (defun mine-bottom () | |
621 "Move to the bottom of the column" | |
622 (interactive) | |
623 (setq mine-y mine-height) | |
624 (mine-goto mine-x mine-y)) | |
625 | |
626 ;;; ================================================================ | |
627 ;;; Internal model functions | |
628 | |
629 (defun mine-init-mines (num-mines) | |
630 (random t) | |
631 (let ((mines (list)) (n num-mines) x y x.y) | |
632 (while (> n 0) | |
633 (setq n (1- n) | |
634 x (1+ (random mine-xmax)) | |
635 y (1+ (random mine-ymax)) | |
636 x.y (cons x y)) | |
637 (while (mine-member x.y mines 'nil) | |
638 ;; replace by the point to the right (or next row if eol) | |
639 (if (< x mine-xmax) | |
640 (setcar x.y (setq x (1+ x))) | |
641 (setcar x.y (setq x 1)) | |
642 (setcdr x.y (setq y (if (< y mine-ymax) (1+ y) 1))))) | |
643 (setq mines (cons x.y mines))) | |
644 mines)) | |
645 | |
646 (defun mine-mine-at-point-p (point slowp) | |
647 (mine-member (mine-top-left (mine-point-to-x.y point)) | |
648 mine-real-mines slowp)) | |
649 | |
650 (defun mine-mine-at-xy-p (x.y) | |
651 (mine-member x.y mine-real-mines 'nil)) | |
652 | |
653 ;;; Returns non-nil if ELT is an element of LIST. | |
654 ;;; Constant time execution if slowp is non-nil. | |
655 (defun mine-member (x.y list slowp) | |
656 (let ((found 'nil)) | |
657 (while (and list (or slowp (not found))) | |
658 (if (equal x.y (car list)) | |
659 (setq found 't)) | |
660 (setq list (cdr list))) | |
661 found)) | |
662 | |
663 ;;; ================================================================ | |
664 ;;; Internal model & interface functions | |
665 | |
666 (defun mine-pxy (x y) | |
667 (cons (mine-xy-to-point x y) (cons x y))) | |
668 | |
669 ;; pxy == (point . (x . y)) | |
670 ;; with 1 <= {xy} <= mine-{xy}max | |
671 (defun mine-deep-hit (pxy) | |
672 (interactive) | |
673 (let (point x.y c) | |
674 (setq point (car pxy) | |
675 x.y (cdr pxy) | |
676 c (char-after point)) | |
677 (cond | |
678 ((eq c mine-char-marked)) ;; free but marked (user bug) | |
679 ((not (eq c mine-char-unmarked))) ;; already done | |
680 ((mine-mine-at-xy-p x.y) | |
681 (error "Internal error: mine-deep-hit mine at %s" point)) | |
682 (t ;; the real job... | |
683 (let* ((adjacent-points (mine-adjacent-points point x.y)) | |
684 (nb-adjacent-mines (mine-nb-adjacent-mines adjacent-points))) | |
685 (mine-display-nb-adjacent-mines point nb-adjacent-mines) | |
686 (when (zerop nb-adjacent-mines) | |
687 ;; Stack overflow: "Lisp nesting exceeds max-lisp-eval-depth" | |
688 ;;(mapc 'mine-deep-hit adjacent-points) | |
689 (setq mine-adjacent-points | |
690 (nconc adjacent-points mine-adjacent-points)))))))) | |
691 | |
692 ;; return == ((point . (x . y))*) | |
693 ;; with 1 <= {xy} <= mine-{xy}max | |
694 (defun mine-adjacent-points (point x.y) | |
695 (mine-random-permut | |
696 (if mine-torus | |
697 (mine-adjacent-points-on-torus point x.y) | |
698 (mine-adjacent-points-no-torus point x.y)))) | |
699 | |
700 (defun mine-random-permut (l) | |
701 (let ((ll (nthcdr (random (length l)) l))) | |
702 (nconc ll l) | |
703 (prog1 (cdr ll) (setcdr ll ())))) | |
704 | |
705 (defun mine-adjacent-points-no-torus (point x.y) | |
706 (let ((x (car x.y)) (y (cdr x.y)) (points (list)) xx yy) | |
707 ;; left column | |
708 (when (not (= x 1)) | |
709 (setq xx (1- x)) | |
710 (when (not (= y 1)) | |
711 (setq yy (1- y)) | |
712 (setq points (cons (mine-pxy xx yy) points))) | |
713 (setq points (cons (mine-pxy xx y) points)) | |
714 (when (not (= y mine-ymax)) | |
715 (setq yy (1+ y)) | |
716 (setq points (cons (mine-pxy xx yy) points)))) | |
717 ;; middle column | |
718 (setq xx x) | |
719 (when (not (= y 1)) | |
720 (setq yy (1- y)) | |
721 (setq points (cons (mine-pxy xx yy) points))) | |
722 (when (not (= y mine-ymax)) | |
723 (setq yy (1+ y)) | |
724 (setq points (cons (mine-pxy xx yy) points))) | |
725 ;; right column | |
726 (when (not (= x mine-xmax)) | |
727 (setq xx (1+ x)) | |
728 (when (not (= y 1)) | |
729 (setq yy (1- y)) | |
730 (setq points (cons (mine-pxy xx yy) points))) | |
731 (setq points (cons (mine-pxy xx y) points)) | |
732 (when (not (= y mine-ymax)) | |
733 (setq yy (1+ y)) | |
734 (setq points (cons (mine-pxy xx yy) points)))) | |
735 (nreverse points))) | |
736 | |
737 (defun mine-adjacent-points-on-torus (point x.y) | |
738 (let ((x (car x.y)) (y (cdr x.y)) (points (list)) xx yy) | |
739 ;; left column | |
740 (setq xx (if (= x 1) mine-xmax (1- x))) | |
741 (setq yy (if (= y 1) mine-ymax (1- y))) | |
742 (setq points (cons (mine-pxy xx yy) points)) | |
743 (setq points (cons (mine-pxy xx y) points)) | |
744 (setq yy (if (= y mine-ymax) 1 (1+ y))) | |
745 (setq points (cons (mine-pxy xx yy) points)) | |
746 ;; middle column | |
747 (setq xx x) | |
748 (setq yy (if (= y 1) mine-ymax (1- y))) | |
749 (setq points (cons (mine-pxy xx yy) points)) | |
750 (setq yy (if (= y mine-ymax) 1 (1+ y))) | |
751 (setq points (cons (mine-pxy xx yy) points)) | |
752 ;; right column | |
753 (setq xx (if (= x mine-xmax) 1 (1+ x))) | |
754 (setq yy (if (= y 1) mine-ymax (1- y))) | |
755 (setq points (cons (mine-pxy xx yy) points)) | |
756 (setq points (cons (mine-pxy xx y) points)) | |
757 (setq yy (if (= y mine-ymax) 1 (1+ y))) | |
758 (setq points (cons (mine-pxy xx yy) points)) | |
759 (nreverse points))) | |
760 | |
761 ;; l == ((p . (x . y))*) | |
762 (defun mine-nb-adjacent-mines (l) | |
763 (let ((nb 0) pxy x.y) | |
764 (while l | |
765 (setq pxy (car l) l (cdr l) x.y (cdr pxy)) | |
766 (if (mine-mine-at-xy-p x.y) | |
767 (setq nb (1+ nb)))) | |
768 nb)) | |
769 | |
770 ;;; ================================================================ | |
771 ;;; Mode map | |
772 | |
773 (defun mine-init-mode-map () | |
774 (let ((map (make-keymap)) (gm global-map)) | |
775 ;; All normally self-inserting keys (except digits) are undefined | |
776 (suppress-keymap map 'nil) | |
777 ;; Help | |
778 (define-key map "?" 'mine-help) | |
779 (define-key map "h" 'mine-help) | |
780 (define-key map "b" 'mine-help-bindings) | |
781 (define-key map "v" 'mine-help-variables) | |
782 (cond | |
783 (mine-xemacs-p | |
784 ;; Mouse control | |
785 (define-key map [mouse-1] 'mine-mouse-hit) | |
786 (define-key map [mouse-3] 'mine-mouse-mark) | |
787 ;; Mouse control to prevent problems | |
788 (define-key map [mouse-2] 'mine-mouse-nop)) | |
789 (t | |
790 ;; Mouse control | |
791 (define-key map [mouse-1] 'mine-mouse-hit) | |
792 (define-key map [mouse-3] 'mine-mouse-mark) | |
793 ;; Mouse control to prevent problems | |
794 (define-key map [mouse-2] 'mine-mouse-nop) | |
795 (define-key map [down-mouse-1] 'mine-mouse-nop) | |
796 (define-key map [down-mouse-2] 'mine-mouse-nop) | |
797 (define-key map [down-mouse-3] 'mine-mouse-nop) | |
798 (define-key map [drag-mouse-1] 'mine-mouse-nop) | |
799 (define-key map [drag-mouse-2] 'mine-mouse-nop) | |
800 (define-key map [drag-mouse-3] 'mine-mouse-nop) | |
801 (define-key map [mouse-2] 'mine-mouse-nop))) | |
802 ;; Move | |
803 (substitute-key-definition 'backward-char 'mine-left map gm) | |
804 (substitute-key-definition 'forward-char 'mine-right map gm) | |
805 (substitute-key-definition 'previous-line 'mine-up map gm) | |
806 (substitute-key-definition 'next-line 'mine-down map gm) | |
807 | |
808 (substitute-key-definition 'beginning-of-line 'mine-bol map gm) | |
809 (substitute-key-definition 'backward-word 'mine-bol map gm) | |
810 (substitute-key-definition 'backward-sexp 'mine-bol map gm) | |
811 (substitute-key-definition 'end-of-line 'mine-eol map gm) | |
812 (substitute-key-definition 'forward-word 'mine-eol map gm) | |
813 (substitute-key-definition 'forward-sexp 'mine-eol map gm) | |
814 (define-key map "\M-p" 'mine-top) | |
815 (define-key map "\M-n" 'mine-bottom) | |
816 ;; Hit and mark | |
817 (define-key map " " 'mine-hit-curpoint) | |
818 (define-key map "\C-m" 'mine-mark-curpoint) | |
819 (define-key map [kp-enter] 'mine-mark-curpoint) | |
820 (define-key map "m" 'mine-mark-curpoint) | |
821 (define-key map "q" 'mine-quit) | |
822 | |
823 (setq mine-mode-map map))) | |
824 | |
825 ;;; ================================================================ | |
826 ;;; Faces | |
827 | |
828 (defun mine-init-faces () | |
829 (setq mine-faces (list)) | |
830 (when mine-colorp | |
831 (let ((l (append mine-colors mine-default-colors)) | |
832 key.col key col name) | |
833 (while l | |
834 (setq key.col (car l) | |
835 l (cdr l) | |
836 key (car key.col) | |
837 col (cdr key.col)) | |
838 (when (null (assoc key mine-faces)) | |
839 (setq name | |
840 (cond | |
841 ((null key) nil) | |
842 ((symbolp key) (mine-make-face key col)) | |
843 ((not (integerp key)) | |
844 (error "Key should be a symbol or a number: '%s'" key)) | |
845 ((or (< key 0) (> key 8)) | |
846 (error "Key should be a number between 0 and 8: '%s'" key)) | |
847 (t | |
848 (setq name (intern (concat "mine-face-" key))) | |
849 (mine-make-face name col)))) | |
850 (setq mine-faces (cons (cons key name) mine-faces)))) | |
851 (setq mine-faces (nreverse mine-faces))))) | |
852 | |
853 (defun mine-make-face (name col) | |
854 (or (if (fboundp 'internal-find-face) | |
855 (internal-find-face name) | |
856 (find-face name)) | |
857 (let ((face (make-face name))) | |
858 (unless (or (not mine-xemacs-p) col) | |
859 (setq col (cdr (face-background 'default 'global)))) | |
860 (set-face-background face col) | |
861 face)) | |
862 name) | |
863 | |
864 (defun mine-get-face (key) | |
865 (cdr (assoc key mine-faces))) | |
866 | |
867 ;;; ================================================================ | |
868 ;;; Init board | |
869 | |
870 (defun mine-init-board () | |
871 (setq mine-padx* (if mine-char-pad 2 1)) | |
872 (if (not mine-torus) | |
873 (setq mine-width mine-xmax | |
874 mine-height mine-ymax) | |
875 (let (window-xmax window-nb-tiles-x window-xmax-int | |
876 window-ymax window-nb-tiles-y window-ymax-int) | |
877 (setq window-xmax (/ (window-width) mine-padx*) | |
878 window-nb-tiles-x (/ window-xmax mine-xmax) | |
879 window-xmax-int (* window-nb-tiles-x window-xmax)) | |
880 (setq mine-width | |
881 (max mine-xmax ; at least mine-xmax | |
882 (cond | |
883 ((null mine-nb-tiles-x) window-xmax) | |
884 ((not (numberp mine-nb-tiles-x)) | |
885 (error "mine-nb-tiles-x should be nil or a number: %s" | |
886 mine-nb-tiles-x)) | |
887 ((zerop mine-nb-tiles-x) window-xmax-int) | |
888 ((< mine-nb-tiles-x 0) | |
889 (floor (* mine-xmax (- mine-nb-tiles-x)))) | |
890 ((floatp mine-nb-tiles-x) | |
891 (min window-xmax (floor (* mine-xmax mine-nb-tiles-x)))) | |
892 (t (min window-xmax-int (* mine-xmax mine-nb-tiles-x)))))) | |
893 (setq window-ymax (- (window-height) 5) | |
894 window-nb-tiles-y (/ window-ymax mine-ymax) | |
895 window-ymax-int (* window-nb-tiles-y window-ymax)) | |
896 (setq mine-height | |
897 (max mine-ymax | |
898 (cond | |
899 ((null mine-nb-tiles-y) window-ymax) | |
900 ((not (numberp mine-nb-tiles-y)) | |
901 (error "mine-nb-tiles-y should be nil or a number: %s" | |
902 mine-nb-tiles-y)) | |
903 ((zerop mine-nb-tiles-y) window-ymax-int) | |
904 ((< mine-nb-tiles-y 0) | |
905 (floor (* mine-ymax (- mine-nb-tiles-y)))) | |
906 ((floatp mine-nb-tiles-y) | |
907 (min window-ymax (floor (* mine-ymax mine-nb-tiles-y)))) | |
908 (t (min window-ymax-int (* mine-ymax mine-nb-tiles-y)))))))) | |
909 (let ((buffer-read-only 'nil) | |
910 (face-unmarked (mine-get-face 'mine-face-unmarked)) | |
911 (face-pad (mine-get-face 'mine-face-pad)) | |
912 row col) | |
913 (erase-buffer) | |
914 (mine-insert-copyright) | |
915 (mine-insert-remaining-mines) | |
916 (mine-insert-mines-hit) | |
917 (setq mine-point-min (point)) | |
918 (setq row mine-height) | |
919 (while (>= (setq row (1- row)) 0) | |
920 (setq col (1- mine-width)) | |
921 (insert mine-char-unmarked) | |
922 (when face-unmarked | |
923 (put-text-property (1- (point)) (point) 'face face-unmarked)) | |
924 (while (>= (setq col (1- col)) 0) | |
925 (when mine-char-pad | |
926 (insert mine-char-pad) | |
927 (when face-pad | |
928 (put-text-property (1- (point)) (point) 'face face-pad))) | |
929 (insert mine-char-unmarked) | |
930 (when face-unmarked | |
931 (put-text-property (1- (point)) (point) 'face face-unmarked))) | |
932 (insert ?\n)) | |
933 (setq mine-point-max (1- (point))) | |
934 (mine-update-remaining-mines) | |
935 (mine-update-mines-hit) | |
936 (set-buffer-modified-p 'nil))) | |
937 | |
938 ;;; ================================================================ | |
939 ;;; Internal moves | |
940 | |
941 (defun mine-goto-point (point) | |
942 (let ((x.y (mine-point-to-x.y point))) | |
943 (setq mine-x (car x.y) mine-y (cdr x.y)) | |
944 (mine-goto mine-x mine-y) | |
945 (= point (point)))) | |
946 | |
947 (defun mine-goto (x y) | |
948 (goto-char (mine-xy-to-point x y)) | |
949 (cond ((fboundp 'hscroll-point-visible) | |
950 (hscroll-point-visible)) | |
951 ((fboundp 'auto-show-make-point-visible) | |
952 (auto-show-make-point-visible)))) | |
953 | |
954 ;;; ================================================================ | |
955 ;;; Conversions | |
956 | |
957 (defun mine-xy-to-point (x y) | |
958 ;; p = pmin + 2*w*(y-1) + 2*(x-1) | |
959 (+ mine-point-min | |
960 (* mine-padx* mine-width (1- y)) | |
961 (* mine-padx* (1- x)))) | |
962 | |
963 ;;; Returns the topleft equivalent of point, | |
964 ;;; on the periodic board, ie. converts point to model coordinates. | |
965 (defun mine-top-left (x.y) | |
966 (setcar x.y (1+ (mod (1- (car x.y)) mine-xmax))) | |
967 (setcdr x.y (1+ (mod (1- (cdr x.y)) mine-ymax))) | |
968 x.y) | |
969 | |
970 (defun mine-point-to-x.y (point) | |
971 (let (x y (p0 (- point mine-point-min))) | |
972 (cond | |
973 ((<= p0 0) | |
974 (setq x 1 y 1)) | |
975 ((>= point mine-point-max) | |
976 (setq x mine-width y mine-height)) | |
977 (t | |
978 ;; p = pmin + 2*w*(y-1) + 2*(x-1) | |
979 ;; y = (p - pmin)/2w + 1 | |
980 ;; x = (p - pmin - 2*w*(y-1)) / 2 + 1 | |
981 (setq y (1+ (/ p0 mine-width mine-padx*)) | |
982 x (1+ (/ (- p0 (* mine-padx* mine-width (1- y))) mine-padx*))))) | |
983 (cons x y))) | |
984 | |
985 ;;; ================================================================ | |
986 ;;; Screen display | |
987 | |
988 (defun mine-mark-board (point) | |
989 (mine-update-board point mine-char-marked 'mine-face-marked)) | |
990 | |
991 (defun mine-unmark-board (point) | |
992 (mine-update-board point mine-char-unmarked 'mine-face-unmarked)) | |
993 | |
994 (defun mine-display-nb-adjacent-mines (point nb) | |
995 (mine-update-board point | |
996 (if (zerop nb) mine-char-zero (+ ?0 nb)) | |
997 nb)) | |
998 | |
999 ;; todo: enumerer tous les points periodiques | |
1000 (defun mine-update-board (point c key) | |
1001 (let ((buffer-read-only 'nil) | |
1002 (face (mine-get-face key)) | |
1003 (x.y (mine-top-left (mine-point-to-x.y point))) | |
1004 x y) | |
1005 (setq x (car x.y)) | |
1006 (while (<= x mine-width) | |
1007 (setq y (cdr x.y)) | |
1008 (while (<= y mine-height) | |
1009 (mine-update-point (mine-xy-to-point x y) c face) | |
1010 (setq y (+ y mine-ymax))) | |
1011 (setq x (+ x mine-xmax))) | |
1012 (mine-reach-level 1) ; redisplay point and its periodic images | |
1013 (set-buffer-modified-p 'nil))) | |
1014 | |
1015 (defun mine-update-point (point c face) | |
1016 (goto-char point) | |
1017 (delete-char 1) | |
1018 (insert c) | |
1019 (when face | |
1020 (put-text-property point (point) 'face face)) | |
1021 (mine-reach-level 0)) ; redisplay point | |
1022 | |
1023 (defun mine-reach-level (level) | |
1024 (cond | |
1025 ((null mine-level)) ; no update at all | |
1026 ((< mine-level 0)) ; no update at all | |
1027 ((zerop mine-level) ; unconditional update | |
1028 (sit-for 0)) | |
1029 ((zerop level)) ; wait for level 1 | |
1030 ((= level 1) | |
1031 (cond | |
1032 ((= mine-level level) | |
1033 (sit-for 0)) | |
1034 ((= mine-count1 mine-count1-max) | |
1035 (setq mine-count1 0) | |
1036 (mine-reach-level (1+ level))) | |
1037 (t (setq mine-count1 (1+ mine-count1))))) | |
1038 ((= level 2) | |
1039 (setq mine-count1 0) | |
1040 (cond | |
1041 ((= mine-level level) | |
1042 (sit-for 0)) | |
1043 ((= mine-count2 mine-count2-max) | |
1044 (setq mine-count2 0) | |
1045 (mine-reach-level (1+ level))) | |
1046 (t (setq mine-count2 (1+ mine-count2))))) | |
1047 ((= level 3) | |
1048 (setq mine-count1 0) | |
1049 (setq mine-count2 0) | |
1050 (cond | |
1051 ((= mine-level level) | |
1052 (sit-for 0)))))) | |
1053 | |
1054 (defun mine-reset-counters () | |
1055 (setq mine-count1 0 | |
1056 mine-count2 0)) | |
1057 | |
1058 ;;; ================================================================ | |
1059 ;;; Messages - init board | |
1060 | |
1061 (defun mine-insert-copyright () | |
1062 (insert mine-version "\n\n")) | |
1063 | |
1064 (defun mine-insert-remaining-mines () | |
1065 (insert (format "%16s" "Remaining mines") ":") | |
1066 (setq mine-point-remaining-mines (point)) | |
1067 (insert " \n")) | |
1068 | |
1069 (defun mine-insert-mines-hit () | |
1070 (insert (format "%16s" "mines hit") ":") | |
1071 (setq mine-point-mines-hit (point)) | |
1072 (insert " \n\n")) | |
1073 | |
1074 ;;; ================================================================ | |
1075 ;;; Messages - update board | |
1076 | |
1077 (defun mine-update-remaining-mines () | |
1078 (let ((buffer-read-only 'nil)) | |
1079 (save-excursion | |
1080 (goto-char mine-point-remaining-mines) | |
1081 (delete-char 3) | |
1082 (insert (format "%3d" mine-nb-remaining-marks))) | |
1083 (set-buffer-modified-p 'nil)) | |
1084 (sit-for 0) | |
1085 (message "mines remaining to find...%d" mine-nb-remaining-marks) | |
1086 (when (and (zerop mine-nb-remaining-mines) | |
1087 (zerop mine-nb-remaining-marks)) | |
1088 (mine-message 'mine-msg-win))) | |
1089 | |
1090 (defun mine-update-mines-hit () | |
1091 (let ((buffer-read-only 'nil)) | |
1092 (save-excursion | |
1093 (goto-char mine-point-mines-hit) | |
1094 (delete-char 3) | |
1095 (insert (format "%3d" mine-nb-mines-hit))) | |
1096 (set-buffer-modified-p 'nil))) | |
1097 | |
1098 (defun mine-update-bogus-mines (nrb nbb) | |
1099 (let ((buffer-read-only 'nil) | |
1100 (msg (format "There were %d remaining mines and %d bogus mines" | |
1101 nrb nbb))) | |
1102 (save-excursion | |
1103 (goto-char (point-max)) | |
1104 (insert "\n" msg)) | |
1105 (set-buffer-modified-p 'nil) | |
1106 (message msg))) | |
1107 | |
1108 ;;; ================================================================ | |
1109 ;;; Messages - write minibuffer | |
1110 | |
1111 (defun mine-message (msg) | |
1112 (ding) | |
1113 (cond | |
1114 ((eq msg 'mine-msg-click-precisely) | |
1115 (message "Please, click more precisely")) | |
1116 ((eq msg 'mine-msg-unmark-before-hit) | |
1117 (message "You must unmark point before hitting it.")) | |
1118 ((eq msg 'mine-msg-point-already-hit) | |
1119 (message "Point has already been hit.")) | |
1120 ((eq msg 'mine-msg-cannot-mark) | |
1121 (message "Can't (un)mark point...")) | |
1122 ((eq msg 'mine-msg-loose) | |
1123 (message "Sorry... There's a mine here...") | |
1124 (sit-for 1) | |
1125 (message "Sorry... There's a mine here... You lost!")) | |
1126 ((eq msg 'mine-msg-win) | |
1127 (message "Congratulations...") | |
1128 (sit-for 1) | |
1129 (message "Congratulations... You won!")) | |
1130 (t | |
1131 (message (format "%s" msg))))) | |
1132 | |
1133 (mine-init-mode-map) | |
1134 | |
1135 ;;; ================================================================ | |
1136 | |
1137 (defun mine-print-variables (l) | |
1138 (let (var) | |
1139 (princ "(setq ") | |
1140 (while l | |
1141 (setq var (car l) l (cdr l)) | |
1142 (cond | |
1143 ((stringp var) (princ (format ";; %s\n " var))) | |
1144 ((not (symbolp var)) (error "Not a symbol: %s" var)) | |
1145 ((not (boundp var)) (error "Unboundp symbol: %s" var)) | |
1146 (t (princ (format "%-20s'%s" var (symbol-value var))) | |
1147 (when l (princ "\n "))))) | |
1148 (princ "))\n"))) | |
1149 | |
1150 ;;; ================================================================ | |
1151 | |
1152 ;;(autoload 'apropos-print "apropos") | |
1153 ;;(autoload 'apropos-do-all "apropos") | |
1154 | |
1155 (if (not (boundp 'apropos-accumulator)) | |
1156 (load "apropos")) | |
1157 | |
1158 (if (boundp 'apropos-item) | |
1159 ;; (Daniel.Pfeiffer's) old official version of apropos | |
1160 (defun apropos-symbols (l &optional do-all) | |
1161 (let ((ll (list))) | |
1162 (while l | |
1163 (when (not (stringp (car l))) | |
1164 (setq ll (cons (car l) ll))) | |
1165 (setq l (cdr l))) | |
1166 (setq apropos-accumulator (nreverse ll))) | |
1167 (or do-all (setq do-all apropos-do-all)) | |
1168 (apropos-print | |
1169 t | |
1170 (lambda (p) | |
1171 (let (doc symbol) | |
1172 (while p | |
1173 (setcar p | |
1174 (list ; (s f v p) | |
1175 (setq symbol (car p)) | |
1176 (if (commandp symbol) | |
1177 (if (setq doc (documentation symbol t)) | |
1178 (substring doc 0 (string-match "\n" doc)) | |
1179 "(not documented)")) | |
1180 (and do-all | |
1181 (user-variable-p symbol) | |
1182 (if (setq doc (documentation-property | |
1183 symbol 'variable-documentation t)) | |
1184 (substring doc 0 (string-match "\n" doc)))))) | |
1185 (setq p (cdr p))))) | |
1186 t))) | |
1187 | |
1188 (provide 'mine) | |
1189 | |
1190 ;;; mine.el ends here |