Fixed typo.
[riece] / lisp / riece-hangman.el
1 ;;; riece-hangman.el --- hangman
2 ;; Copyright (C) 1998-2004 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Keywords: IRC, riece
6
7 ;; This file is part of Riece.
8
9 ;; This program is free software; you can redistribute it and/or modify
10 ;; it under the terms of the GNU General Public License as published by
11 ;; the Free Software Foundation; either version 2, or (at your option)
12 ;; any later version.
13
14 ;; This program is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
21 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 ;; Boston, MA 02111-1307, USA.
23
24 ;;; Commentary:
25
26 ;; To use, add the following line to your ~/.riece/init.el:
27 ;; (add-to-list 'riece-addons 'riece-hangman)
28
29 ;;; Code:
30
31 (require 'riece-globals)
32 (require 'riece-identity)
33 (require 'riece-message)
34 (require 'riece-server)
35
36 (defgroup riece-hangman nil
37   "Interface to hangman.el"
38   :prefix "riece-"
39   :group 'riece)
40
41 (defcustom riece-hangman-hello-regexp "^, hangman"
42   "Pattern of string to start the game."
43   :type 'string
44   :group 'riece-hangman)
45
46 (defcustom riece-hangman-bye-regexp "^, bye hangman"
47   "Pattern of string to end the game."
48   :type 'string
49   :group 'riece-hangman)
50
51 (defcustom riece-hangman-words-file "/usr/share/dict/words"
52   "Location of words file."
53   :type 'file
54   :group 'riece-hangman)
55
56 (defvar riece-hangman-player-context-alist nil)
57 (defvar riece-hangman-words-buffer nil)
58
59 (defun riece-hangman-make-context (word)
60   "Make an instance of player context object.
61 This function is for internal use only."
62   (vector word nil 0))
63
64 (defun riece-hangman-context-word (context)
65   "Return the correct word of CONTEXT.
66 This function is for internal use only."
67   (aref context 0))
68
69 (defun riece-hangman-context-guessed (context)
70   "Return the guessed letters in this CONTEXT.
71 This function is for internal use only."
72   (aref context 1))
73
74 (defun riece-hangman-context-missed-count (context)
75   "Return the count of missed guesses in this CONTEXT.
76 This function is for internal use only."
77   (aref context 2))
78
79 (defun riece-hangman-context-set-guessed (context guessed)
80   "Set the GUESSED letters in this CONTEXT.
81 This function is for internal use only."
82   (aset context 1 guessed))
83
84 (defun riece-hangman-context-set-missed-count (context missed-count)
85   "Set the count of MISSED guesses in this CONTEXT.
86 This function is for internal use only."
87   (aset context 2 missed-count))
88
89 (defun riece-hangman-word ()
90   "Return random word.
91 The wordlist is read from `riece-hangman-words-file'."
92   (unless riece-hangman-words-buffer
93     (setq riece-hangman-words-buffer (generate-new-buffer " *riece-hangman*"))
94     (save-excursion
95       (set-buffer riece-hangman-words-buffer)
96       (buffer-disable-undo)
97       (insert-file-contents riece-hangman-words-file)
98       (let ((case-fold-search nil))
99         (delete-non-matching-lines "^[a-z][a-z][a-z][a-z][a-z][a-z]"))))
100   (save-excursion
101     (set-buffer riece-hangman-words-buffer)
102     (goto-char (% (1+ (random)) (buffer-size)))
103     (if (eobp)
104         (beginning-of-line -1)
105       (beginning-of-line))
106     (buffer-substring (point) (progn (end-of-line) (point)))))
107
108 (defun riece-hangman-reply (target string)
109   (riece-display-message
110    (riece-make-message (riece-make-identity riece-real-nickname
111                                             riece-server-name)
112                        (riece-make-identity target riece-server-name)
113                        string 'notice t))
114   (riece-send-string (format "NOTICE %s :%s\r\n" target string)))
115
116 (defun riece-hangman-reply-with-context (user target context)
117   (let ((masked-word (make-string
118                       (length (riece-hangman-context-word context))
119                       ?-))
120         (guessed (copy-sequence (riece-hangman-context-guessed context)))
121         (index 0))
122     (while (< index (length (riece-hangman-context-word context)))
123       (if (memq (aref (riece-hangman-context-word context) index) guessed)
124           (aset masked-word index
125                 (aref (riece-hangman-context-word context) index)))
126       (setq index (1+ index)))
127     (riece-hangman-reply
128      target
129      (format "%s: Word: %s, Guessed: %s"
130              user masked-word
131              (if guessed
132                  (apply #'string (sort guessed #'<))
133                "")))))
134
135 (defun riece-hangman-after-privmsg-hook (prefix string)
136   (let* ((user (riece-prefix-nickname prefix))
137          (parameters (riece-split-parameters string))
138          (targets (split-string (car parameters) ","))
139          (message (nth 1 parameters))
140          case-fold-search
141          pointer word guessed index)
142     (if (string-match riece-hangman-hello-regexp message)
143         (if (riece-identity-assoc user riece-hangman-player-context-alist t)
144             (riece-hangman-reply
145              (car targets)
146              (format "%s: You are already playing the game." user))
147           (let ((context (riece-hangman-make-context (riece-hangman-word))))
148             (setq riece-hangman-player-context-alist
149                   (cons (cons user context)
150                         riece-hangman-player-context-alist))
151             (riece-hangman-reply-with-context user (car targets) context)))
152       (if (string-match riece-hangman-bye-regexp message)
153           (when (setq pointer (riece-identity-assoc
154                                user riece-hangman-player-context-alist t))
155             (setq riece-hangman-player-context-alist
156                   (delq pointer riece-hangman-player-context-alist))
157             (riece-hangman-reply
158              (car targets)
159              (format "%s: Sorry, the word was \"%s\""
160                      user
161                      (riece-hangman-context-word (cdr pointer)))))
162         (if (setq pointer (riece-identity-assoc
163                            user riece-hangman-player-context-alist t))
164             (if (or (/= (length message) 1)
165                     (not (string-match "[a-z]" message)))
166                 (riece-hangman-reply
167                  (car targets)
168                  (format "%s: Not a valid guess: %s" user message))
169               (if (memq (aref message 0)
170                         (riece-hangman-context-guessed (cdr pointer)))
171                   (riece-hangman-reply (car targets)
172                                        (format "%s: Already guessed '%c'"
173                                                user (aref message 0)))
174                 (setq guessed (riece-hangman-context-set-guessed
175                                (cdr pointer)
176                                (cons (aref message 0)
177                                      (riece-hangman-context-guessed
178                                       (cdr pointer))))
179                       word (riece-hangman-context-word (cdr pointer)))
180                 (unless (catch 'found
181                           (setq index 0)
182                           (while (< index (length word))
183                             (if (eq (aref word index) (aref message 0))
184                                 (throw 'found t))
185                             (setq index (1+ index))))
186                   (riece-hangman-context-set-missed-count
187                    (cdr pointer)
188                    (1+ (riece-hangman-context-missed-count (cdr pointer)))))
189                 (if (>= (riece-hangman-context-missed-count (cdr pointer)) 7)
190                     (progn
191                       (riece-hangman-reply
192                        (car targets)
193                        (format "%s: Sorry, the word was \"%s\""
194                                user
195                                (riece-hangman-context-word (cdr pointer))))
196                       (setq riece-hangman-player-context-alist
197                             (delq pointer
198                                   riece-hangman-player-context-alist)))
199                   (if (catch 'missing
200                         (setq index 0)
201                         (while (< index (length word))
202                           (unless (memq (aref word index) guessed)
203                             (throw 'missing t))
204                           (setq index (1+ index))))
205                       (riece-hangman-reply-with-context user (car targets)
206                                                         (cdr pointer))
207                     (riece-hangman-reply (car targets)
208                                          (format "%s: You got it!" user))
209                     (setq riece-hangman-player-context-alist
210                           (delq pointer
211                                 riece-hangman-player-context-alist)))))))))))
212
213 (defun riece-hangman-insinuate ()
214   (add-hook 'riece-after-privmsg-hook 'riece-hangman-after-privmsg-hook))
215
216 (provide 'riece-hangman)
217
218 ;;; riece-hangman.el ends here