Initial commit on github to give this project a somewhat more 'permanent' home

Signed-off-by: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
This commit is contained in:
Gwenhael Le Moine 2009-05-12 13:18:50 +07:00
commit f7adc8384e
27 changed files with 835 additions and 0 deletions

54
INSTALL Normal file
View file

@ -0,0 +1,54 @@
======================================================================
INSTALLATION NOTES FOR EMACS EMSTAR
2008, Gwenhael Le Moine <gwenhael.le.moine!gmail.com>
======================================================================
Copy `emstar.el' anywhere you like, best in a directory, which is in
the default load-path of your emacs.
Copy the directory `emstar-levels' and it's content anywhere you
like, the default configuration of Emacs Emstar expects it in
/usr/local/share/
Add the following lines to your .emacs file:
(autoload 'emstar "emstar.el"
"Start a new game of Emstar." t)
(autoload 'emstar-mode "emstar.el"
"Play Emstar in current buffer." t)
If you put `emstar.el' in a place which is not in your load-path you
have to write the full path like "/path/to/emstar.el" instead of
"emstar.el".
If you put the emstar-levels in a other directory than
/usr/local/share you must configure `emstar-levels-dir' in your
.emacs to point to the proper place:
(setq emstar-levels-dir "/path/to/emstar-levels")
This can also be set using emacs customize feature.
Player files
============
By default Emacs Emstar saves player-files to /tmp. These files hold
the best results for each player and the last level each player finished.
If you want your player files to be put in another place set the value
of `emstar-playerfiles-dir' appropriate, either in your .emacs file
with:
(setq emstar-playerfiles-dir "/path/to/emstar-playerfiles")
or using the emacs customize feature.
IMPORTANT NOTE: The directory holding the playerfiles must be
writeable for all players of Emacs Emstar. So it should be a
dedicated directory with access permissions set to 1777 on *nix
systems.
You can turn of writing of playerfiles by setting
`emstar-playerfiles-dir' to nil, but this will disable some features,
such as best players listing.

View file

@ -0,0 +1,9 @@
################
#@## *#H#
# * ###
# ##* #
# ## * ##
## * * * #
# * *## * #
# ##* *#
################

View file

@ -0,0 +1,9 @@
###########
#### * #
# H ###* *# *#
# * #* #* #
# # * # *#
#*#* # *# #@#
#* ### ###
# # # #
######### # #

View file

@ -0,0 +1,9 @@
################
# # @#
# #** ** ##
## * ## *#
#* #*#** ###
## ## ## #
#* *# * H *#
##*### # ##
## ###########

View file

@ -0,0 +1,9 @@
## ## ####
#@#####* ### *##
# ** * #
# ## ##* #*# #
# # * ###* ## #
# ## ## #H# #
# * #
# * #
################

View file

@ -0,0 +1,9 @@
##############
# @# * ##
# # #* *## #
# * # #
# * #*#
# # * #
## * * #*#
#H # * # # #
##############

View file

@ -0,0 +1,9 @@
################
#*#* *#*#
# *#@ ## #
# H * #
# *# #
# * #
# *# # #
#*#* *#*#
################

View file

@ -0,0 +1,9 @@
###### #######
# *# * #
# # * # # * #
# @# #** #* #
# # # * H# #
#* # #* #
# * #
#* *#
##############

View file

@ -0,0 +1,9 @@
################
## H#* * *#
#* @*#* ##
## ### * ##
## *#*# #
#** *#* #
## * ####* #
##*# # #
################

View file

@ -0,0 +1,9 @@
################
# *# #@ #
# # *#**#* # #
# #*##*# * #
# *# *# #
# *#* *# #
# # # ##*# # #
# * #* H #
################

View file

@ -0,0 +1,9 @@
################
# * * H# #
# #*#* #* #
# #*# #* #
# * # *#* #
# #*# # *# #
# *#* # * # #
#*#@ # # #
################

View file

@ -0,0 +1,9 @@
################
#* ## ##*#
# # # #* #
# *# *## * #
# # #* #
# # *# #
# ## *# ##* #H#
# *# #* ##@#
################

