Author: gmilare Date: Wed Jan 2 10:40:42 2008 New Revision: 12
Modified: feebs.tex main.lisp package.lisp rules.lisp system.lisp Log:
Modified: feebs.tex ============================================================================== --- feebs.tex (original) +++ feebs.tex Wed Jan 2 10:40:42 2008 @@ -1,18 +1,3 @@ -\documentclass[english]{article} -\usepackage[T1]{fontenc} -\usepackage[latin1]{inputenc} -\IfFileExists{url.sty}{\usepackage{url}} - {\newcommand{\url}{\texttt}} - -\makeatletter -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. -\newenvironment{lyxlist}[1] -{\begin{list}{} -{\settowidth{\labelwidth}{#1} - \setlength{\leftmargin}{\labelwidth} - \addtolength{\leftmargin}{\labelsep} - \renewcommand{\makelabel}[1]{##1\hfil}}} -{\end{list}}
% Copyright (c) 2007 Gustavo Henrique Milar� % @@ -31,7 +16,21 @@ % You should have received a copy of the GNU General Public License % along with The Feebs War. If not, see http://www.gnu.org/licenses/.
+\documentclass[english]{article} +\usepackage[T1]{fontenc} +\usepackage[latin1]{inputenc} +\IfFileExists{url.sty}{\usepackage{url}} + {\newcommand{\url}{\texttt}}
+\makeatletter +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands. +\newenvironment{lyxlist}[1] +{\begin{list}{} +{\settowidth{\labelwidth}{#1} + \setlength{\leftmargin}{\labelwidth} + \addtolength{\leftmargin}{\labelsep} + \renewcommand{\makelabel}[1]{##1\hfil}}} +{\end{list}}
\IfFileExists{url.sty}{\usepackage{url} @@ -110,12 +109,15 @@ in this case). That was only a reason to duplicate code and work, adding no results at all... \item Many functions and variables are changed and others were added -\item This document is more objective than the one provided with \textit{Planet +\item Documentation is more objective than the one provided with \textit{Planet of the Feebs}, and is fully compatible with the code. This way it is easier to understand the game. +\item Security is improved. Now it the behavior functions are allowed to store +and change structures and vectors passed to it. +The parameters can't be change by those functions while inside the game. \item It is possible now to extend the rules: the code is object oriented and -new rules, special moves, change the behavior of flames, etc. This manual -is just the beginning! +new rules, special moves, change the behavior of flames, etc, can be done +by adding new classes and/or methods. This manual is just the beginning! \end{itemize}
\section{The Game} @@ -162,18 +164,17 @@
\subsection{Throwing flame}
-If a feeb decides to throw a flame, and if it is prepared to, it will -spend energy, and the next turn there will be a flame in the square -in front of the feeb. For a few turns, the feeb will not be able to -throw flames. The turn after the feeb throws the flame, it is able -to see its own flame exactly in front of it, so it shouldn't move -forward. Each turn, the flame moves forward destroing mushrooms and +If a feeb decides to throw a flame, if it is prepared to and has +enough energy, the next turn there will be a flame in the square +in front of the feeb, and it will see it, so the feeb shouldn't move +forward. For a few turns, the feeb will not be able to +throw flames. Each turn, the flame moves forward destroing mushrooms and killing feebs it encounters, transforming them into carcass. If there is a wall, the flame can reflect, and, if so, it will turn 180 degrees.
Once a feeb is killed (or starves), in it's place in the maze there will appear -a carcass. The feeb goes to the end of the dead feebs line. After a while -the first feeb in line will reincarnate. So, dying is not so terrible. +a carcass. The feeb goes to the end of the dead feebs line. When the +carcass rots, the first feeb in line reincarnates. So, dying is not so terrible.
These are the parameters related to flames:
@@ -198,7 +199,8 @@
There are two kinds of food, carcasses and mushrooms. Carcasses usually give less energy than mushrooms, and may rot, but, while it does not -rot, a feeb can feed as long as it wishes. By eating food, the feeb +rot, a feeb can feed as long as it wishes. Mushrooms disapear after +being eaten. By eating food, the feeb will be able to recover energy, wich is important because, if a feeb stays with 0 or less units of energy, it starves.
@@ -339,10 +341,12 @@ \subsubsection{Proximity and vision}
The brain receives also information about what is near the feeb and -what the feeb sees. +what the feeb sees. We note that, contrary to \emph{Planet of the Feebs}, +it is safe to change anything inside these structures, so you are +alowed to keep them stored and to modify them as you wish.
The structure \textsf{\emph{proximity}} has the contents of the squares -near the feeb, not affected by peeking, with these fields: +near the feeb (not affected by peeking) with these fields:
\begin{lyxlist}{00.00.0000} \item [{\textsf{\textbf{(my-square}}\textsf{\emph{~proximity}}\textsf{\textbf{)}}}] \begin{flushleft} @@ -389,7 +393,8 @@
Both fireballs and feebs that are given to the brain function are not the real ones, but just images with contents that the brain function -can access. +can access. It is allowed to keep and change its contents because they +doesn't represent anything.
These are the fields available:
Modified: main.lisp ============================================================================== --- main.lisp (original) +++ main.lisp Wed Jan 2 10:40:42 2008 @@ -27,11 +27,7 @@ (defun rot-carcass-p (time) t)
-(defun reincarnate-feeb-p (feeb) - t) - (defun finish-game-p () - ;; This is a little dangerous... nil)
@@ -53,7 +49,8 @@ (gethash name parameters))
(defun change-parameter (name value) - (setf (car (gethash name parameters)) value)) + (unless *playing-feeb* + (setf (car (gethash name parameters)) value)))
(defmethod documentation (name (type (eql 'feeb-parameter))) (cdr (gethash name parameters))) @@ -244,11 +241,14 @@ (dotimes (i mushrooms) (let ((site (pop m-sites))) (unless (member #'fireball-p) - (create-mushroom (car site) (cdr site))))) + (create-mushroom (car site) (cdr site)))))) ;; Maybe rot some carcasses (dolist (carc (prog1 *carcasses* (setf *carcasses* nil))) - (unless (rot-carcass (first carc) (second carc) (third carc)) + (if (rot-carcass-p (first carc)) + (progn + (delete-object :carcass (second carc) (third carc)) + (reincarnate-feeb (pop *dead-feebs*))) (progn (incf (first carc)) (push carc *carcasses*)))) @@ -256,22 +256,19 @@ (dolist (fireball *fireballs-flying*) (move-object fireball (make-move-choice fireball))) (dolist (feeb *feebs*) - (if (feeb-dead-p feeb) - ;; Reincarnate some feebs (if the rules allow it) - (reincarnate-feeb feeb) - (progn - ;; Starve the feeb: - (when (<= (decf (feeb-energy-reserve feeb)) 0) - (destroy-object feeb :starve)) - ;; Compute vision for the feeb: - (compute-vision feeb)))) + ;; Starve the feeb: + (when (<= (decf (feeb-energy-reserve feeb)) 0) + (destroy-object feeb :starve))) (dolist (*playing-feeb* *feebs*) - (unless (feeb-dead-p *playing-feeb*) - ;; Collect the feeb's move - (move-object *playing-feeb* - (prog1 - (setf (feeb-last-move *playing-feeb*) - (make-move-choice *playing-feeb*)) - (setf (feeb-peeking *playing-feeb*) nil)))))))) - -) ; end of let ((mushrooms 1)) + ;; Compute vision for the feeb: + (compute-vision feeb) + ;; Lets the feeb make a choice + (setf (feeb-last-move *playing-feeb*) + (make-move-choice *playing-feeb*) + (feeb-peeking *playing-feeb*) nil)) + ;; binds the variable to the current playing feeb + (dolist (feeb *feebs*) + ;; Collect the feeb's move + (move-object feeb (feeb-last-move feeb)))) + + ) ; end of let ((mushrooms 1))
Modified: package.lisp ============================================================================== --- package.lisp (original) +++ package.lisp Wed Jan 2 10:40:42 2008 @@ -113,7 +113,7 @@ wallp chance
;; Graphics for alpha release - simple-play print-map)) + simple-play))
(in-package :feebs)
Modified: rules.lisp ============================================================================== --- rules.lisp (original) +++ rules.lisp Wed Jan 2 10:40:42 2008 @@ -23,71 +23,78 @@
+;;; -*- General Rules -*- + (def-feeb-parm 'game-length 320 "Number of turns the game will last.")
(def-feeb-parm 'number-of-mushrooms 3 "Maximum number of mushrooms created each turn.")
-(let (turn-number) +(let (turn-number total-time) + ;; Function redefinitions + (defun start-round () - (setf turn-number 0) - (number-of-mushrooms - (random (1+ (get-feeb-parm 'number-of-mushrooms))))) + (setf turn-number 0))
(defun start-turn () - (incf turn-number)) + (incf turn-number) + (setf total-time 0) + (number-of-mushrooms + (random (1+ (get-feeb-parm 'number-of-mushrooms)))))
(defun finish-game-p () - (>= (get-feeb-parm 'game-length) turn-number))) + (= (get-feeb-parm 'game-length) turn-number))
-(def-feeb-parm 'slow-feeb-noop-switch nil - "If is non-nil, there is a possibility that the move -of a feeb is aborted according to its function evaluation -time.") + (defun inc-total-time (time) + (incf time total-time))
-(def-feeb-parm 'slow-feeb-noop-factor 1/4 - "The probability of the feeb to abort will be this factor -times the amount of time the feeb takes to have a decision, -divided by the total time taken by all the feebs in the -current turn, or by a reference time.") + (defun total-time () + total-time))
-(def-feeb-parm 'reference-time nil - "Time taken by reference if non-nil. See slow-feeb-noop-factor.") +;;; Detecting if feeb is playing
(def-feeb-parm 'sense-location-p t "If nil, x-position and y-position will return nil when someone tries to invoke it. Otherwise return the position.")
-;;; Scoring: +(defmethod x-position :around ((fb feeb)) + (if (get-feeb-parm 'sense-location-p) + (call-next-method)))
-(def-feeb-parm 'points-for-killing 5 - "How many points some feeb earn for killing someone.") +(defmethod y-position :around ((fb feeb)) + (if (get-feeb-parm 'sense-location-p) + (call-next-method)))
-(def-feeb-parm 'points-for-dying -3 - "How many points some feeb earn for dying (usually negative).")
-(def-feeb-parm 'points-for-slow-down -1 - "Points earned when a feeb's move is aborted due to slowness.")
+;;; -*- Being Born and Dying -*-
-;;; Energies: +;;; Being Born / Reincarnating
-(def-feeb-parm 'flame-energy 10 - "Amount of energy lost after throwing a flame.") +(def-feeb-parm 'starting-energy 50 + "Smallest amount of energy a feeb will start with.")
-(def-feeb-parm 'mushroom-energy 50 - "Amount of energy recovered when the feeb eats a mushroom.") +(defmethod create-object :before ((feeb feeb) x y) + (setf (feeb-energy-reserve feeb) + (get-feeb-parm 'starting-energy) + (feeb-ready-to-fire feeb) t))
-(def-feeb-parm 'carcass-energy 30 - "Amount of energy recovered each turn that the feeb -eats a carcass.") +;;; Dying and Killing
-(def-feeb-parm 'maximum-energy 100 - "The most energy a feeb can accumulate.") +(def-feeb-parm 'points-for-dying -3 + "How many points some feeb earn for dying (usually negative).")
-(def-feeb-parm 'starting-energy 50 - "Smallest amount of energy a feeb will start with.") +(defmethod destroy-object :before ((feeb feeb) cause) + (incf (feeb-score feeb) (get-feeb-parm 'points-for-dying))) + +(def-feeb-parm 'points-for-killing 5 + "How many points some feeb earn for killing someone.") + +(defmethod destroy-object :before ((feeb feeb) (fireball fireball)) + (unless (eq (fireball-owner fireball) feeb) + (incf (feeb-score (fireball-owner fireball)) + (get-feeb-parm 'points-for-killing))))
;;; Carcasses:
@@ -99,6 +106,13 @@ (def-feeb-parm 'carcass-rot-probability 1/3 "Probability of the carcass to rot, after the apropriate time.")
+(defun rot-carcass-p (time) + (and (> time (get-feeb-parm 'carcass-guaranteed-lifetime)) + (chance (get-feeb-parm 'carcass-rot-probability)))) + + + +;;; -*- Movement Choice -*-
;;; Fireballs:
@@ -109,6 +123,19 @@ (def-feeb-parm 'fireball-reflection-probability 2/3 "Probability of the flame to reflect when encountering a wall.")
+(defmethod make-move-choice ((fireball fireball)) + (cond + ((wallp (get-forward-pos fireball)) + (if (chance (get-feeb-parm 'fireball-reflection-probability)) + :turn-around + :dissipate)) + ((chance (get-feeb-parm 'fireball-dissipation-probability)) + :dissipate) + (t :move-forward))) + + +;;; Feebs + (deef-feeb-parm 'flame-no-recovery-time 2 "Probability of the feeb to recover the hability to throw a flame, after the apropriate @@ -117,3 +144,103 @@ (def-feeb-parm 'flame-recovery-probability 1/3 "Probability of the feeb to recover the hability to throw a flame, after the apropriate time.") + +(defmethod make-move-choice :around ((feeb feeb)) + (inc-total-time + (setf (feeb-time feeb) + (+ (- (get-intenal-real-time)) + (progn + (call-next-method) + (get-intenal-real-time))))) + (unless (feeb-ready-to-fire feeb) + (and (> (feeb-turns-since-flamed feebs) + (get-feeb-parm 'flame-no-recovery-time)) + (chance (get-feeb-parm 'flame-recovery-probability)) + (setf (feeb-ready-to-fire feeb) t)))) + + + +;;; -*- Moving -*- + +;;; Fireball + +(defmethod make-move :before ((fireball fireball) (move (eql :move-forward))) + (multiple-value-bind (stuff x-pos y-pos) + (get-forward-pos fireball) + (dolist (thing stuff) + (typecase thing + (feeb (destroy-object thing fireball)) + ((eql :mushroom) + (delete-object thing x-pos y-pos)))))) + + +;;; Feebs + +(def-feeb-parm 'slow-feeb-noop-switch nil + "If is non-nil, there is a possibility that the move +of a feeb is aborted according to its function evaluation +time.") + +(def-feeb-parm 'slow-feeb-noop-factor 1/4 + "The probability of the feeb to abort will be this factor +times the amount of time the feeb takes to have a decision, +divided by the total time taken by all the feebs in the +current turn, or divided by a reference time.") + +(def-feeb-parm 'reference-time nil + "Time taken by reference if non-nil. See slow-feeb-noop-factor.") + +(def-feeb-parm 'points-for-slow-down -1 + "Points earned when a feeb's move is aborted due to slowness.") + +(defmethod make-move :around ((feeb feeb) move) + (if (get-feeb-parm 'slow-feeb-noop-switch) + (if (chance (* (get-feeb-parm 'slow-feeb-noop-factor) + (/ (feeb-time feeb) + (or (get-feeb-parm 'reference-time) + (total-time))))) + (prog1 nil ; in case that the move was eating something + (incf (feeb-score feeb) (get-feeb-parm 'points-for-slow-down))) + (call-next-method)) + (call-next-method))) + +(defmethod make-move :around ((feeb feeb) (move (eql :move-forward))) + (let ((thing (find-if #'fireball-p (get-forward-pos feeb)))) + (if thing + (destroy-object feeb thing) + (call-next-method)))) + + +;;; Eating + +(def-feeb-parm 'maximum-energy 100 + "The most energy a feeb can accumulate.") + +(def-feeb-parm 'mushroom-energy 50 + "Amount of energy recovered when the feeb eats a mushroom.") + +(defmethod make-move :around ((feeb feeb) (move (eql :eat-mushroom))) + (when (call-next-method) ; was eating successfull? + (setf (feeb-energy-reserve feeb) + (min (+ (feeb-energy-reserve feeb) + (get-feeb-parm 'mushroom-energy)) + (get-feeb-parm 'maximum-energy))))) + +(def-feeb-parm 'carcass-energy 30 + "Amount of energy recovered each turn that the feeb +eats a carcass.") + +(defmethod make-move :around ((feeb feeb) (move (eql :eat-carcass))) + (when (call-next-method) + (setf (feeb-energy-reserve feeb) + (min (+ (feeb-energy-reserve feeb) + (get-feeb-parm 'carcass-energy)) + (get-feeb-parm 'maximum-energy))))) + +(def-feeb-parm 'flame-energy 10 + "Amount of energy lost after throwing a flame.") + +(defmethod make-move :around ((feeb feeb) (move (eql :flame))) + (when (>= (feeb-energy-reserve feeb) (get-feeb-parm 'flame-energy)) + (decf (feeb-energy-reserve) (get-feeb-parm 'flame-energy)) + (call-next-method)))
Modified: system.lisp ============================================================================== --- system.lisp (original) +++ system.lisp Wed Jan 2 10:40:42 2008 @@ -60,7 +60,6 @@ (last-kills :accessor feeb-last-kills :initform 0) (score :accessor feeb-score :initform 0) (kills :accessor feeb-kills :initform 0) - (dead-p :accessor feeb-dead-p) (turns-since-flamed :accessor feeb-turns-since-flamed :initform 0) (proximity :accessor feeb-proximity :initform (make-proximity)) (vision :accessor feeb-vision @@ -85,53 +84,6 @@ (defun feeb-p (x) (typep x 'feeb))
-;;; These make sure that these accessors are just available -;;; for the feeb itself - -(defmethod name :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod facing :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod peeking :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod graphics :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod x-position :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod y-position :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod line-of-sight :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod energy-reserve :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod ready-to-fire :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod aborted :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) - -(defmethod last-move :around ((fb feeb)) - (if (feeb-playing-p fb) - (call-next-method))) -
;;; Place and delete @@ -170,6 +122,7 @@
;;; --**-- System Rules --**--
+ ;;; -*- General Rules -*-
;; These will be redefined by rules @@ -188,28 +141,26 @@
(defgeneric create-object (object x-pos y-pos &key &allow-other-keys) (:method (object x-pos y-pos) - (change-object-pos object x-pos y-pos))) + (change-object-pos object x-pos y-pos)) + (:method ((feeb feeb) x-pos y-pos) + (setf (feeb-dead-p feeb) nil + (feeb-last-move feeb) :dead) + (pushnew feeb *feebs*)))
;;; Reincarnating
-(defgeneric reincarnate-feeb (feeb &key &allow-other-keys) - (:method ((feeb feeb)) - (let ((pos (nth (random *number-of-entry-points*) *entry-points*))) - (change-object-pos feeb (car pos) (cdr pos))) - (setf (feeb-facing feeb) (random 4) - (feeb-dead-p feeb) nil - (feeb-ready-to-fire feeb) t - (feeb-energy-reserve feeb) *starting-energy* - (feeb-last-move feeb) :dead))) +(defun reincarnate-feeb (feeb) + (let ((pos (nth (random *number-of-entry-points*) *entry-points*))) + (create-object feeb (car pos) (cdr pos))))
;;; Dying
(defgeneric destroy-object (object cause &key &allow-other-keys) (:method ((feeb feeb) cause) (setf *dead-feebs* (nconc *dead-feebs* (list feeb)) - (feeb-dead-p feeb) t) - (let* ((status (feeb-status feeb)) - (x (feeb-x-position feeb)) + (feeb-dead-p feeb) t + *feebs* (delete feeb *feebs*)) + (let* ((x (feeb-x-position feeb)) (y (feeb-y-position feeb))) (push (list 0 x y) *carcasses*) (delete-object (feeb-image feeb) x y) @@ -218,13 +169,12 @@
-;;; -*- Movement -*- +;;; -*- Movement Choice -*-
-;;; Lets the feeb make a choice +;;; Lets the feeb or fireball make a choice
(defgeneric make-move-choice (object) (:documentation "Lets object make its move choice.") - (:method ((feeb feeb)) (funcall (feeb-brain feeb) (feeb-status feeb) @@ -233,46 +183,34 @@ (feeb-vision-left feeb) (feeb-vision-right feeb))))
-;;; Moving + + +;;; -*- Moving -*-
(defgeneric make-move (object move) (:documentation "Applies the move MOVE to OBJECT. The MOVE is returned from MAKE-MOVE-CHOICE for the same object.")
+ (:method (object move) + nil) + (:method (object (move (eql :turn-right))) (setf (object-direction object) - (right-of (object-direction object))) - t) + (right-of (object-direction object))))
(:method (object (move (eql :turn-around))) (setf (object-direction object) - (behind (object-direction object))) - t) + (behind (object-direction object))))
(:method (object (move (eql :move-forward))) (multiple-value-bind (stuff new-x new-y) (get-forward-pos object) (when (wallp stuff) (return-from make-move nil)) - (change-object-pos object new-x new-y)) - t) - -;;; Fireball + (change-object-pos object new-x new-y)))
- (:method ((fireball fireball) (move (eql :move-forward))) - (multiple-value-bind (stuff new-x new-y) - (get-forward-pos fireball) - (dolist (thing stuff) - (if (feeb-image-p thing) - (destroy-object feeb fireball))))) - -;;; Feeb moves - - (:method ((feeb feeb) (move (eql :move-forward))) - (let ((thing (find-if #'fireball-p stuff))) - (when thing (destroy-object feeb thing) - (return-from make-move t))) - (call-next-method)) + (:method ((fireball fireball) (move (eql :dissipate))) + (destroy-object fireball))
(:method ((feeb feeb) (move (eql :flame))) (let ((x (feeb-x-position feeb)) @@ -281,26 +219,24 @@ (make-instace 'fireball (feeb-facing feeb) feeb x y (forward-dx facing) (forward-dy facing)))) - (push fireball *fireballs-flying*) - t)) + (push fireball *fireballs-flying*)))
(:method ((feeb feeb) (move (eql :eat-mushroom))) (let ((x (feeb-x-position feeb)) (y (feeb-y-position feeb))) - (when (member :mushroom (aref *maze* x y)) + (when (find :mushroom (aref *maze* x y)) (delete-object :mushroom x y) t)))
(:method ((feeb feeb) (move (eql :eat-carcass))) - (let ((x (feeb-x-position feeb)) - (y (feeb-y-position feeb))) - (when (member :carcass (aref *maze* x y)) - t))) + (when (find :carcass (aref *maze* (feeb-x-position feeb) + (feeb-y-position feeb))) + t))
(:method ((feeb feeb) (move (or (eql :peek-left) (eql :peek-right)))) (multiple-value-bind (x y stuff) (get-forward-pos feeb) (unless (wallp stuff) - (setf (feeb-peeking feeb) move))) + (setf (feeb-peeking feeb) move))))
) ; end of make-move generic function