;;; riece-hangman.el --- hangman ;; Copyright (C) 1998-2004 Daiki Ueno ;; Author: Daiki Ueno ;; Keywords: IRC, riece ;; This file is part of Riece. ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 2, or (at your option) ;; any later version. ;; This program is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, ;; Boston, MA 02111-1307, USA. ;;; Commentary: ;; To use, add the following line to your ~/.riece/init.el: ;; (add-to-list 'riece-addons 'riece-hangman) ;;; Code: (require 'riece-globals) (require 'riece-identity) (require 'riece-message) (require 'riece-server) (defgroup riece-hangman nil "Interface to hangman.el" :prefix "riece-" :group 'riece) (defcustom riece-hangman-hello-regexp "^, hangman" "Pattern of string to start the game." :type 'string :group 'riece-hangman) (defcustom riece-hangman-bye-regexp "^, bye hangman" "Pattern of string to end the game." :type 'string :group 'riece-hangman) (defcustom riece-hangman-words-file "/usr/share/dict/words" "Location of words file." :type 'file :group 'riece-hangman) (defvar riece-hangman-player-context-alist nil) (defvar riece-hangman-words-buffer nil) (defvar riece-hangman-enabled nil) (defconst riece-hangman-description "Allow users in channel to play classic textual game \"hangman\"") (put 'riece-hangman 'riece-addon-default-disabled t) (defun riece-hangman-make-context (word) "Make an instance of player context object. This function is for internal use only." (vector word nil 0)) (defun riece-hangman-context-word (context) "Return the correct word of CONTEXT. This function is for internal use only." (aref context 0)) (defun riece-hangman-context-guessed (context) "Return the guessed letters in this CONTEXT. This function is for internal use only." (aref context 1)) (defun riece-hangman-context-missed-count (context) "Return the count of missed guesses in this CONTEXT. This function is for internal use only." (aref context 2)) (defun riece-hangman-context-set-guessed (context guessed) "Set the GUESSED letters in this CONTEXT. This function is for internal use only." (aset context 1 guessed)) (defun riece-hangman-context-set-missed-count (context missed-count) "Set the count of MISSED guesses in this CONTEXT. This function is for internal use only." (aset context 2 missed-count)) (defun riece-hangman-word () "Return random word. The wordlist is read from `riece-hangman-words-file'." (unless riece-hangman-words-buffer (setq riece-hangman-words-buffer (generate-new-buffer " *riece-hangman*")) (save-excursion (set-buffer riece-hangman-words-buffer) (buffer-disable-undo) (insert-file-contents riece-hangman-words-file) (let ((case-fold-search nil)) (delete-non-matching-lines "^[a-z][a-z][a-z][a-z][a-z][a-z]+")))) (save-excursion (set-buffer riece-hangman-words-buffer) (goto-char (% (1+ (random)) (buffer-size))) (if (eobp) (beginning-of-line -1) (beginning-of-line)) (buffer-substring (point) (progn (end-of-line) (point))))) (defun riece-hangman-reply (target string) (riece-display-message (riece-make-message (riece-make-identity riece-real-nickname riece-server-name) (riece-make-identity target riece-server-name) string 'notice t)) (riece-send-string (format "NOTICE %s :%s\r\n" target string))) (defun riece-hangman-reply-with-context (user target context) (let ((masked-word (make-string (length (riece-hangman-context-word context)) ?-)) (guessed (copy-sequence (riece-hangman-context-guessed context))) (index 0)) (while (< index (length (riece-hangman-context-word context))) (if (memq (aref (riece-hangman-context-word context) index) guessed) (aset masked-word index (aref (riece-hangman-context-word context) index))) (setq index (1+ index))) (riece-hangman-reply target (format "%s: Word: %s, Guessed: %s" user masked-word (if guessed (apply #'string (sort guessed #'<)) ""))))) (defun riece-hangman-after-privmsg-hook (prefix string) (if riece-hangman-enabled (let* ((user (riece-prefix-nickname prefix)) (parameters (riece-split-parameters string)) (targets (split-string (car parameters) ",")) (message (nth 1 parameters)) case-fold-search pointer word guessed index) (if (string-match riece-hangman-hello-regexp message) (if (riece-identity-assoc user riece-hangman-player-context-alist t) (riece-hangman-reply (car targets) (format "%s: You are already playing the game." user)) (let ((context (riece-hangman-make-context (riece-hangman-word)))) (setq riece-hangman-player-context-alist (cons (cons user context) riece-hangman-player-context-alist)) (riece-hangman-reply-with-context user (car targets) context))) (if (string-match riece-hangman-bye-regexp message) (when (setq pointer (riece-identity-assoc user riece-hangman-player-context-alist t)) (setq riece-hangman-player-context-alist (delq pointer riece-hangman-player-context-alist)) (riece-hangman-reply (car targets) (format "%s: Sorry, the word was \"%s\"" user (riece-hangman-context-word (cdr pointer))))) (if (setq pointer (riece-identity-assoc user riece-hangman-player-context-alist t)) (if (or (/= (length message) 1) (not (string-match "[a-z]" message))) (riece-hangman-reply (car targets) (format "%s: Not a valid guess: %s" user message)) (if (memq (aref message 0) (riece-hangman-context-guessed (cdr pointer))) (riece-hangman-reply (car targets) (format "%s: Already guessed '%c'" user (aref message 0))) (setq guessed (riece-hangman-context-set-guessed (cdr pointer) (cons (aref message 0) (riece-hangman-context-guessed (cdr pointer)))) word (riece-hangman-context-word (cdr pointer))) (unless (catch 'found (setq index 0) (while (< index (length word)) (if (eq (aref word index) (aref message 0)) (throw 'found t)) (setq index (1+ index)))) (riece-hangman-context-set-missed-count (cdr pointer) (1+ (riece-hangman-context-missed-count (cdr pointer))))) (if (>= (riece-hangman-context-missed-count (cdr pointer)) 7) (progn (riece-hangman-reply (car targets) (format "%s: Sorry, the word was \"%s\"" user (riece-hangman-context-word (cdr pointer)))) (setq riece-hangman-player-context-alist (delq pointer riece-hangman-player-context-alist))) (if (catch 'missing (setq index 0) (while (< index (length word)) (unless (memq (aref word index) guessed) (throw 'missing t)) (setq index (1+ index)))) (riece-hangman-reply-with-context user (car targets) (cdr pointer)) (riece-hangman-reply (car targets) (format "%s: You got it!" user)) (setq riece-hangman-player-context-alist (delq pointer riece-hangman-player-context-alist)))))))))))) (defun riece-hangman-insinuate () (add-hook 'riece-after-privmsg-hook 'riece-hangman-after-privmsg-hook)) (defun riece-hangman-enable () (setq riece-hangman-enabled t)) (defun riece-hangman-disable () (setq riece-hangman-enabled nil)) (provide 'riece-hangman) ;;; riece-hangman.el ends here