View file

@ -0,0 +1,9 @@
# # # # # ##
# * @#
#* #* *
# # * * # #
# * #
# #H# * #
# # # #**#
# #
# # #

View file

@ -0,0 +1,9 @@
################
# *#* #
##* *# ##* ##
# # # * # # #
# H # ## # @*#
# # # * # # #
## *## #* *##
# *#* #
################

View file

@ -0,0 +1,9 @@
################
# ### * ##
# # # ##
# ##* * #
# * * * ##
# # ###* #
# * * @ H * **#
################

View file

@ -0,0 +1,9 @@
################
#*# #*# #* # #
# # #
#* # #* * #
## #* * ###
# * # ###* #
# #@#H * #
################

View file

@ -0,0 +1,9 @@
##############
# # #*# #* # #
# * # #
## # * #* #
# #* # ** * #
##* # ## * #
# #@#H * #
##############

View file

@ -0,0 +1,9 @@
################
# # ##
# ##* * ##*##
# #* *# ###
# ** *# ## #
# #* * # ## #
# ## @#H###**#
################

View file

@ -0,0 +1,9 @@
################
# # #
# * ##* * #
# #* * ## #
# * ## #* #
# #* *# * #
# ##* #@ H #
################

View file

@ -0,0 +1,9 @@
################
# *#@#
# ## ##H#
# #* * #
# * *## *#
# #* * *# *##
# ##* #* * *###
#* ##* #
################

View file

@ -0,0 +1,9 @@
################
# #H#
# # #
##*#* *#*#*#*#*#
# # #* *# # # ##
##*#*#* *#*#*#*#
# # #
# # #@ #
################

View file

@ -0,0 +1,9 @@
##############
#@ # # # #
# #* # * * # #
## # # #
#* #*# ##
## # * # #
#*# # # # #H#
# # *# #*#
##############

View file

@ -0,0 +1,9 @@
############
# * #* *#
# * # ##
# * #
#@ * #
## * # ##
# * # #
#H # * ##* #
################

View file

@ -0,0 +1,9 @@
################
# #
## ### #* ##*#
#* #* # # # #
# # ### ##
## # #*# #*#
# #
# @#* H #*#
################

View file

@ -0,0 +1,9 @@
###############
# *## ##
# #* ## * #
# *## # #* #
## ## #*# #
## # *#* #
#*H*# * #@# #
## #
###############

View file

@ -0,0 +1,9 @@
# ###########
#*#* # @#
#* *# * #
# # *## *# #
# #* #*H* *#
# *## #
#*#* #
# #
############

556
emstar.el Normal file
View file

@ -0,0 +1,556 @@
;;; emstar.el --- Emstar Game
;; Copyright (C) 2008 Gwenhael Le Moine
;; Author: Gwenhael Le Moine <gwenhael.le.moine@gmail.com>
;; Keywords: games
;; This file 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 3, or (at your option)
;; any later version.
;; This file 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:
;; Play Emstar in emacs.
;; Heavily based on emacs-sokoban
;;; Code:
(require 'cl)
(defconst emstar-version "0.1"
"Version string for this version of GNU-Emacs Emstar.")
(defconst emstar-left '(-1 . 0))
(defconst emstar-right '( 1 . 0))
(defconst emstar-down '( 0 . 1))
(defconst emstar-up '( 0 . -1))
(defconst emstar-eater "eater")
(defconst emstar-stopper "stopper")
(defgroup emstar nil
"Emstar game for GNU Emacs."
:prefix "emstar-"
:group 'games)
(defcustom emstar-playerfiles-dir "/tmp/"
"*The directory holding the emstar playerfiles.
Emstar saves the information from `emstar-player-stats' to a
playerfile in this directory. If you don't want to use
playerfiles, set value to NIL."
:group 'emstar
:type 'string)
(defvar emstar-player-stats nil
"Alist with player specific information as saved in the playerfiles.
This holds the best results for each finished level and the
players current level.")
(defconst emstar-playerfile-prefix "emstar-pl-"
"The prefix used for emstar playerfiles.")
(defvar emstar-best-players-list nil
"A list with the best result for each level
generated from all available playerfiles, if `emstar-playerfiles-dir'
is none nil.")
(defcustom emstar-levels-dir "/usr/local/share/emstar/emstar-levels"
"*Directory holding the emstar level files"
:group 'emstar
:type 'string)
(defcustom emstar-levels-basename "emstar-lvl."
"*Basename of the emstar level files"
:group 'emstar
:type 'string)
(defcustom emstar-start-level 1
"*Defines the level-numver to start with.
This might be overwritten by the last level played,
as saved in the playerfile."
:group 'emstar
:type 'integer)
(defcustom emstar-undo-penalty 3
"*Defines the number of moves one undo costs."
:group 'emstar
:type 'integer)
(defcustom emstar-eater-char ?@
"*Defines the character used to diplay the eater."
:group 'emstar
:type 'character)
(defcustom emstar-gift-char ?*
"*Defines the character used to diplay the gifts."
:group 'emstar
:type 'character)
(defcustom emstar-stopper-char ?H
"*Defines the character used to diplay the stopper."
:group 'emstar
:type 'character)
(defcustom emstar-wall-char ?#
"*Defines the character used to diplay the walls."
:group 'emstar
:type 'character)
(defface emstar-eater-face
'((t (:foreground "green"
:weight bold)))
"*Face used display the eater in emstar game."
:group 'emstar)
(defface emstar-stopper-face
'((t (:foreground "red"
:weight bold)))
"*Face used display the stopper in emstar game."
:group 'emstar)
(defface emstar-gift-face
'((t (:foreground "yellow"
:weight bold)))
"*Face used display gifts in emstar game."
:group 'emstar)
(defface emstar-wall-face
'((t (:foreground "blue")))
"*Face used display walls in emstar game."
:group 'emstar)
(defvar emstar-eater-face 'emstar-eater-face)
(defvar emstar-stopper-face 'emstar-stopper-face)
(defvar emstar-gift-face 'emstar-gift-face)
(defvar emstar-wall-face 'emstar-wall-face)
(defconst emstar-font-lock-keywords
`((,(regexp-quote (char-to-string emstar-eater-char))
. emstar-eater-face)
(,(regexp-quote (char-to-string emstar-stopper-char))
. emstar-stopper-face)
(,(regexp-quote (char-to-string emstar-gift-char))
. emstar-gift-face)
(,(regexp-quote (char-to-string emstar-wall-char))
. emstar-wall-face))
"Stuff to highlight in emstar.")
(defvar emstar-mode-map nil
"Keymap for emstar.")
(defvar emstar-selected 'emstar-eater
"Currently selected piece.")
(setq emstar-mode-map (make-sparse-keymap))
(define-key emstar-mode-map [up] 'emstar-move-up)
(define-key emstar-mode-map [down] 'emstar-move-down)
(define-key emstar-mode-map [left] 'emstar-move-left)
(define-key emstar-mode-map [right] 'emstar-move-right)
(define-key emstar-mode-map "u" 'emstar-undo)
(define-key emstar-mode-map "b" 'emstar-display-best-players-list)
(define-key emstar-mode-map ">" 'emstar-goto-next-level)
(define-key emstar-mode-map "n" 'emstar-goto-next-level)
(define-key emstar-mode-map "<" 'emstar-goto-prev-level)
(define-key emstar-mode-map "p" 'emstar-goto-prev-level)
(define-key emstar-mode-map " " 'emstar-switch-selected)
(define-key emstar-mode-map "r" 'emstar-reload-level)
(defvar emstar-collected-gifts 0
"Number of gifts collected. Buffer-local in emstar-mode.")
(defvar emstar-total-gifts 0
"Total number of gifts. Buffer-local in emstar-mode.")
(defvar emstar-level nil
"Number of current level. Buffer-local in emstar games.")
(defvar emstar-moves nil
"Number of moves made by player. Buffer-local in emstar-mode.")
(defvar emstar-pos nil
"Current position of player. Buffer-local in emstar-mode.")
(defvar emstar-last-pos nil
"Backup of last player position. Buffer-local in emstar-mode.")
(defvar emstar-game-info nil
"String with infos to the current game. Buffer-local in emstar-mode.")
(defvar emstar-level-best-string nil
"String holding the best result for the current level as displayed.")
(defun emstar-forward-line (arg)
"Like forward-line but preserve the current column.
The implementation is rather simple, as we can make certain
assumptions about the structure of a valid emstar level buffer."
(let ((goal-column (current-column)))
(forward-line arg)
(move-to-column goal-column)))
(defun emstar-paint (char)
"Insert char at point, overwriting the old char.
Extreme simple, but sufficient for our needs."
(let ((inhibit-read-only t))
(delete-char 1)
(insert (char-to-string char))
(forward-char -1))
t)
(defun emstar-count-gifts ()
(setq emstar-total-gifts 0)
(goto-char (point-min))
(while (search-forward (char-to-string emstar-gift-char) nil t)
(setq emstar-total-gifts (1+ emstar-total-gifts))))
(defun emstar-refresh-collected-gifts ()
(setq emstar-collected-gifts 0)
(goto-char (point-min))
(while (search-forward (char-to-string emstar-gift-char) nil t)
(setq emstar-collected-gifts (1+ emstar-collected-gifts)))
(setq emstar-collected-gifts (- emstar-total-gifts emstar-collected-gifts )))
(defun emstar-update-score (level moves)
"Save number of moves for level to `emstar-player-stats'."
(let* ((level-name (concat emstar-levels-basename
(number-to-string level)))
(entry (assoc level-name emstar-player-stats)))
(if entry
(or (< (cdr entry) moves) (setcdr entry moves))
(push (cons level-name moves) emstar-player-stats))))
(defun emstar-get-level-best (level &optional list)
"Get best result for level from `emstar-player-stats'."
(if level
(let* ((level-name (concat emstar-levels-basename
(number-to-string level)))
(entry (assoc level-name
(or list emstar-player-stats))))
(if entry
(cdr entry)))))
(defun emstar-update-current-level (level)
"Save current level to `emstar-player-stats'."
(let ((entry (assoc :level emstar-player-stats)))
(if entry
(setcdr entry level)
(push (cons :level level) emstar-player-stats))))
(defun emstar-save-playerfile ()
"Save `emstar-player-stats' to playerfile."
(if emstar-playerfiles-dir
(let ((filename (concat emstar-playerfiles-dir "/"
emstar-playerfile-prefix
(user-login-name))))
(with-temp-file filename
(prin1 emstar-player-stats (current-buffer)))
(set-file-modes filename #o644))))
(defun emstar-load-playerfile ()
"Load `emstar-player-stats' from playerfile."
(if emstar-playerfiles-dir
(let ((filename (concat emstar-playerfiles-dir "/"
emstar-playerfile-prefix
(user-login-name))))
(if (file-readable-p filename)
(with-temp-buffer
(insert-file-contents filename nil)
(setq emstar-player-stats
(read (current-buffer))))))))
(defun emstar-gen-best-players-list ()
(if emstar-playerfiles-dir
(let ((files (directory-files emstar-playerfiles-dir
t (concat "^" emstar-playerfile-prefix)
t)))
(dolist (filename files)
(if (file-readable-p filename)
(with-temp-buffer
(insert-file-contents filename nil)
(let ((stats (read (current-buffer)))
(player (substring (file-name-nondirectory filename)
(1- (length emstar-levels-basename)))))
(dolist (entry stats)
(let* ((level-name (car entry))
(best-entry (assoc level-name
emstar-best-players-list)))
(if (and (stringp level-name)
(compare-strings level-name
0 (length emstar-levels-basename)
emstar-levels-basename
0 nil))
(cond ((and best-entry
(> (cadr best-entry) (cdr entry)))
(setcdr best-entry
(cons (cdr entry) player)))
((or (not best-entry)
(= (cadr best-entry) (cdr entry)))
(push (cons level-name
(cons (cdr entry) player))
emstar-best-players-list)))))))))))))
(defun emstar-display-best-players-list ()
(interactive)
(if emstar-best-players-list
(progn
(switch-to-buffer (get-buffer-create "*Emstar Best Players*"))
(erase-buffer)
(dolist (entry emstar-best-players-list)
(let ((level-name (car entry)))
(if (and (stringp level-name)
(compare-strings level-name
0 (length emstar-levels-basename)
emstar-levels-basename
0 nil))
(insert (format "%4s: %5d - %s\n"
(substring level-name
(length emstar-levels-basename))
(cadr entry)
(cddr entry))))))
(sort-columns nil (point-min) (point-max)))
(error "No best players list available")))
(defun emstar-load-next-level (&optional arg)
"Load next level, with negative arg load previous level.
If requested level doesn't exist, load `emstar-start-level'."
(when (bound-and-true-p emstar-level)
(setq emstar-level (if (and arg (< arg 0))
(1- emstar-level)
(1+ emstar-level)))
(or (emstar-load-level emstar-level)
(progn
(setq emstar-level emstar-start-level)
(emstar-load-level emstar-level)))
(emstar-init-level)
t))
(defun emstar-level-finished ()
(message
(format "You finished Level %d in %d moves. Congratulations!"
(or (bound-and-true-p emstar-level) 0)
emstar-moves))
(when (bound-and-true-p emstar-level)
(emstar-update-score emstar-level emstar-moves))
(when (emstar-load-next-level)
(emstar-update-current-level emstar-level)
(emstar-save-playerfile)))
(defun emstar-find-current-pos ()
(goto-char (point-min))
(search-forward (char-to-string (if (equal emstar-selected emstar-eater)
emstar-eater-char
emstar-stopper-char)))
(forward-char -1)
(setq emstar-pos (point)))
(defun emstar-move-here ()
"Move player to point.
Move player char to point, repaint pits and evaluate game status."
(interactive)
(setq emstar-pos (point))
(emstar-paint (if (equal emstar-selected emstar-eater)
emstar-eater-char
emstar-stopper-char))
(goto-char emstar-last-pos)
(emstar-paint 32)
(setq emstar-moves (1+ emstar-moves))
(emstar-update-mode-line))
(defun emstar-move-eater (direction)
(goto-char emstar-pos)
(setq emstar-last-pos (point))
(while (progn
(setq emstar-pos (point))
(forward-char (car direction))
(emstar-forward-line (cdr direction))
(if (= (char-after) emstar-gift-char)
(progn
(setq emstar-collected-gifts (1+ emstar-collected-gifts))
(emstar-paint 32)))
(= (char-after) 32)))
(goto-char emstar-pos)
(if (or
(= (char-after) 32)
(= (char-after) emstar-gift-char))
(emstar-move-here))
(if (= emstar-total-gifts emstar-collected-gifts)
(emstar-level-finished)))
(defun emstar-move-stopper (direction)
(goto-char emstar-pos)
(setq emstar-last-pos (point))
(while (progn
(setq emstar-pos (point))
(forward-char (car direction))
(emstar-forward-line (cdr direction))
(= (char-after) 32)))
(goto-char emstar-pos)
(if (= (char-after) 32)
(emstar-move-here)))
(defun emstar-move-up ()
"Move the player up if possible."
(interactive)
(if (equal emstar-selected emstar-eater)
(emstar-move-eater emstar-up)
(emstar-move-stopper emstar-up)))
(defun emstar-move-down ()
"Move the player down if possible."
(interactive)
(if (equal emstar-selected emstar-eater)
(emstar-move-eater emstar-down)
(emstar-move-stopper emstar-down)))
(defun emstar-move-left ()
"Move the player left if possible."
(interactive)
(if (equal emstar-selected emstar-eater)
(emstar-move-eater emstar-left)
(emstar-move-stopper emstar-left)))
(defun emstar-move-right ()
"Move the player right if possible."
(interactive)
(if (equal emstar-selected emstar-eater)
(emstar-move-eater emstar-right)
(emstar-move-stopper emstar-right)))
(defun emstar-goto-next-level ()
"Jump to next level."
(interactive)
(emstar-load-next-level))
(defun emstar-goto-prev-level ()
"Jump to previous level."
(interactive)
(emstar-load-next-level -1))
(defun emstar-reload-level ()
"Jump to previous level."
(interactive)
(emstar-load-level emstar-level)
(emstar-init-level))
(defun emstar-switch-selected ()
"Switch the item moved."
(interactive)
(setq emstar-selected (if (equal emstar-selected emstar-eater)
emstar-stopper
emstar-eater))
(if (equal emstar-selected emstar-eater)
(progn
(set-face-inverse-video-p emstar-eater-face t)
(set-face-inverse-video-p emstar-stopper-face nil))
(progn
(set-face-inverse-video-p emstar-eater-face nil)
(set-face-inverse-video-p emstar-stopper-face t)))
(emstar-find-current-pos))
(defun emstar-update-mode-line ()
(setq emstar-game-info (format "Level:%d -- %d/%d -- Moves:%d"
(or (bound-and-true-p emstar-level)
0)
emstar-collected-gifts
emstar-total-gifts
emstar-moves
(or emstar-level-best-string ""))))
(defun emstar-undo ()
(interactive)
(let ((inhibit-read-only t))
(undo))
(emstar-find-current-pos)
(setq emstar-moves (+ emstar-moves emstar-undo-penalty))
(emstar-refresh-collected-gifts)
(emstar-update-mode-line))
(defun emstar-load-level (num)
"Load emstar level num."
(let ((inhibit-read-only t)
(level-file
(concat emstar-levels-dir "/"
emstar-levels-basename (number-to-string num))))
(when (file-exists-p level-file)
(insert-file-contents level-file nil nil nil t)
t)))
(defun emstar-init-level ()
"Initialize level elements."
(setq emstar-selected emstar-eater)
(set-face-inverse-video-p emstar-eater-face t)
(set-face-inverse-video-p emstar-stopper-face nil)
(setq emstar-moves 0)
(setq emstar-collected-gifts 0)
(setq emstar-total-gifts 0)
(setq emstar-level-best-string
(let ((best (emstar-get-level-best emstar-level))
(world-best (if emstar-best-players-list
(emstar-get-level-best
emstar-level
emstar-best-players-list))))
(if (or best world-best)
(format " [Best:%s%s]"
(if best (number-to-string best) "")
(if (and world-best
(or (not best)
(< (car world-best) best)))
(format " (%s:%d)"
(cdr world-best) (car world-best))
"")))))
(emstar-count-gifts)
(emstar-update-mode-line)
(emstar-find-current-pos)
(buffer-disable-undo (current-buffer))
(buffer-enable-undo)
)
;;;###autoload
(defun emstar-mode ()
"Major mode to play emstar.
Commands:
\\{emstar-mode-map}"
(interactive)
(kill-all-local-variables)
(toggle-read-only 1)
(use-local-map emstar-mode-map)
(make-local-variable 'font-lock-defaults)
(setq font-lock-defaults '(emstar-font-lock-keywords
t nil nil beginning-of-line))
(setq cursor-type nil)
(make-local-variable 'emstar-level)
(make-local-variable 'emstar-pos)
(make-local-variable 'emstar-last-pos)
(make-local-variable 'emstar-moves)
(make-local-variable 'emstar-collected-gifts)
(make-local-variable 'emstar-total-gifts)
(make-local-variable 'emstar-game-info)
(setq major-mode 'emstar-mode)
(setq mode-name "Emstar")
(setq header-line-format
(list "Emstar v" 'emstar-version
" -- " 'emstar-game-info " ~ " 'emstar-selected))
(emstar-init-level)
(run-hooks 'emstar-mode-hook))
;;;###autoload
(defun emstar ()
"Play emstar."
(interactive)
(switch-to-buffer (generate-new-buffer "*Emstar*"))
(emstar-load-playerfile)
(setq emstar-best-players-list nil)
(emstar-gen-best-players-list)
(let ((level (or (cdr (assoc :level emstar-player-stats))
emstar-start-level)))
(emstar-load-level level)
(emstar-mode)
(setq emstar-level level))
(emstar-init-level)
(emstar-update-mode-line))
(provide 'emstar)
;;; emstar.el ends here