From gmilare at common-lisp.net Wed Dec 19 20:45:38 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Wed, 19 Dec 2007 15:45:38 -0500 (EST) Subject: [the-feebs-war-cvs] r2 - Message-ID: <20071219204538.B5DB344086@common-lisp.net> Author: gmilare Date: Wed Dec 19 15:45:38 2007 New Revision: 2 Modified: feebs.tex Log: Modified: feebs.tex ============================================================================== --- feebs.tex (original) +++ feebs.tex Wed Dec 19 15:45:38 2007 @@ -1,5 +1,3 @@ -%% LyX 1.5.1 created this file. For more info, see http://www.lyx.org/. -%% Do not edit unless you really know what you are doing. \documentclass[english]{article} \usepackage[T1]{fontenc} \usepackage[latin1]{inputenc} @@ -16,7 +14,6 @@ \renewcommand{\makelabel}[1]{##1\hfil}}} {\end{list}} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands. % Copyright (c) 2007 Gustavo Henrique Milar? % % This file is part of The Feebs War. @@ -34,7 +31,6 @@ % You should have received a copy of the GNU General Public License % along with this program. If not, see . -%% LyX 1.4.2 created this file. For more info, see http://www.lyx.org/. From gmilare at common-lisp.net Wed Dec 19 20:36:54 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Wed, 19 Dec 2007 15:36:54 -0500 (EST) Subject: [the-feebs-war-cvs] r1 - feebs Message-ID: <20071219203654.8F32C1D0FC@common-lisp.net> Author: gmilare Date: Wed Dec 19 15:36:51 2007 New Revision: 1 Added: brains.fasl (contents, props changed) brains.lisp extra.lisp feebs/ feebs.asd feebs.tex feebs/WARNINGS feebs/feebs.css feebs/feebs.html feebs/index.html feebs/internals.pl feebs/labels.pl feebs/node1.html feebs/node10.html feebs/node11.html feebs/node12.html feebs/node13.html feebs/node14.html feebs/node15.html feebs/node16.html feebs/node17.html feebs/node18.html feebs/node19.html feebs/node2.html feebs/node20.html feebs/node21.html feebs/node22.html feebs/node23.html feebs/node24.html feebs/node3.html feebs/node4.html feebs/node5.html feebs/node6.html feebs/node7.html feebs/node8.html feebs/node9.html graphics.lisp license main.lisp mazes.lisp package.lisp system.lisp Log: Added: brains.fasl ============================================================================== Binary file. No diff available. Added: brains.lisp ============================================================================== --- (empty file) +++ brains.lisp Wed Dec 19 15:36:51 2007 @@ -0,0 +1,47 @@ +;;; -*- Common Lisp -*- + +(in-package :feebs) + + +;;; Modified from "cautious-brain" + + +(defun auto-brain (status proximity vision vision-left vision-right) + (declare (ignore vision-left vision-right)) + (let ((stuff (my-square proximity))) + (cond ((and (member :mushroom stuff :test #'eq) + (< (energy-reserve status) + (- *maximum-energy* 20))) + :eat-mushroom) + ((member :carcass stuff :test #'eq) + :eat-carcass) + ((and (ready-to-fire status) + (> (energy-reserve status) 30) + (dotimes (index (min (line-of-sight status) 5)) + (let ((feeb (car (member-if #'feeb-image-p (svref vision index))))) + (if (and feeb + (not (eq (feeb-image-facing feeb) + (facing status)))) + (return t))))) + :flame) + ((and (not (eq (left-square proximity) :rock)) + (or (member :mushroom (left-square proximity)) + (> 3 (random 10)))) + :turn-left) + ((and (not (eq (right-square proximity) :rock)) + (or (member :mushroom (right-square proximity)) + (> 3 (random 10)))) + :turn-right) + ((and (> (line-of-sight status) 0) + (not (dotimes (index (min (line-of-sight status) 7)) + (if (member-if #'fireball-image-p (svref vision index)) + (return t))))) + :move-forward) + (t + :turn-around)))) + +(defun make-auto-feebs (n) + (dotimes (i n) + (define-feeb + (format nil "System Feeb # ~d" i) + #'auto-brain))) \ No newline at end of file Added: extra.lisp ============================================================================== --- (empty file) +++ extra.lisp Wed Dec 19 15:36:51 2007 @@ -0,0 +1,125 @@ +;;; -*- Common Lisp -*- + +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 this program. If not, see . +|# + + +;;; Usefull for creating a feeb +;;; These are optimized so someone can use them without +;;; complaining that they slow down your feeb !!! + +(in-package :feebs) + +(declaim (optimize (speed 3) (safety 0)) + + (inline left-of right-of behind + forward-dx forward-dy + left-dx left-dy + right-dx right-dy + behind-dx behind-dy + + relative-facing + + wallp chance) + + ((function ((integer 0 3)) (integer 0 3)) + left-of right-of behind + relative-facing) + + ((function ((integer 0 3)) (integer -1 1)) + forward-dx forward-dy + left-dx left-dy + right-dx right-dy + behind-dx behind-dy) + + ((function (rational) boolean) + chance)) + +;;; Directional arithmetic. + +(defun left-of (facing) + (mod (+ facing 3) 4)) + +(defun right-of (facing) + (mod (+ facing 1) 4)) + +(defun behind (facing) + (mod (+ facing 2) 4)) + +(defun relative-facing (my-facing other-facing) + (mod (- my-facing other-facing) 4)) + +(defun forward-dy (facing) + (if (oddp facing) + 0 + (rem (1- facing) 4))) + +(defun forward-dx (facing) + (if (oddp facing) + (rem (- 2 facing) 4) + 0)) + +(defun left-dy (facing) + (forward-dy (left-of facing))) + +(defun left-dx (facing) + (forward-dx (left-of facing))) + +(defun right-dy (facing) + (forward-dy (right-of facing))) + +(defun right-dx (facing) + (forward-dx (right-of facing))) + +(defun behind-dy (facing) + (forward-dy (behind facing))) + +(defun behind-dx (facing) + (forward-dx (behind facing))) + +;;; Tests + +(defun wallp (thing) + (the boolean + (eq :rock thing))) + +#| +;;; Handling the vision, vision-left and vision-right objects + (defmacro with-visible-elements ((count line-of-sight) + ((vis vision) &body vis-body) + ((vis-l vision-left) &body vis-l-body) + ((vis-r vision-right) &body vis-r-body) + &body finalize) + (let ((v (gensym)) + (vl (gensym)) + (vr (gensym))) + `(do* ((,count 1 (1+ ,count)) + (,v (svref ,vision ,count)) + (,vl (svref ,vision ,count)) + (,vr (svref ,vision ,count))) + ((= ,count line-of-sight) + , at finalize) + (declare (list ,v ,vl ,vr) + (fixnum ,count)) ; can be assumed fixnum unless you have a mega PC + (dolist (,vis ,v) + , at vis-body) + (dolist (,vis-l ,vl) + , at vis-l-body) + (dolist (,vis-r ,vr) + , at vis-r-body)))) +|# \ No newline at end of file Added: feebs.asd ============================================================================== --- (empty file) +++ feebs.asd Wed Dec 19 15:36:51 2007 @@ -0,0 +1,30 @@ +;;; -*- Common Lisp -*- + +(defpackage :feebs-system + (:use :cl :asdf)) + +(in-package :feebs-system) + +(defsystem feebs + :description "The Feebs War is an extension of Planetof the Feebs" + :version "0.0.1" + :author "Gustavo Henrique Milar? " + :licence "GPL" + + :components + (;; source + (:cl-source-file "package") + (:cl-source-file "main" :depends-on ("package")) + (:cl-source-file "extra" :depends-on ("main")) + (:cl-source-file "system" :depends-on ("extra")) + + (:cl-source-file "mazes" :depends-on ("extra")) + (:cl-source-file "brains" :depends-on ("extra")) + + (:file "graphics" :depends-on ("main")) + + ;; GPL + (:doc-file "licence") + + ;; documentation + (:doc-file "feebs.tex"))) Added: feebs.tex ============================================================================== --- (empty file) +++ feebs.tex Wed Dec 19 15:36:51 2007 @@ -0,0 +1,577 @@ +%% LyX 1.5.1 created this file. For more info, see http://www.lyx.org/. +%% Do not edit unless you really know what you are doing. +\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}} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands. +% Copyright (c) 2007 Gustavo Henrique Milar? +% +% This file is part of The Feebs War. +% +% The Feebs War 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 of the License, or +% (at your option) any later version. +% +% The Feebs War 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 this program. If not, see . + +%% LyX 1.4.2 created this file. For more info, see http://www.lyx.org/. + + + +\IfFileExists{url.sty}{\usepackage{url} +} + {\newcommand{\url}{\texttt}} + +\makeatletter + + + + +\makeatother + +\usepackage{babel} +\makeatother + +\begin{document} + +\title{\textbf{\huge The Feebs War}} + + +\author{Gustavo Henrique Milar?} + +\maketitle +\begin{abstract} +\textit{The Feebs War} is a modified version of Planet of the Feebs +\url{http://www.cliki.net/}, a game made for people learn and improve +their lisp and code manipulation tecniques. The graphics are now displayed +using PAL \url{http://common-lisp.net/project/pal/}'s libraries, +so the problems with portability from CMUCL and X Window Sistem do +not exist anymore. Also the code is cleaner and simpler both to make +a feeb and to read the code. +\end{abstract} +\tableofcontents{} + + +\section{Introduction} + +The Feebs are intelligent and hostile creatures that live inside maze +tunnels. They also have no mercy with each other, so they frequently +throw a letal flame from through their mouth, and, after that, they +can eat the carcass left. But throwing flames have an energy cost, +so they must keep tracking for food. + +This game is intended to help lisp newbies (or maybe a little more +advanced lispers) to learn lisp. A player must create a function that +receives what his/her feeb is seeing and feeling, and returns what +it will do next. To create the better feeb, one can create variables +to store data from previous moves (or not), and can also use all the +power of lisp to improve his/her creature. + + +\subsection{Changes from \emph{Planet of the Feebs}} + +Many changes were made from the original game, but, if you have any +feeb definition and you want to use it, it should be easy to adapt +the brain function to the new rules. + +The main reason of this project is that \textit{Planet of the Feebs} +is really interesting for (not just) newbies to learn lisp, but the +difficulties to install, unportability and the ausence of competitors +make it difficult to someone to be interested in making a feeb. So, +I hope that making these adjustments and maybe creating some contests +over the web make people be more interested in learning lisp. + +So, these are (some of) the changes: + +\begin{itemize} +\item The graphics are not based on X Window Sistem anymore, but on PAL, +and there are no CMUCL's event handler. This way, the code is more +portable and graphics can be improved without those hundreds of lines +that the original version has. Just creating some .bmp or .jpg files +of a feeb and your feeb is much more personalized! +\item Every element of the map (except walls) is a list, so the brain of +a feeb doesn't need to test all the time if the element is an atom +or a list (wich, in my opinion, is really boring, unlispy and unnecessary +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 Someone watching the game can control a Feeb with the keyboard, if +he/she wants to, and say when the game must finish. +\item This document 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 search for some information. +\end{itemize} + +\section{The Game} + + +\subsection{Overview} + +Your feeb's objective is to survive and kill other feebs. It is inside +a maze of tunnels. Every turn, all feebs lose one unit of energy, +and maybe starves. Your feeb is able to move forward, turn left, right +or around, flame, peek around a corner, eat something or just wait. +After all feebs move, the flames thrown before also move (or dissipate), +carcasses may rot and mushrooms may grow, accordingly to some rules. + +To see what values are taken, one can use \textsf{\textbf{(list-parameter-settings)}}. +Using \textsf{\textbf{setf}} gives the possibility to change them +and \textsf{\textbf{documentation}} can be used to know them. Just +remember that every probability must be a rational number (like 1/2). +These parameters are just for one to know how the game is going to +be, but in the begining there is no need to explicitly use them when +creating the brain of a feeb. + +These are some global parameters: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{{*}game-length{*}}}}] Number of turns the game +will last, or nil if there is a human player. +\item [{\textsf{\textbf{{*}points-for-killing{*}}}}] How many points some +feeb earn for killing someone. +\item [{\textsf{\textbf{{*}points-for-dying{*}}}}] How many points some +feeb earn for dying (usually negative). +\item [{\textsf{\textbf{{*}maze-x-size{*}}}}] Horizontal size of the maze. +\item [{\textsf{\textbf{{*}maze-y-size{*}}}}] Vertical size of the maze. +\item [{\textsf{\textbf{(get-maze-map)}}}] This command can be used to +get the map (see section \ref{sub:Map}). +\end{lyxlist} + +\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 +killing feebs it encounters, transforming them into carcass. If there +is a wall, the flame can reflect, and will turn 180 degrees. + +Once a feeb is killed, in it's place in the maze there will appear +a carcass. The feeb goes to the end of the killed feebs line. Whenever +a carcass rots, the first feeb in line will reincarnate. So, dying +is not so terrible. + +These are the parameters related to flames: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{{*}flame-energy{*}}}}] Amount of energy lost after +throwing a flame. +\item [{\textsf{\textbf{{*}fireball-guaranteed-lifetime{*}}}}] Number of +turns that a fireball is guaranteed not to dissipate, unless it encounters +a wall. +\item [{\textsf{\textbf{{*}fireball-dissipation-probability{*}}}}] Probability +of the flame to dissipate each turn after the apropriate time. +\item [{\textsf{\textbf{{*}fireball-reflection-probability{*}}}}] Probability +of the flame to reflect when encountering a wall. +\item [{\textsf{\textbf{{*}flame-no-recovery-time{*}}}}] Number of turns +that a feeb cannot fire. +\item [{\textsf{\textbf{{*}flame-recovery-probability{*}}}}] Probability +of the feeb to recover the hability to throw a flame, after the apropriate +time. +\end{lyxlist} + +\subsection{Eating food} + +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 +will be able to recover energy, wich is important because, if a feeb +stays with 0 or less units of energy, it starves. + +These are the quantities: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{{*}mushroom-energy{*}}}}] Amount of energy recovered +when the feeb eats a mushroom. +\item [{\textsf{\textbf{{*}carcass-energy{*}}}}] Amount of energy recovered +each turn that the feeb eats a carcass. +\item [{\textsf{\textbf{{*}carcass-guaranteed-lifetime{*}}}}] Number of +turns that a carcass will surely stay there. After these turns, it +can rot, depending on probabilities. +\item [{\textsf{\textbf{{*}carcass-rot-probability{*}}}}] Probability of +the carcass to rot, after the apropriate time. +\item [{\textsf{\textbf{{*}maximum-energy{*}}}}] Maximum amount of energy +that a feeb can have eating. +\item [{\textsf{\textbf{{*}starting-energy{*}}}}] Amount of energy a feeb +has when it reincarnates. +\item [{\textsf{\textbf{{*}number-of-mushrooms{*}}}}] Quantity of mushrooms +that exist in the maze. +\end{lyxlist} + +\section{The Feeb} + +A feeb needs four things: a name, a brain, an initialize function +(optional) and a set of graphics (optional). + +\begin{itemize} +\item The name, a string. +\item The brain is a function that decides what the feeb will do next, based +on what it is seeing and feeling. +\item The initializer is invoked when the game is about to start, so it +can analyze the map, global parameters, and so on. +\item The set of graphics is an image file (of format BMP, JPEG, PNG, and +any others that supported by SDL\_image). +\end{itemize} +One can create a feeb calling \textsf{\textbf{(define-feeb~}}\textsf{name~brain~}\textsf{\textbf{:initializer}}\textsf{~prepare~}\textsf{\textbf{:graphics}}\textsf{~graphics}\textsf{\textbf{)}}. +If name is already used, a warning will be signaled, and the old feeb +will be substituted. Calling \textsf{\textbf{(list-of-feebs)}} will +return the list of the feebs (names only) that will be defined when +the game begins. \textsf{\textbf{(delete-feeb}}\textsf{~name}\textsf{\textbf{)}} +will delete the feeb with this name from this list, and \textsf{\textbf{(delete-all-feebs)}} +will clear it. + + +\subsection{Possible decisions} + +After processing the information available, the brain will take a +decision. If this decision is not one of the decisions listed down, +a warning will be signaled, and the result will be like \textsf{\textbf{:wait}}. +Then, if someone are testing a brain function, he or she will be able +to know if something goes wrong. + +The possible values that the brain function can return are these: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{:move-forward}}}] Move one square forward, unless +there is a wall in front of the feeb. +\item [{\textsf{\textbf{:turn-left}}}] Turn 90 degrees to the left. +\item [{\textsf{\textbf{:turn-right}}}] Turn 90 degrees to the right. +\item [{\textsf{\textbf{:turn-around}}}] Turn 180 degrees. +\item [{\textsf{\textbf{:flame}}}] Throw a flame. The flame will be created +next turn in the front square of the feeb. +\item [{\textsf{\textbf{:wait}}}] Do nothing in this turn. +\item [{\textsf{\textbf{:peek-left}}}] Peek to the left around a corner. +The creature does note actually move, but, in the next turn, the creature +will have the same vision that it would have if he had moved one step +foward and turned left. This is used so a feeb can analize a corridor +before trespassing it. +\item [{\textsf{\textbf{:peek-right}}}] Peek to the right around a corner, +analogous of \textsf{\textbf{:peek-left}}. +\item [{\textsf{\textbf{:eat-carcass}}}] Eat a carcass if there is any +available in the feeb's square. The amount of \textsf{\textbf{{*}carcass-energy{*}}} +is restored to the feeb's energy. +\item [{\textsf{\textbf{:eat-mushroom}}}] Eat a mushroom if there is any +available in the feeb's square. The amount of \textsf{\textbf{{*}mushroom-energy{*}}} +is restored to the feeb's energy. +\end{lyxlist} + +\subsection{Information available} + +The brain of a feeb mus take five arguments; I'll call them \textsf{\emph{status}}, +\textsf{\emph{proximity}}, \textsf{\emph{vision}}, \textsf{\emph{vision-left}} +and \textsf{\emph{vision-right}}. + + +\subsubsection{Status} + +Every time the brain is called, it receives some useful information +through \textsf{\textbf{status}}. + +The structure \textsf{\textbf{status}} keeps information about the +feeb itself. Also it has information of the previous movement of the +feeb. To access them, one must call: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{(name}}\textsf{\emph{~status}}\textsf{\textbf{)}}}] \begin{flushleft} +The +name of the feeb. +\par\end{flushleft} +\item [{\textsf{\textbf{(facing~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} +Where +the feeb is facing, one of the constants provided: \textsf{\textbf{north}}, +\textsf{\textbf{south}}, \textsf{\textbf{east}} or \textsf{\textbf{west}}, +wich are 0, 1, 2 and 3 respectivelly. +\par\end{flushleft} +\item [{\textsf{\textbf{(x-position~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} +The +horizontal position of the feeb, increasing to east. If \textsf{\textbf{{*}sense-location{*}}} +is nil, it returns nil instead. +\par\end{flushleft} +\item [{\textsf{\textbf{(y-position~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} +The +vertical position of the feeb, increasing to north. If \textsf{\textbf{{*}sense-location{*}}} +is nil, it returns nil instead. +\par\end{flushleft} +\item [{\textsf{\textbf{(peeking~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} +If +it is \textsf{\textbf{:left}} or \textsf{\textbf{:right}}, it means +that the current \textsf{\emph{vision}} provided is result of a previous +\textsf{\textbf{:peek-left}} or \textsf{\textbf{:peek-right}} command +of the same feeb. Otherwise, it is \textsf{\textbf{nil}}. +\par\end{flushleft} +\item [{\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} +Indicates +the amount of valid entries in \textsf{\emph{vision}}. It actually +means that \textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{))}} +will return \textsf{\textbf{:rock}}. +\par\end{flushleft} +\item [{\textsf{\textbf{(ready-to-fire~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} +\textsf{\textbf{T}} +indicates that the feeb is ready to fire. \textsf{\textbf{Nil}} indicates +it is not. +\par\end{flushleft} +\item [{\textsf{\textbf{(aborted}}\textsf{\emph{~status}}\textsf{\textbf{)}}}] \begin{flushleft} +Related +with timing. Returns \textsf{\textbf{T}} if the last move of feeb +was aborted because of speed. +\par\end{flushleft} +\item [{\textsf{\textbf{(last-move~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} +The +feeb's previous move, or \textsf{\textbf{:dead}} if it has just reincarnated. +\par\end{flushleft} +\end{lyxlist} + +\subsubsection{Proximity and vision} + +The brain receives also information about what is near the feeb and +what the feeb sees. + +The structure \textsf{\emph{proximity}} has the contents of the squares +near the feeb, with these fields: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{(my-square~}}\textsf{\emph{proximity}}\textsf{\textbf{)}}}] \begin{flushleft} +Contents +of the feeb's current square. +\par\end{flushleft} +\item [{\textsf{\textbf{(left-square~}}\textsf{\emph{proximity}}\textsf{\textbf{)}}}] \begin{flushleft} +Contents +of the right square of the feeb. +\par\end{flushleft} +\item [{\textsf{\textbf{(right-square~}}\textsf{\emph{proximity}}\textsf{\textbf{)}}}] \begin{flushleft} +Contents +of the left square of the feeb. +\par\end{flushleft} +\item [{\textsf{\textbf{(rear-square}}\textsf{\emph{~proximity}}\textsf{\textbf{)}}}] \begin{flushleft} +Contents +of the square behind the feeb. +\par\end{flushleft} +\item [{The}] vector \textsf{\emph{vision}} has the contents of the squares +that are in front of the feeb. For example, \textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{0}\textsf{\textbf{)}} +will return the contents of the square in front of the feeb, \textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{1}\textsf{\textbf{)}} +will return the contents of the next square, and so on. As said before, +\textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{))}} +will be the first :rock encountered. All subsequents square, like +\textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{\textbf{(+~}}\textsf{1~}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{)))}}, +will be garbage and should not be used. +\end{lyxlist} +The contents of one square returned by any of these calls is either +:rock or a list of elements, or maybe \textsf{\textbf{nil}} if the +square is empty. Each element of the square is one of these: + +\begin{itemize} +\item \textbf{Feeb image.} One can call \textsf{\textbf{(feeb-image-p~}}\textsf{element}\textsf{\textbf{)}} +to see if element is a feeb image. +\item \textbf{Fireball image.} One can call \textsf{\textbf{(fireball-image-p~}}\textsf{element}\textsf{\textbf{)}} +to check if element is a fireball image. +\item \textsf{\textbf{:carcass}}. If there is a \textsf{\textbf{:carcass}} +in the square of the feeb (i.e. in \textsf{\textbf{(my-square~}}\textsf{\emph{proximity}}\textsf{\textbf{)}}), +the call \textsf{\textbf{:eat-carcass}} will make the feeb eat it. +\item \textsf{\textbf{:mushroom}}. Analogous to \textsf{\textbf{:carcass}}. +A mushroom appears randomly in places (mushroom patchs) previouly +marked in the map. +\end{itemize} + +\subsubsection{Feebs and fireballs images} + +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. + +These are the fields available: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{(feeb-image-name}}\textsf{~feeb-image}\textsf{\textbf{)}}}] \begin{flushleft} +The +name of the feeb. Maybe you can know it's weakpoints. +\par\end{flushleft} +\item [{\textsf{\textbf{(feeb-image-facing~}}\textsf{feeb-image}\textsf{\textbf{)}}}] \begin{flushleft} +The +facing of the feeb. This way the brain function can see if the feeb-image +either sees it or not. +\par\end{flushleft} +\item [{\textsf{\textbf{(feeb-image-peeking~}}\textsf{feeb-image}\textsf{\textbf{)}}}] \begin{flushleft} +Returns +\textsf{\textbf{:peek-left}} or \textsf{\textbf{:peek-right}} if the +feeb is peeking to (its) left or right, or \textsf{\textbf{nil}} if +not. +\par\end{flushleft} +\item [{\textsf{\textbf{(fireball-image-direction~}}\textsf{fireball-image}\textsf{\textbf{)}}}] \begin{flushleft} +The +direction that the fireball image is going to. +\par\end{flushleft} +\end{lyxlist} + +\subsubsection{Vision-left and vision-right} + +\textsf{\emph{vision-left}} and \textsf{\emph{vision-right}} are vectors +similar to vision, but they are less precise in the contents. Also +their valid contents are limited by \textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{)}}, +so \textsf{\textbf{(aref~}}\textsf{\emph{vision-left~}}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{))}}, +for example, will return \textsf{\textbf{:unknown}}. + +Note that feebs that are not peeking, mushrooms and carcasses are +\emph{not} be detected by these vectors. Also, if there is a feeb +peeking to the opposite side, it won't be detected either. These are +the possible returns of the elements in \textsf{\textbf{vision-left}} +and \textsf{\textbf{vision-right}}: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{:peek-letf}}}] This means that in that square there +is a feeb peeking to (its) left. +\item [{\textsf{\textbf{:peek-right}}}] This means that in that square +there is a feeb peeking to (its) right. +\item [{\textsf{\textbf{nil}}}] This square is empty. +\item [{\textsf{\textbf{:rock}}}] This square is just a wall. +\end{lyxlist} + +\subsection{Extra functions provided} + +Before making the brain of your feeb, you might want to take a look +at the Extra functions that are available at the end of the feebs.lisp +file. The only thing you need so you can use them is to see their +code and know what they do. + + +\subsection{Graphics} + +With this version of the game, it's possible to choose the graphics +of a feeb when creating it, so your feeb will be more personalized. + +The graphic of a feeb is defined by an image file, which should have +three colunms by eight lines of pictures of the same size. The four +first lines must be the animations of the feeb walking up, left, down +and right, respectively. The next four lines must be the pictures +of the feeb flaming up, left, down and right, respectively. To see +an example, see {}``default-feeb.png''. + +After creating the image file, you must call \textsf{\textbf{(create-graphics}}\textsf{~path-to-image-file}\textsf{\textbf{)}}. +If you now how to work with sdl surfaces in lispbuilder, you may use +the function with a surface instead of a image file; or you can call +\textsf{\textbf{(create-graphics~}}\textsf{path-to-image-file~nil}\textsf{\textbf{)}} +if the surface should not be freed after the call. The result must +be the third argument given to define-feeb. + + +\subsection{Starting the game} + +The game loop is started by calling (feebs). + + +\section{Contests} + +I sugest that you see this chapter only after you have created at +least a basic brain feeb, wich is better than the (simple) provided +brain, and when you want to participate of a contest or a game with +your friends. + + +\subsection{\label{sub:Map}Map} + +It is possible to get the maze map during the game, but with only +the corridors. Note that the function that gets the map is purposely +a little slow, so, invoking it too many times in a contest that uses +timing atributes is not a good idea; anyway, it is possible to invoke +this function before defining the feeb, and store its value somewhere. +Also note that the map returned does not have any information about +what is really in the maze, but only the possible ways. + +To get the map, one can call \textsf{\textbf{(get-maze-map)}}. This +function will return \textsf{\textbf{nil}} if \textsf{\textbf{{*}may-get-maze-p{*}}} +is also \textsf{\textbf{nil}}. Otherwise, the map returned is an array, +so that calling \textsf{\textbf{(aref}}\textsf{~map~x~y}\textsf{\textbf{)}} +will get the contents in the euclidean position (x,y) . The contents +of a cell could be one of these: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{:mushroom-place}}}] A mushroom patch, i.e. when +a mushroom is eaten it can come out here. +\item [{\textsf{\textbf{:feeb-entry-place}}}] A feeb entry, i.e. if a carcass +rots a feeb can appear here. +\item [{\textsf{\textbf{:rock}}}] A wall. Feebs cannot come in this place. +\item [{\textsf{\textbf{nil}}}] An {}``empty'' place, i.e. neither of +the previous. +\end{lyxlist} + +\subsection{Timing} + +There are also some timing atributes that can be given to the game. +If the feeb takes too long to make a decision, there is more probability +of its command to be aborted. + +To make this available, someone must set these: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{{*}slow-feeb-noop-switch{*}}}}] If is non-nil, +there is a possibility that the move of a feeb is aborted according +to its function time. Not applied to the human controlled feeb. +\item [{\textsf{\textbf{{*}slow-feeb-noop-factor{*}}}}] The probability +of the feeb to abort will be this factor times the amount of time +the feeb takes to have a decision, divided for the total time taken +by all the feebs in the current turn. +\end{lyxlist} + +\subsection{Sense of location} + +Some accessors related to position and orientation of the feeb can +be turned off. + +These are the parameters: + +\begin{lyxlist}{00.00.0000} +\item [{\textsf{\textbf{{*}sense-location-p{*}}}}] Tells if the actual +position of the feeb can be determinated accessing \textsf{\textbf{x-position}} +and \textsf{\textbf{y-position}}. +\end{lyxlist} + +\subsection{Changing the rules} + +To change the rules of the contest, they must be changed before the +feebs are defined, because in a feeb definition it could use the values +of the variables to make a global strategy, and change the strategies +after this could not be fair. + +All the parameters that can be listed using \textsf{\textbf{(list-parameter-settings)}} +can be changed using setf. Also, they all have documentation about +themselves, so feel free to use \textsf{\textbf{(documentation~}}\textsf{parameter~'variable}\textsf{\textbf{)}} +and see what each parameter does. Documentation is available to external +functions too. + +It is possible to change the layout of the map by calling \textsf{\textbf{(change-layout}}\textsf{~new-layout}\textsf{\textbf{)}}. +There are a few predefined mazes that are \textsf{\textbf{{*}maze-0{*}}} +throw \textsf{\textbf{{*}maze-5{*}}}. If you want to create a new +map, take the template (commented) inside the same file, or create +maybe a bigger template (of any size, because the values of \textsf{\textbf{{*}maze-x-size{*}}} +and \textsf{\textbf{{*}maze-y-size{*}}} will be changed accordingly). + + +\section{Reference} + +\begin{quote} +Fahlman, S. E. \textbf{\emph{Planet of the Feebs -}} \emph{A Somewhat +Educational Game.} \url{ftp://ftp.csl.sri.com/pub/users/gilham/feebs/feebs.tex}. +\end{quote} + +\end{document} Added: feebs/WARNINGS ============================================================================== --- (empty file) +++ feebs/WARNINGS Wed Dec 19 15:36:51 2007 @@ -0,0 +1,9 @@ +No implementation found for style `fontenc' +No implementation found for style `url' + +redefining command \url + +previous meaning of \url will be lost + +The feebs.aux file was not found, so sections will not be numbered +and cross-references will be shown as icons. Added: feebs/feebs.css ============================================================================== --- (empty file) +++ feebs/feebs.css Wed Dec 19 15:36:51 2007 @@ -0,0 +1,30 @@ +/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */ +.MATH { font-family: "Century Schoolbook", serif; } +.MATH I { font-family: "Century Schoolbook", serif; font-style: italic } +.BOLDMATH { font-family: "Century Schoolbook", serif; font-weight: bold } + +/* implement both fixed-size and relative sizes */ +SMALL.XTINY { font-size : xx-small } +SMALL.TINY { font-size : x-small } +SMALL.SCRIPTSIZE { font-size : smaller } +SMALL.FOOTNOTESIZE { font-size : small } +SMALL.SMALL { } +BIG.LARGE { } +BIG.XLARGE { font-size : large } +BIG.XXLARGE { font-size : x-large } +BIG.HUGE { font-size : larger } +BIG.XHUGE { font-size : xx-large } + +/* heading styles */ +H1 { } +H2 { } +H3 { } +H4 { } +H5 { } + +/* mathematics styles */ +DIV.displaymath { } /* math displays */ +TD.eqno { } /* equation-number cells */ + + +/* document-specific styles come next */ Added: feebs/feebs.html ============================================================================== --- (empty file) +++ feebs/feebs.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,145 @@ + + + + + +The Feebs War + + + + + + + + + + + + + + + + + +next +up +previous + +contents +
+ Next: Contents +   Contents +
+
+ + +

+ +

+ +

+

The Feebs War

+
+ +

Gustavo Henrique Milaré

+
+ +

Abstract:

+
+The Feebs War is a modified version of Planet of the Feebs +http://www.cliki.net/, a game made for people learn and improve +their lisp and code manipulation tecniques. The graphics are now displayed +using PAL http://common-lisp.net/project/pal/'s libraries, +so the problems with portability from CMUCL and X Window Sistem do +not exist anymore. Also the code is cleaner and simpler both to make +a feeb and to read the code. +
+

+


+ + + + + +

+
+ +2007-12-19 +
+ + Added: feebs/index.html ============================================================================== --- (empty file) +++ feebs/index.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,145 @@ + + + + + +The Feebs War + + + + + + + + + + + + + + + + + +next +up +previous + +contents +
+ Next: Contents +   Contents +
+
+ + +

+ +

+ +

+

The Feebs War

+
+ +

Gustavo Henrique Milaré

+
+ +

Abstract:

+
+The Feebs War is a modified version of Planet of the Feebs +http://www.cliki.net/, a game made for people learn and improve +their lisp and code manipulation tecniques. The graphics are now displayed +using PAL http://common-lisp.net/project/pal/'s libraries, +so the problems with portability from CMUCL and X Window Sistem do +not exist anymore. Also the code is cleaner and simpler both to make +a feeb and to read the code. +
+

+


+ + + + + +

+
+ +2007-12-19 +
+ + Added: feebs/internals.pl ============================================================================== --- (empty file) +++ feebs/internals.pl Wed Dec 19 15:36:51 2007 @@ -0,0 +1,10 @@ +# LaTeX2HTML 2002-2-1 (1.71) +# Associate internals original text with physical files. + + +$key = q/sub:Map/; +$ref_files{$key} = "$dir".q|node19.html|; +$noresave{$key} = "$nosave"; + +1; + Added: feebs/labels.pl ============================================================================== --- (empty file) +++ feebs/labels.pl Wed Dec 19 15:36:51 2007 @@ -0,0 +1,17 @@ +# LaTeX2HTML 2002-2-1 (1.71) +# Associate labels original text with physical files. + + +$key = q/sub:Map/; +$external_labels{$key} = "$URL/" . q|node19.html|; +$noresave{$key} = "$nosave"; + +1; + + +# LaTeX2HTML 2002-2-1 (1.71) +# labels from external_latex_labels array. + + +1; + Added: feebs/node1.html ============================================================================== --- (empty file) +++ feebs/node1.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,118 @@ + + + + + +Contents + + + + + + + + + + + + + + + + + + + + +next + +up + +previous +
+ Next: Introduction + Up: The Feebs War + Previous: The Feebs War +
+
+ +
+ +

+Contents +

+ + + + + +

+


+
+ +2007-12-19 +
+ + Added: feebs/node10.html ============================================================================== --- (empty file) +++ feebs/node10.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,90 @@ + + + + + +Information available + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Status + Up: The Feeb + Previous: Possible decisions +   Contents +
+
+ + +

+Information available +

+ +

+The brain of a feeb mus take five arguments; I'll call them status, +proximity, vision, vision-left +and vision-right. + +

+


+ +Subsections + + + +

+
+ +2007-12-19 +
+ + Added: feebs/node11.html ============================================================================== --- (empty file) +++ feebs/node11.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,193 @@ + + + + + +Status + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Proximity and vision + Up: Information available + Previous: Information available +   Contents +
+
+ + +

+Status +

+ +

+Every time the brain is called, it receives some useful information +through status. + +

+The structure status keeps information about the +feeb itself. Also it has information of the previous movement of the +feeb. To access them, one must call: + +

+ +

    +
  • [(name status)]
    +The +name of the feeb. +
    +

    +

    +
    +
  • +
  • [(facing status)]
    +Where +the feeb is facing, one of the constants provided: north, +south, east or west, +wich are 0, 1, 2 and 3 respectivelly. +
    +

    +

    +
    +
  • +
  • [(x-position status)]
    +The +horizontal position of the feeb, increasing to east. If *sense-location* +is nil, it returns nil instead. +
    +

    +

    +
    +
  • +
  • [(y-position status)]
    +The +vertical position of the feeb, increasing to north. If *sense-location* +is nil, it returns nil instead. +
    +

    +

    +
    +
  • +
  • [(peeking status)]
    +If +it is :left or :right, it means +that the current vision provided is result of a previous +:peek-left or :peek-right command +of the same feeb. Otherwise, it is nil. +
    +

    +

    +
    +
  • +
  • [(line-of-sight status)]
    +Indicates +the amount of valid entries in vision. It actually +means that (aref vision (line-of-sight status)) +will return :rock. +
    +

    +

    +
    +
  • +
  • [(ready-to-fire status)]
    +T +indicates that the feeb is ready to fire. Nil indicates +it is not. +
    +

    +

    +
    +
  • +
  • [(aborted status)]
    +Related +with timing. Returns T if the last move of feeb +was aborted because of speed. +
    +

    +

    +
    +
  • +
  • [(last-move status)]
    +The +feeb's previous move, or :dead if it has just reincarnated. +
    +

    +

    +
    +
  • +
+

+


+ + +next + +up + +previous + +contents +
+ Next: Proximity and vision + Up: Information available + Previous: Information available +   Contents + +
+ +2007-12-19 +
+ + Added: feebs/node12.html ============================================================================== --- (empty file) +++ feebs/node12.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,172 @@ + + + + + +Proximity and vision + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Feebs and fireballs images + Up: Information available + Previous: Status +   Contents +
+
+ + +

+Proximity and vision +

+ +

+The brain receives also information about what is near the feeb and +what the feeb sees. + +

+The structure proximity has the contents of the squares +near the feeb, with these fields: + +

+ +

    +
  • [(my-square proximity)]
    +Contents +of the feeb's current square. +
    +

    +

    +
    +
  • +
  • [(left-square proximity)]
    +Contents +of the right square of the feeb. +
    +

    +

    +
    +
  • +
  • [(right-square proximity)]
    +Contents +of the left square of the feeb. +
    +

    +

    +
    +
  • +
  • [(rear-square proximity)]
    +Contents +of the square behind the feeb. +
    +

    +

    +
    +
  • +
  • [The] vector vision has the contents of the squares +that are in front of the feeb. For example, (aref vision 0) +will return the contents of the square in front of the feeb, (aref vision 1) +will return the contents of the next square, and so on. As said before, +(aref vision (line-of-sight status)) +will be the first :rock encountered. All subsequents square, like +(aref vision (+ (line-of-sight status))), +will be garbage and should not be used. +
  • +
The contents of one square returned by any of these calls is either +:rock or a list of elements, or maybe nil if the +square is empty. Each element of the square is one of these: + +

+ +

    +
  • Feeb image. One can call (feeb-image-p element) +to see if element is a feeb image. +
  • +
  • Fireball image. One can call (fireball-image-p element) +to check if element is a fireball image. +
  • +
  • :carcass. If there is a :carcass +in the square of the feeb (i.e. in (my-square proximity)), +the call :eat-carcass will make the feeb eat it. +
  • +
  • :mushroom. Analogous to :carcass. +A mushroom appears randomly in places (mushroom patchs) previouly +marked in the map. +
  • +
+ +

+


+ + +next + +up + +previous + +contents +
+ Next: Feebs and fireballs images + Up: Information available + Previous: Status +   Contents + +
+ +2007-12-19 +
+ + Added: feebs/node13.html ============================================================================== --- (empty file) +++ feebs/node13.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,117 @@ + + + + + +Feebs and fireballs images + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Vision-left and vision-right + Up: Information available + Previous: Proximity and vision +   Contents +
+
+ + +

+Feebs and fireballs images +

+ +

+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. + +

+These are the fields available: + +

+ +

    +
  • [(feeb-image-name feeb-image)]
    +The +name of the feeb. Maybe you can know it's weakpoints. +
    +

    +

    +
    +
  • +
  • [(feeb-image-facing feeb-image)]
    +The +facing of the feeb. This way the brain function can see if the feeb-image +either sees it or not. +
    +

    +

    +
    +
  • +
  • [(feeb-image-peeking feeb-image)]
    +Returns +:peek-left or :peek-right if the +feeb is peeking to (its) left or right, or nil if +not. +
    +

    +

    +
    +
  • +
  • [(fireball-image-direction fireball-image)]
    +The +direction that the fireball image is going to. +
    +

    +

    +
    +
  • +
+

+


+
+ +2007-12-19 +
+ + Added: feebs/node14.html ============================================================================== --- (empty file) +++ feebs/node14.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,97 @@ + + + + + +Vision-left and vision-right + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Extra functions provided + Up: Information available + Previous: Feebs and fireballs images +   Contents +
+
+ + +

+Vision-left and vision-right +

+ +

+vision-left and vision-right are vectors +similar to vision, but they are less precise in the contents. Also +their valid contents are limited by (line-of-sight status), +so (aref vision-left (line-of-sight status)), +for example, will return :unknown. + +

+Note that feebs that are not peeking, mushrooms and carcasses are +not be detected by these vectors. Also, if there is a feeb +peeking to the opposite side, it won't be detected either. These are +the possible returns of the elements in vision-left +and vision-right: + +

+ +

    +
  • [:peek-letf] This means that in that square there +is a feeb peeking to (its) left. +
  • +
  • [:peek-right] This means that in that square +there is a feeb peeking to (its) right. +
  • +
  • [nil] This square is empty. +
  • +
  • [:rock] This square is just a wall. +
  • +
+

+


+
+ +2007-12-19 +
+ + Added: feebs/node15.html ============================================================================== --- (empty file) +++ feebs/node15.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,76 @@ + + + + + +Extra functions provided + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Graphics + Up: The Feeb + Previous: Vision-left and vision-right +   Contents +
+
+ + +

+Extra functions provided +

+ +

+Before making the brain of your feeb, you might want to take a look +at the Extra functions that are available at the end of the feebs.lisp +file. The only thing you need so you can use them is to see their +code and know what they do. + +

+


+
+ +2007-12-19 +
+ + Added: feebs/node16.html ============================================================================== --- (empty file) +++ feebs/node16.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,90 @@ + + + + + +Graphics + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Starting the game + Up: The Feeb + Previous: Extra functions provided +   Contents +
+
+ + +

+Graphics +

+ +

+With this version of the game, it's possible to choose the graphics +of a feeb when creating it, so your feeb will be more personalized. + +

+The graphic of a feeb is defined by an image file, which should have +three colunms by eight lines of pictures of the same size. The four +first lines must be the animations of the feeb walking up, left, down +and right, respectively. The next four lines must be the pictures +of the feeb flaming up, left, down and right, respectively. To see +an example, see ``default-feeb.png''. + +

+After creating the image file, you must call (create-graphics path-to-image-file). +If you now how to work with sdl surfaces in lispbuilder, you may use +the function with a surface instead of a image file; or you can call +(create-graphics path-to-image-file nil) +if the surface should not be freed after the call. The result must +be the third argument given to define-feeb. + +

+


+
+ +2007-12-19 +
+ + Added: feebs/node17.html ============================================================================== --- (empty file) +++ feebs/node17.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,72 @@ + + + + + +Starting the game + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Contests + Up: The Feeb + Previous: Graphics +   Contents +
+
+ + +

+Starting the game +

+ +

+The game loop is started by calling (feebs). + +

+


+
+ +2007-12-19 +
+ + Added: feebs/node18.html ============================================================================== --- (empty file) +++ feebs/node18.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,91 @@ + + + + + +Contests + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Map + Up: The Feebs War + Previous: Starting the game +   Contents +
+
+ + +

+Contests +

+ +

+I sugest that you see this chapter only after you have created at +least a basic brain feeb, wich is better than the (simple) provided +brain, and when you want to participate of a contest or a game with +your friends. + +

+


+ +Subsections + + + +

+
+ +2007-12-19 +
+ + Added: feebs/node19.html ============================================================================== --- (empty file) +++ feebs/node19.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,130 @@ + + + + + +Map + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Timing + Up: Contests + Previous: Contests +   Contents +
+
+ + +

+
+Map +

+ +

+It is possible to get the maze map during the game, but with only +the corridors. Note that the function that gets the map is purposely +a little slow, so, invoking it too many times in a contest that uses +timing atributes is not a good idea; anyway, it is possible to invoke +this function before defining the feeb, and store its value somewhere. +Also note that the map returned does not have any information about +what is really in the maze, but only the possible ways. + +

+To get the map, one can call (get-maze-map). This +function will return nil if *may-get-maze-p* +is also nil. Otherwise, the map returned is an array, +so that calling (aref map x y) +will get the contents in the euclidean position (x,y) . The contents +of a cell could be one of these: + +

+ +

    +
  • [:mushroom-place] A mushroom patch, i.e. when +a mushroom is eaten it can come out here. +
  • +
  • [:feeb-entry-place] A feeb entry, i.e. if a carcass +rots a feeb can appear here. +
  • +
  • [:rock] A wall. Feebs cannot come in this place. +
  • +
  • [nil] An ``empty'' place, i.e. neither of +the previous. +
  • +
+

+


+ + +next + +up + +previous + +contents +
+ Next: Timing + Up: Contests + Previous: Contests +   Contents + +
+ +2007-12-19 +
+ + Added: feebs/node2.html ============================================================================== --- (empty file) +++ feebs/node2.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,94 @@ + + + + + +Introduction + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Changes from Planet of + Up: The Feebs War + Previous: Contents +   Contents +
+
+ + +

+Introduction +

+ +

+The Feebs are intelligent and hostile creatures that live inside maze +tunnels. They also have no mercy with each other, so they frequently +throw a letal flame from through their mouth, and, after that, they +can eat the carcass left. But throwing flames have an energy cost, +so they must keep tracking for food. + +

+This game is intended to help lisp newbies (or maybe a little more +advanced lispers) to learn lisp. A player must create a function that +receives what his/her feeb is seeing and feeling, and returns what +it will do next. To create the better feeb, one can create variables +to store data from previous moves (or not), and can also use all the +power of lisp to improve his/her creature. + +

+


+ +Subsections + + + +

+
+ +2007-12-19 +
+ + Added: feebs/node20.html ============================================================================== --- (empty file) +++ feebs/node20.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,91 @@ + + + + + +Timing + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Sense of location + Up: Contests + Previous: Map +   Contents +
+
+ + +

+Timing +

+ +

+There are also some timing atributes that can be given to the game. +If the feeb takes too long to make a decision, there is more probability +of its command to be aborted. + +

+To make this available, someone must set these: + +

+ +

    +
  • [*slow-feeb-noop-switch*] If is non-nil, +there is a possibility that the move of a feeb is aborted according +to its function time. Not applied to the human controlled feeb. +
  • +
  • [*slow-feeb-noop-factor*] The probability +of the feeb to abort will be this factor times the amount of time +the feeb takes to have a decision, divided for the total time taken +by all the feebs in the current turn. +
  • +
+

+


+
+ +2007-12-19 +
+ + Added: feebs/node21.html ============================================================================== --- (empty file) +++ feebs/node21.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,85 @@ + + + + + +Sense of location + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Changing the rules + Up: Contests + Previous: Timing +   Contents +
+
+ + +

+Sense of location +

+ +

+Some accessors related to position and orientation of the feeb can +be turned off. + +

+These are the parameters: + +

+ +

    +
  • [*sense-location-p*] Tells if the actual +position of the feeb can be determinated accessing x-position +and y-position. +
  • +
+

+


+
+ +2007-12-19 +
+ + Added: feebs/node22.html ============================================================================== --- (empty file) +++ feebs/node22.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,90 @@ + + + + + +Changing the rules + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Reference + Up: Contests + Previous: Sense of location +   Contents +
+
+ + +

+Changing the rules +

+ +

+To change the rules of the contest, they must be changed before the +feebs are defined, because in a feeb definition it could use the values +of the variables to make a global strategy, and change the strategies +after this could not be fair. + +

+All the parameters that can be listed using (list-parameter-settings) +can be changed using setf. Also, they all have documentation about +themselves, so feel free to use (documentation parameter 'variable) +and see what each parameter does. Documentation is available to external +functions too. + +

+It is possible to change the layout of the map by calling (change-layout new-layout). +There are a few predefined mazes that are *maze-0* +throw *maze-5*. If you want to create a new +map, take the template (commented) inside the same file, or create +maybe a bigger template (of any size, because the values of *maze-x-size* +and *maze-y-size* will be changed accordingly). + +

+


+
+ +2007-12-19 +
+ + Added: feebs/node23.html ============================================================================== --- (empty file) +++ feebs/node23.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,77 @@ + + + + + +Reference + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: About this document ... + Up: The Feebs War + Previous: Changing the rules +   Contents +
+
+ + +

+Reference +

+ +

+

+Fahlman, S. E. Planet of the Feebs - A Somewhat +Educational Game. ftp://ftp.csl.sri.com/pub/users/gilham/feebs/feebs.tex. + +
+ +

+


+
+ +2007-12-19 +
+ + Added: feebs/node24.html ============================================================================== --- (empty file) +++ feebs/node24.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,79 @@ + + + + + +About this document ... + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Up: The Feebs War + Previous: Reference +   Contents +
+
+ + +

+About this document ... +

+ The Feebs War

+This document was generated using the +LaTeX2HTML translator Version 2002-2-1 (1.71) +

+Copyright © 1993, 1994, 1995, 1996, +Nikos Drakos, +Computer Based Learning Unit, University of Leeds. +
+Copyright © 1997, 1998, 1999, +Ross Moore, +Mathematics Department, Macquarie University, Sydney. +

+The command line arguments were:
+ latex2html feebs.tex +

+The translation was initiated by on 2007-12-19 +


+
+ +2007-12-19 +
+ + Added: feebs/node3.html ============================================================================== --- (empty file) +++ feebs/node3.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,138 @@ + + + + + +Changes from Planet of the Feebs + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: The Game + Up: Introduction + Previous: Introduction +   Contents +
+
+ + +

+Changes from Planet of the Feebs +

+ +

+Many changes were made from the original game, but, if you have any +feeb definition and you want to use it, it should be easy to adapt +the brain function to the new rules. + +

+The main reason of this project is that Planet of the Feebs +is really interesting for (not just) newbies to learn lisp, but the +difficulties to install, unportability and the ausence of competitors +make it difficult to someone to be interested in making a feeb. So, +I hope that making these adjustments and maybe creating some contests +over the web make people be more interested in learning lisp. + +

+So, these are (some of) the changes: + +

+ +

    +
  • The graphics are not based on X Window Sistem anymore, but on PAL, +and there are no CMUCL's event handler. This way, the code is more +portable and graphics can be improved without those hundreds of lines +that the original version has. Just creating some .bmp or .jpg files +of a feeb and your feeb is much more personalized! +
  • +
  • Every element of the map (except walls) is a list, so the brain of +a feeb doesn't need to test all the time if the element is an atom +or a list (wich, in my opinion, is really boring, unlispy and unnecessary +in this case). That was only a reason to duplicate code and work, +adding no results at all... +
  • +
  • Many functions and variables are changed and others were added. +
  • +
  • Someone watching the game can control a Feeb with the keyboard, if +he/she wants to, and say when the game must finish. +
  • +
  • This document is more objective than the one provided with Planet +of the Feebs, and is fully compatible with the code. This way it +is easier to search for some information. +
  • +
+ +

+


+ + +next + +up + +previous + +contents +
+ Next: The Game + Up: Introduction + Previous: Introduction +   Contents + +
+ +2007-12-19 +
+ + Added: feebs/node4.html ============================================================================== --- (empty file) +++ feebs/node4.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,83 @@ + + + + + +The Game + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Overview + Up: The Feebs War + Previous: Changes from Planet of +   Contents +
+
+ + +

+The Game +

+ +

+


+ +Subsections + + + +

+
+ +2007-12-19 +
+ + Added: feebs/node5.html ============================================================================== --- (empty file) +++ feebs/node5.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,138 @@ + + + + + +Overview + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Throwing flame + Up: The Game + Previous: The Game +   Contents +
+
+ + +

+Overview +

+ +

+Your feeb's objective is to survive and kill other feebs. It is inside +a maze of tunnels. Every turn, all feebs lose one unit of energy, +and maybe starves. Your feeb is able to move forward, turn left, right +or around, flame, peek around a corner, eat something or just wait. +After all feebs move, the flames thrown before also move (or dissipate), +carcasses may rot and mushrooms may grow, accordingly to some rules. + +

+To see what values are taken, one can use (list-parameter-settings). +Using setf gives the possibility to change them +and documentation can be used to know them. Just +remember that every probability must be a rational number (like 1/2). +These parameters are just for one to know how the game is going to +be, but in the begining there is no need to explicitly use them when +creating the brain of a feeb. + +

+These are some global parameters: + +

+ +

    +
  • [*game-length*] Number of turns the game +will last, or nil if there is a human player. +
  • +
  • [*points-for-killing*] How many points some +feeb earn for killing someone. +
  • +
  • [*points-for-dying*] How many points some +feeb earn for dying (usually negative). +
  • +
  • [*maze-x-size*] Horizontal size of the maze. +
  • +
  • [*maze-y-size*] Vertical size of the maze. +
  • +
  • [(get-maze-map)] This command can be used to +get the map (see section [*]). +
  • +
+

+


+ + +next + +up + +previous + +contents +
+ Next: Throwing flame + Up: The Game + Previous: The Game +   Contents + +
+ +2007-12-19 +
+ + Added: feebs/node6.html ============================================================================== --- (empty file) +++ feebs/node6.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,140 @@ + + + + + +Throwing flame + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Eating food + Up: The Game + Previous: Overview +   Contents +
+
+ + +

+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 +killing feebs it encounters, transforming them into carcass. If there +is a wall, the flame can reflect, and will turn 180 degrees. + +

+Once a feeb is killed, in it's place in the maze there will appear +a carcass. The feeb goes to the end of the killed feebs line. Whenever +a carcass rots, the first feeb in line will reincarnate. So, dying +is not so terrible. + +

+These are the parameters related to flames: + +

+ +

    +
  • [*flame-energy*] Amount of energy lost after +throwing a flame. +
  • +
  • [*fireball-guaranteed-lifetime*] Number of +turns that a fireball is guaranteed not to dissipate, unless it encounters +a wall. +
  • +
  • [*fireball-dissipation-probability*] Probability +of the flame to dissipate each turn after the apropriate time. +
  • +
  • [*fireball-reflection-probability*] Probability +of the flame to reflect when encountering a wall. +
  • +
  • [*flame-no-recovery-time*] Number of turns +that a feeb cannot fire. +
  • +
  • [*flame-recovery-probability*] Probability +of the feeb to recover the hability to throw a flame, after the apropriate +time. +
  • +
+

+


+ + +next + +up + +previous + +contents +
+ Next: Eating food + Up: The Game + Previous: Overview +   Contents + +
+ +2007-12-19 +
+ + Added: feebs/node7.html ============================================================================== --- (empty file) +++ feebs/node7.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,105 @@ + + + + + +Eating food + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: The Feeb + Up: The Game + Previous: Throwing flame +   Contents +
+
+ + +

+Eating food +

+ +

+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 +will be able to recover energy, wich is important because, if a feeb +stays with 0 or less units of energy, it starves. + +

+These are the quantities: + +

+ +

    +
  • [*mushroom-energy*] Amount of energy recovered +when the feeb eats a mushroom. +
  • +
  • [*carcass-energy*] Amount of energy recovered +each turn that the feeb eats a carcass. +
  • +
  • [*carcass-guaranteed-lifetime*] Number of +turns that a carcass will surely stay there. After these turns, it +can rot, depending on probabilities. +
  • +
  • [*carcass-rot-probability*] Probability of +the carcass to rot, after the apropriate time. +
  • +
  • [*maximum-energy*] Maximum amount of energy +that a feeb can have eating. +
  • +
  • [*starting-energy*] Amount of energy a feeb +has when it reincarnates. +
  • +
  • [*number-of-mushrooms*] Quantity of mushrooms +that exist in the maze. +
  • +
+

+


+
+ +2007-12-19 +
+ + Added: feebs/node8.html ============================================================================== --- (empty file) +++ feebs/node8.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,125 @@ + + + + + +The Feeb + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Possible decisions + Up: The Feebs War + Previous: Eating food +   Contents +
+
+ + +

+The Feeb +

+ +

+A feeb needs four things: a name, a brain, an initialize function +(optional) and a set of graphics (optional). + +

+ +

    +
  • The name, a string. +
  • +
  • The brain is a function that decides what the feeb will do next, based +on what it is seeing and feeling. +
  • +
  • The initializer is invoked when the game is about to start, so it +can analyze the map, global parameters, and so on. +
  • +
  • The set of graphics is an image file (of format BMP, JPEG, PNG, and +any others that supported by SDL_image). +
  • +
+One can create a feeb calling (define-feeb name brain :initializer prepare :graphics graphics). +If name is already used, a warning will be signaled, and the old feeb +will be substituted. Calling (list-of-feebs) will +return the list of the feebs (names only) that will be defined when +the game begins. (delete-feeb name) +will delete the feeb with this name from this list, and (delete-all-feebs) +will clear it. + +

+


+ +Subsections + + + +

+
+ +2007-12-19 +
+ + Added: feebs/node9.html ============================================================================== --- (empty file) +++ feebs/node9.html Wed Dec 19 15:36:51 2007 @@ -0,0 +1,142 @@ + + + + + +Possible decisions + + + + + + + + + + + + + + + + + + + + +next + +up + +previous + +contents +
+ Next: Information available + Up: The Feeb + Previous: The Feeb +   Contents +
+
+ + +

+Possible decisions +

+ +

+After processing the information available, the brain will take a +decision. If this decision is not one of the decisions listed down, +a warning will be signaled, and the result will be like :wait. +Then, if someone are testing a brain function, he or she will be able +to know if something goes wrong. + +

+The possible values that the brain function can return are these: + +

+ +

    +
  • [:move-forward] Move one square forward, unless +there is a wall in front of the feeb. +
  • +
  • [:turn-left] Turn 90 degrees to the left. +
  • +
  • [:turn-right] Turn 90 degrees to the right. +
  • +
  • [:turn-around] Turn 180 degrees. +
  • +
  • [:flame] Throw a flame. The flame will be created +next turn in the front square of the feeb. +
  • +
  • [:wait] Do nothing in this turn. +
  • +
  • [:peek-left] Peek to the left around a corner. +The creature does note actually move, but, in the next turn, the creature +will have the same vision that it would have if he had moved one step +foward and turned left. This is used so a feeb can analize a corridor +before trespassing it. +
  • +
  • [:peek-right] Peek to the right around a corner, +analogous of :peek-left. +
  • +
  • [:eat-carcass] Eat a carcass if there is any +available in the feeb's square. The amount of *carcass-energy* +is restored to the feeb's energy. +
  • +
  • [:eat-mushroom] Eat a mushroom if there is any +available in the feeb's square. The amount of *mushroom-energy* +is restored to the feeb's energy. +
  • +
+

+


+ + +next + +up + +previous + +contents +
+ Next: Information available + Up: The Feeb + Previous: The Feeb +   Contents + +
+ +2007-12-19 +
+ + Added: graphics.lisp ============================================================================== --- (empty file) +++ graphics.lisp Wed Dec 19 15:36:51 2007 @@ -0,0 +1,98 @@ +;;; -*- Common Lisp -*- + +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 this program. If not, see . +|# + +(in-package :feebs) + +(defun print-direction (dir) + (case dir + (0 #\N) + (1 #\E) + (2 #\S) + (3 #\W))) + +(defun print-map () + (dotimes (y *maze-y-size*) + (dotimes (x *maze-x-size*) + (let ((elt (aref *maze* x y))) + (apply 'format t + (cond + ((wallp elt) + (list " XX")) + ((feeb-image-p (car elt)) + (list "F~1d~a" + (feeb-id (feeb-image-feeb (car elt))) + (print-direction (feeb-image-facing (car elt))))) + ((fireball-image-p (car elt)) + (list " *~a" (print-direction (fireball-image-direction (car elt))))) + ((eq (car elt) :mushroom) + (list " mm")) + ((eq (car elt) :carcass) + (list " cc")) + (t (list " ")))))) + (format t "~%"))) + +(defun simple-play (&optional layout) + (if layout + (change-layout layout)) + (make-auto-feebs (- 10 (length *feebs-to-be*))) + (initialize-feebs) + (loop repeat *game-length* do + (play-one-turn) (print-map) (sleep 0.3) (format t "~%~%")) + (format t "Fim de jogo!!~%~%Pontua??es:~%~%") + (dolist (feeb *feebs*) + (format t "~a: ~d~%" (name (feeb-status feeb)) (score (feeb-status feeb))))) + + +#| + +;;; Feeb creation. + +;; This a little better version of conservative-brain +;; all others (stupid or redundant) brains of original +;; feebs.lisp were eliminated + (defun simple-brain (status proximity vision vision-left vision-right) + (declare (ignore vision-left vision-right)) + (let ((stuff (my-square proximity))) + (cond ((and (consp stuff) (member :mushroom stuff :test #'eq)) + :eat-mushroom) + ((and (consp stuff) (member :carcass stuff :test #'eq)) + :eat-carcass) + ((and (ready-to-fire status) + (> (energy-reserve status) 30) + (dotimes (index (min (line-of-sight status) 5)) + (if (find-if #'feeb-image-p (aref vision index)) + (return t)))) + :flame) + ((and (not (eq (left-square proximity) :rock)) + (> 2 (random 10))) + :turn-left) + ((and (not (eq (right-square proximity) :rock)) + (> 2 (random 10))) + :turn-right) + ((plusp (line-of-sight status)) + :move-forward) + ((not (wallp (left-square proximity))) + :turn-left) + ((not (wallp (right-square proximity))) + :turn-right) + ((not (wallp (rear-square proximity))) + :turn-around)))) + +|# Added: license ============================================================================== --- (empty file) +++ license Wed Dec 19 15:36:51 2007 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 3 of the License, 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 this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. Added: main.lisp ============================================================================== --- (empty file) +++ main.lisp Wed Dec 19 15:36:51 2007 @@ -0,0 +1,412 @@ +;;; -*- Common Lisp -*- + +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 this program. If not, see . +|# + + +(in-package :feebs) + +;;; Some functions + +(defmacro def-feeb-parm (name value doc) + `(progn + (defvar ,name ,value ,doc) + (pushnew ',name *feeb-parameters*))) + +(defun list-parameter-settings () + (let ((settings nil)) + (dolist (parm *feeb-parameters*) + (push (cons parm (symbol-value parm)) settings)) + settings)) + +(defun chance (ratio) + (< (random (denominator ratio)) (numerator ratio))) + +;;; General game parameters: + +(def-feeb-parm *game-length* 320 + "Number of cycles in the simulation.") + +(def-feeb-parm *number-of-auto-feebs* 0 + "Number of dumb system-provided feebs.") + +(def-feeb-parm *slow-feeb-noop-switch* nil + "If non-null, each feeb has a chance of having its orders aborted in + proportion to the time it takes to produce them. + See *slow-feeb-noop-factor*.") + +(def-feeb-parm *slow-feeb-noop-factor* 1/4 + "If *slow-feeb-noop-switch* is non-null, a feeb's orders will be aborted + with probability equal to the product of this factor times the time + taken by this feeb divided by *reference-time*, if non-nil, or + the total time taken by all feebs this turn otherwise.") + +(def-feeb-parm *reference-time* nil + "Time taken by reference if non-nil. See *slow-feeb-noop-factor*.") + +(def-feeb-parm *sense-location-p* t + "If non-null, x-position and y-position will return nil when + some a behavior function tries to invoke it.") + +;;(def-feeb-parm *sense-facing-p* t +;; "If non-null, facing will return nil when one tries to +;; invoke it.") + +;;; Scoring: + +(def-feeb-parm *points-for-killing* 5 + "Added to one's score for killing an opponent.") + +(def-feeb-parm *points-for-dying* -3 + "Added to one's score for being killed or starving.") + +(def-feeb-parm *points-for-slow-down* -1 + "Points earned when a feeb's move is aborted due to slowness.") + +;;; Cheating + +(def-feeb-parm *exclude-cheater-p* nil + "Tells if a feeb is excluded from the game when a cheating is done.") + +(def-feeb-parm *warn-when-cheating-p* t + "Tells if a continuable error must be signaled when a cheating is done.") + +;;; Characteristics of the maze: + +(def-feeb-parm *may-get-maze-map-p* t + "Tells if the function (get-maze-map) returns the map layout of nil + during the game.") + +(def-feeb-parm *maze-x-size* 32 + "Number of columns in the maze.") + +(def-feeb-parm *maze-y-size* 32 + "Number of rows in the maze.") + +(def-feeb-parm *number-of-mushrooms* 8 + "Average number of mushrooms in the maze at any given time.") + + +;;; Energies: + +(def-feeb-parm *flame-energy* 10 + "Energy used when a feeb flames.") + +(def-feeb-parm *mushroom-energy* 50 + "Energy gained when a mushroom is eaten.") + +(def-feeb-parm *carcass-energy* 30 + "Energy gained by feeding on a carcass.") + +(def-feeb-parm *maximum-energy* 100 + "The most energy a feeb can accumulate.") + +(def-feeb-parm *starting-energy* 50 + "Smallest amount of energy a feeb will start with.") + +;;; Carcasses: + +(def-feeb-parm *carcass-guaranteed-lifetime* 5 + "Minimum number of turns a carcass will hang around.") + +(def-feeb-parm *carcass-rot-probability* 1/3 + "Chance of a carcass rotting away each turn after its guaranteed lifetime.") + + +;;; Fireballs: + +(def-feeb-parm *fireball-dissipation-probability* 1/5 + "Chance that a fireball will dissipate each turn after it is fired.") + +(def-feeb-parm *fireball-reflection-probability* 2/3 + "Chance that a fireball will reflect when it hits a wall.") + +(def-feeb-parm *flame-recovery-probability* 1/3 + "Chance a feeb will regain its ability to flame each turn after flaming once.") + + +;;; Structures: + +;;; The Feeb structure contains all of the info relevant to a particular feeb. +;;; The info available to the brain function is in the Status sub-structure. + +(defstruct (feeb + (:print-function print-feeb) + (:constructor make-feeb (id brain))) + id + brain + image + status + proximity + time + last-score + last-kills + facing + x-position + y-position + (dead-p nil) + (turns-since-flamed 0) + (vision (make-array (max *maze-x-size* *maze-y-size*))) + (vision-left (make-array (max *maze-x-size* *maze-y-size*))) + (vision-right (make-array (max *maze-x-size* *maze-y-size*)))) + +(defstruct (status + (:conc-name nil) + (:constructor make-status (name graphics))) + (name "" :read-only t) + facing + graphics + x-position + y-position + peeking + line-of-sight + (energy-reserve *starting-energy*) + (score 0) + (kills 0) + (ready-to-fire t) + (aborted nil) + (last-move :dead)) + +(defun print-feeb (structure stream depth) + (declare (ignore depth)) + (format stream "#" + (name (feeb-status structure)))) + + +(defstruct (proximity + (:conc-name nil)) + my-square + rear-square + left-square + right-square) + + +;;; These image structures are used to represent feebs and fireballs in +;;; the sensory displays of other feebs. + +(defstruct (feeb-image + (:print-function print-feeb-image) + (:constructor make-feeb-image (name feeb))) + (name "" :read-only t) + facing + (feeb nil :read-only t) + peeking) + +(defun print-feeb-image (structure stream depth) + (declare (ignore depth)) + (format stream "#" + (feeb-image-name structure) + (feeb-image-facing structure))) + +(defstruct (fireball-image + (:print-function print-fireball-image) + (:constructor make-fireball-image (direction owner x y dx dy))) + direction + owner + x + y + dx + dy + (new t)) + +(defun print-fireball-image (structure stream depth) + (declare (ignore depth)) + (format stream "#" + (fireball-image-direction structure))) + +(defstruct (pos (:constructor make-pos (x y))) + x + y) + +;;; Changing the maze +(defun change-layout (layout) + (when *feebs-to-be* + (warn "There are some feebs that have already been defined. +They could have used (get-maze-map). Those are they: +~a." (loop for feeb in *feebs-to-be* collect (first feeb)))) + (let ((x (length layout)) + (y (length (car layout)))) + (loop for string in layout do + (if (/= (length string) y) + (error "Not all the strings in ~a have the same size." layout))) + (setf *layout* layout + *maze-y-size* y + *maze-x-size* x))) + +(defun get-maze-map () + (when *may-get-maze-map-p* + (unless (and *maze* *fake-maze*) + (init-maze)) + (let ((new-maze (make-array (list *maze-x-size* *maze-y-size*)))) + (dotimes (x *maze-x-size*) + (dotimes (y *maze-y-size*) + (setf (aref new-maze x y) (aref *fake-maze* x y)))) + new-maze))) + +(defun init-maze () + (setf *maze* (make-array (list *maze-x-size* *maze-y-size*)) + *fake-maze* (make-array (list *maze-x-size* *maze-y-size*)) + *entry-points* nil) + (do ((rows *layout* (cdr rows)) + (i (1- *maze-y-size*) (1- i))) + ((null rows)) + (let ((str (car rows))) + (dotimes (j (length str)) + (setf (aref *maze* j i) nil + (aref *fake-maze* j i) nil) + (case (schar str j) + (#\X + (setf (aref *maze* j i) :rock + (aref *fake-maze* j i) :rock)) + (#\* + (setf (aref *fake-maze* j i) :mushroom-place) + (push (make-pos j i) *mushroom-sites*)) + (#\e + (setf (aref *fake-maze* j i) :feeb-entry-place) + (push (make-pos j i) *entry-points*)) + (#\space nil) + (t + (error "Unknown spec in maze: ~C." (schar str j)))))))) + +(defun initialize-feebs () + (setf *mushrooms-alive* *number-of-mushrooms* + *dead-feebs* nil + *fireballs-flying* nil + *continue* t + *mushroom-sites* nil + *entry-points* nil + *carcasses* nil + *static-parameters* + (loop for (symbol . value) in (list-parameter-settings) + collect value)) + (init-maze) + (setf *number-of-mushroom-sites* (length *mushroom-sites*) + *number-of-entry-points* (length *entry-points*)) + (create-feebs)) ; The feebs are defined here + +(defun create-mushrooms () + (dotimes (i (- *number-of-mushrooms* (length *mushrooms-alive*) (random 3))) + (do ((site (nth (random *number-of-mushroom-sites*) *mushroom-sites*) + (nth (random *number-of-mushroom-sites*) *mushroom-sites*))) + ((null (aref *maze* (pos-x site) (pos-y site))) + (setf (aref *maze* (pos-x site) (pos-y site)) :mushroom))))) + +;;; Setting up the feebs. + +(defvar *feebs* nil + "A list of all the feebs in the current game.") + +(defvar *next-feeb-id* 0 + "A counter used to assign a unique numerical code to each feeb.") + +;;; Define-Feeb builds a list of feebs to create. Create-Feebs actually +;;; builds the feebs on this list. + +(defvar *feebs-to-be* nil) + +(defun define-feeb (name brain &optional prepare graphs) + (if (delete-feeb name) + (warn "Feeb ~s already exists, deleting..." name)) + (push (list name brain prepare graphs) *feebs-to-be*)) + +(defun delete-feeb (name) + (not + (equal *feebs-to-be* + (setf *feebs-to-be* + (remove name *feebs-to-be* :key #'car :test #'string=))))) + +(defun create-feebs () + (flet ((create-feeb (name brain prepare graphs) + (let ((pos (pick-random-entry-point)) + (feeb (make-feeb *next-feeb-id* brain))) + (incf *next-feeb-id*) + (setf (feeb-image feeb) + (make-feeb-image name feeb) + (feeb-status feeb) + (make-status name nil); (sdl:load-and-convert-image graphs)) + (feeb-proximity feeb) + (make-proximity)) + (change-feeb-pos feeb (pos-x pos) (pos-y pos)) + (change-feeb-facing feeb (random 4)) + (push feeb *feebs*) + (place-object (feeb-image feeb) (pos-x pos) (pos-y pos)) + (when prepare + (let (*static-parameters* *fake-maze*) + (funcall prepare)) + (check-cheating name))))) + (setf *feebs* nil + *next-feeb-id* 0) + (dolist (feeb-spec (reverse *feebs-to-be*)) + (apply #'create-feeb feeb-spec)))) + +;;; Start at some randomly chosen entry point. If this one is occupied, +;;; scan successive entry points until a winner is found. Circle back +;;; to start of list if necessary. + +(defun pick-random-entry-point () + (do ((points (nth (random *number-of-entry-points*) *entry-points*) + (nth (random *number-of-entry-points*) *entry-points*))) + (nil) + (when (null (aref *maze* (pos-x points) + (pos-y points))) + (return points)))) + +;;; Movement interface. + +(defun delete-object (thing x y) + (when (eq thing :mushroom) + (decf *mushrooms-alive*)) + (setf (aref *maze* x y) + (delete thing (aref *maze* x y)))) + +(defun place-object (thing x j) + (when (eq thing :mushroom) + (incf *mushrooms-alive*)) + (push thing (aref *maze* x j))) + +;;; Functions to change optional structure in status + +(defun change-feeb-pos (feeb x y) + (setf (feeb-x-position feeb) x + (feeb-y-position feeb) y) + (if *sense-location-p* + (setf (x-position (feeb-status feeb)) x + (y-position (feeb-status feeb)) y))) + +(defun change-feeb-facing (feeb facing) + (setf (feeb-facing feeb) +;; ;; use this code to make *sense-facing-p* available +;; ;; but be carefull - it does not really work +;; (if (or *sense-location-p* *sense-facing-p*) +;; (setf (facing (feeb-status feeb)) +;; facing) +;; facing) + (setf (facing (feeb-status feeb)) + (setf (feeb-image-facing (feeb-image feeb)) + facing)))) + +(defun kill-feeb (feeb) + (setf *dead-feebs* (nconc *dead-feebs* (list feeb)) + (feeb-dead-p feeb) t) + (let* ((status (feeb-status feeb)) + (x (feeb-x-position feeb)) + (y (feeb-y-position feeb))) + (push (list 0 x y) *carcasses*) + (incf (score status) *points-for-dying*) + (delete-object (feeb-image feeb) x y) + (place-object :carcass x y))) Added: mazes.lisp ============================================================================== --- (empty file) +++ mazes.lisp Wed Dec 19 15:36:51 2007 @@ -0,0 +1,238 @@ +;;; -*- Common Lisp -*- + +;;; Mazes for Planet of the Feebs. +;;; A somewhat educational simulation game. +;;; +;;; Created by Jim Healy, July 1987. +;;; +;;; ************************************************** +;;; Maze guidelines: +;;; Maze should be *maze-i-size* by *maze-j-size* +;;; (currently 32 x 32). +;;; X represents a wall. +;;; * represents a mushroom patch. +;;; e is a feeb entry point. +;;; ************************************************** + +;;; Maze1 has a good number of dead ends and little nooks. + +(in-package :feebs) + +(defparameter *maze-1* + '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXX *eXXXX *e ** X" + "XXX XXXXX XXXX XXXXXXXXXXXX XX X" + "XXX XXX XXXXXX X X" + "XXXXX XXXXXXX XXXXXXX XXXXXXX XX" + "X * XXX XX * XeXX XX" + "X XXXXXXX XXX XXXXXXX X XXX XXXX" + "X XXXXXX XXX XX X *XX" + "X XXXXXXX XXX XXXXXXX XXXXXXXXXX" + "X XXXXXXX XXX* e XXXXXX XXX" + "X XXXXX XXXXXXXXX * XXX" + "X XXXXX XXXXXX XXXXXX XX XX" + "X eXXXX XXXXXX XXX XXXXX XX XXX" + "X XXXXX* XXXXe XXXX XX XX" + "X XXXXX XXXXXX XXXXX XXX XXX XX" + "X eXXXX e XXXXXX *XX XX XX" + "X XXXXX XXXXXX XXXXXXX X XXeXXX" + "X XXX XXXXXXXX XX XX" + "X XXXXX XXXXXX XXXXXXXXXX XXXXXX" + "X XXXXX * XXXXX XX" + "X* XXX XXXXXX XXXXX XXXXXX X XX" + "X XXXXX e XXXXX X e X XX" + "X XX XX XXXXXX XXXXX X XXXXXX XX" + "X *XXX XXXXX * XX" + "X XX XX XXXXXX XXXXXXXXXX XXXXXX" + "X XXXXX XXXXXX * * XX" + "X XXX XXXXXXXXXXXXXXXXXXXXX XX" + "X XXXX X X eX X XX" + "X XXX XX X XX X XX X XX X XX XX" + "X XXXX XX X XX X XX X XX*X XX XX" + "X e * XX XX * XX XX XXeXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) + +;;; Maze2 doesn't have any really long corridors. + +(defparameter *maze-2* + '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "X eXXXXX * X XXXXXX X e XXXXX" + "X XXXX X X XXXX X X XXXXX" + "X XX XXXX XXXX X* X X XXXXX" + "XX XX XXX XXXX XX XX X X" + "XX e XXX XXXXXXX XX XXXXXXXX*X" + "XXXX XXX XXXXX X e XXX XX X" + "XXXX XXX XXXXXXXX XXXX X X" + "XX * XX XXe XXXXXXXXXX XX XXX" + "XX XXXX X XX X XXX XXXXX XXX" + "XX XX XXX X XX XXXXX" + "XXXXX XXX *XXX X XXXXXXXX" + "XX* XXXXXX XXXX XXXX XXXXXXXX" + "XXXXX XX XXXX XXXXXXXXX XXXXXXXX" + "XXXXX e XXXX *XXXXXX eXXXXX" + "XXXXXXXX XXXXXXX XXXXXXXXX XXXXX" + "XXXXXX XXXXX eXXXXX XXXXX" + "XXXXXX XXX XXXXXXX XXXXX XXXXXXX" + "XX XXX X XXX XX X XX" + "XX XXX XXXXX XX XX XXX XX XX" + "XX XXXXX *X XX X XX XXXXXX*XX" + "X XXXXX XXXX X XX XX" + "X XX XXXXXXX XXXXX*X X Xe XXXX" + "X XXXX e X XXXXX*XX XX XXXX" + "X XX XXXXXX XX XXX*XXX XXX" + "XXXX eXXX XXXX XX XXXXX X X" + "XXXXXX XXXXXXXXX XX XXXX XXX X" + "XXX * X X XX XXXX XXX X X" + "XX XXXX X XX XXXX XXX X e X" + "XX XX * X * X XXXX XX XXX*X" + "XX XXX XXX XX eXXX XXX*X" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) + +;;; Maze3 has the minimum number of mushroom sites, most +;;; of which are between a rock and a hard place. Those +;;; poor feebs! + +(defparameter *maze-3* + '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "X e XXXXXX XXXXXXX*XXXXXXXXX" + "X X XXX XXXXX e XXXX XXX e X" + "X XXX XXXXXX XX XX XXX XXX X" + "XXX XXX XXXXXX XX XX X X e X" + "Xe XXX*XXXX* XX XXeX X XXXXX X" + "X X XXX XXXXXX XX XX X XXXXX X" + "X XXX XXXXXX XX* XXXXXXXXX X" + "X XXXXX XX e XX XXXXXXXX XXX X" + "X X XXX XXX XXXXX XXXXXX XXX X" + "Xe XXX XXXX XXXX X X X" + "XXX XXXX XXXXXXXX X XXX XXX" + "XXX eXX XXXXXXXXX XXXXX XXXXX" + "XXXXX XXXXXXXXXXXX XXXXXX XXX" + "XXXXX * XX eXX XXX XX XXX" + "XX*XXXX XXXXXX XX XXX XXX XX XXX" + "XX X XXXXX X XXX eXX XXX" + "X XXXXXXXX XX XXXX XXX XX XXX" + "X XXXXeXXXXXX XXXX XXX XX XXX" + "X XX*XXXXX XXXXXXXXX XXX" + "XXXXXX XXX XXXX XXXXXX XXX" + "XXXXXXXXX XXX XXXXXX XXXXXX XXX" + "XXX XX e eX XXXX" + "XX XXXXX XXXX XXXX XXXX XXXX" + "XX XXXXX XX XXXX XXXX XXXX XX" + "XX eXXXX XX XXXX XXXX XXXXXX XX" + "XXX XX XXX * XXX XX" + "XX XX XXXX* XXXX XXXX XXXXXX XX" + "XXX X XXXXX XXXX XXXX X XX" + "XXXX e XXXX XXXX X XX X X" + "XXXXXXXXXXXX *e X e XX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) + + +;;; Maze4 is symmetric about the vertical axis. (Wow...) + +(defparameter *maze-4* + '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "X* eXXXXXXXXXXe *X" + "X XXXXXXXX XXXXXXXX X" + "X XX XXXXXXX XX XXXXXXX XX X" + "X XeXXXXXXX XX XXXXXXXeX X" + "XX X XXXXXXX eXXe XXXXXXX X XX" + "XX X XXXXXXX XXXXXX XXXXXXX X XX" + "XX * XXXXXXX XXXXXX XXXXXXX * XX" + "XX X XXXe eXXX X XX" + "XX X XXX XXXXXXXXXXXXXX XXX X XX" + "XX e XXX XXXXXXXX XXX e XX" + "XX X XXXXXX XXXXXXXX XXXXXX X XX" + "XX X XXXX XXXXXXXX XXXX X XX" + "XX XXXX XXXe eXXXX XXXX XX" + "XXX XXXXX XXX XXX XXXX XXXXX XXX" + "XXX XXXXX XXX XXX XXXXX XXX" + "X* XXXXX XXXX XXXXX *X" + "X XXXXX XX XX ** XX XX XXXXX X" + "X XXXXX XX XX XXXX XX XX XXXXX X" + "X XXX e XX XX XXXX XX XX e XXX X" + "X XXXXX XX XXXX XX XXXXX X" + "X XXXXX XXXXX XXXX XXXXX XXXXX X" + "X X XXXXX XXXX XXXXX X X" + "XXXXX * * XXXXX" + "XXXXX XXXXXXXX XX XXXXXXXX XXXXX" + "XXXXX XXXXXXXX XX XXXXXXXX XXXXX" + "XXXXX XXXXX XX XXXXX XXXXX" + "XXXX XX XXXXeXXeXXXX XX XXXX" + "XXX XXXX XXX XX XXX XXXX XXX" + "XXX XXXXXX XXX XX XXX XXXXXX XXX" + "XX* e XX e *XX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) + +;;; Maze5 has a lot of long corridors good for feeb showdowns. +;;; Furthermore, all the feeb entry-points are in the corridors. +;;; You can run but you can't hide! + +(defparameter *maze-5* + '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "X e e X" + "X XXXXXXX*XXXXXXXXXXXX XXXXXXX X" + "X e X" + "X X XXXXX XXXXXXXXXXXX XXXXX X X" + "X * X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X X XX XX XXXXXXXXXXXX XXeXX X X" + "X X XX XX * XX XX X X" + "XeX XX XX XXXXXXXXXXXX XX XX X X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X X XX XX e XX XXeX X" + "X X XXeXX XXXXXXXXXXXX XX XX X X" + "X X XX XX XXXXXXXXXXXX XX XX XeX" + "X*X XX XX XX XX X X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X XeXX XX XXXXXXXXXXXX*XX XX X X" + "X X XX XX * XX XX*X X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X X XX XX e XX XX*X X" + "X X XX*XX XXXXXXXXXXXX XX XX X X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X X XX XX XX XXeX X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X X XX XX XXXXXXXXXXXX XX XX X X" + "X e X" + "X*X XXXXX XXXXXXXXXXXX XXXXX X*X" + "X e * X" + "X XXXXXXX XXXXXXXXXXXX XXXXXXX X" + "X e * X" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) + +;;; Use this template to create new mazes. + +#| (defparameter *maze-template* + '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) |# Added: package.lisp ============================================================================== --- (empty file) +++ package.lisp Wed Dec 19 15:36:51 2007 @@ -0,0 +1,211 @@ +;;; -*- Common Lisp -*- + +#| Copyright (c) 2007 Gustavo Henrique Milar?? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 this program. If not, see . +|# + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; ;;; +;;; The Feebs War ;;; +;;; ;;; +;;; Written by Gustavo Henrique Milar?? ;;; +;;; ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; The GPL should in the file "license", provided with the software. + +;;; based on Planet of the Feebs + +;;; About Planet of the Feebs: +;; +;; Written by Skef Wholey. +;; Modified by Scott Fahlman. +;; Modified by Dan Kuokka. +;; Modified by Jim Healy. +;; +;; Graphics ported to X11 by Fred Gilham 8-FEB-1998. +;; +;; +;;; This project exists thanks to them + + +(defpackage :feebs + (:use :common-lisp) + ;; Export everything we want the players to get their hands on. + (:export *number-of-feebs* *game-length* + *number-of-auto-feebs* + + ;; Strategic quantities + *points-for-killing* *points-for-dying* + *flame-energy* *mushroom-energy* *carcass-energy* + *maximum-energy* + *starting-energy* + + ;; Game quantities + *maze-x-size* + *maze-y-size* + *number-of-mushrooms* + + ;; Probabilities + *carcass-guaranteed-lifetime* + *carcass-rot-probability* + *fireball-dissipation-probability* + *fireball-reflection-probability* + *flame-recovery-probability* + + ;; Difficulty variables + *slow-feeb-noop-switch* + *slow-feeb-noop-factor* + *sense-location-p* +;; *sense-facing-p* ;; if this will be used, one must find a way to +;; ;; a feeb detect other feeb's facing, and fireball's +;; ;; direction, only relative to the feeb (in the brain call) +;; ;; should not be so difficult + *may-get-maze-map-p* + + ;; Slots accessors + name facing + x-position y-position peeking line-of-sight + energy-reserve + score kills + ready-to-fire + aborted last-move + + my-square left-square right-square rear-square + + ;; Images + feeb-image-p feeb-image-name + feeb-image-facing feeb-image-peeking + fireball-image-p fireball-image-direction + + ;; Functions + list-parameter-settings + define-feeb delete-feeb + feebs + change-layout + get-maze-map + + ;; Constants + north south east west + + ;; Some layouts (can be find in mazes.lisp) + *maze-1* *maze-2* *maze-3* *maze-4* *maze-5* + *maze-template* + + ;; Graphics + create-graphics + + ;; Extras + + ;; Directional arithmetic + left-of right-of behind-of + relative-facing + + forward-dx forward-dy + left-dx left-dy + right-dx right-dy + behind-dx behind-dy + + ;; Others + wallp + + ;; Graphics for alpha release + simple-play print-map)) + +(in-package :feebs) + +;;; Directions + +(defconstant north 0) +(defconstant east 1) +(defconstant south 2) +(defconstant west 3) + + +;;; Parameters that affect strategy of the game. + +(defvar *number-of-mushroom-sites* 0) +(defvar *feeb-parameters* nil) + +;;; These are for security + +(defvar *static-parameters* nil) + +;;; Setting up the maze. + +;;; The default maze. +;;; X represents a wall, +;;; * represents a mushroom patch, and +;;; e is a feeb entry point. + +(defvar *maze* nil) +(defvar *fake-maze* nil) + +(defparameter *layout* + '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" + "Xe * XXXXXXX XXXXXXXXXX" + "XXXXX XXXXXXX XXXXXXX * XXXXX" + "XXXXX XXXXXXX XXXXXXX XXX XXXXXX" + "XXXXX XXX XXX XXXXXXeXXX XXXXXX" + "XXXXX XXX XXXX XXXXXXXXXX XXXXXX" + "XXXXX XXX XXXX XX XXXXXXX XXXXXX" + "XXXXX * XX XX XXXXXXX XXXXXX" + "XXXXX XXXX XXX XX* * XXXXXX" + "XX *XXXX XXX XX XXXX XXXXXXXXX" + "XX XX XXXXeXXX XX XXXX XXXXXXXXX" + "XX XX XXXX XXX * * * X" + "XX XX XXXX XXXXXXXX XXXXXXXXXXeX" + "XXeXX XXXX XXXXXXXX XXXXXXXXXX X" + "XX XX * * XXXXXXXX X" + "XX XXXXXXXXXXX XXXX XXXXXXXX XXX" + "XX eXXXXXXXXXX XXXe XXXXXX XXX" + "XX XXXXXXXXXXXXe XXXXXXXXXXX XXX" + "XX* XXX XXXXXXX XXXXXXXXXX XXX" + "XX X XX XXXXXXXX eXXXXXXXXX XXX" + "XX XX X XXXXXXXXX XXXXXXXX XXX" + "X XXX * XXXXXX* * X" + "X XXXXXX XXX XXXXXX XXXXXXXXXX X" + "X XXXXXX XXX XXXXXX X X X" + "X XXXXXX XXX XXXXXX X XXXXXX X X" + "X * * XX X X *eX X X" + "XXXXX XXXX XXXXXXXX X XXX XX X X" + "XXXXX XXXX XXXXX *X XXX XX X X" + "XXXXX XXXX XXXXX XX X e X X" + "XXXXX XXXX e XX XXX*XXXXXX X" + "XXXXX XXXXXXXXXXXXX X" + "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) + +(defparameter *maze-x-size* 32) +(defparameter *maze-y-size* 32) + + +;;; Quantities during the game + +(defvar *mushroom-sites*) +(defvar *entry-points*) +(defvar *number-of-entry-points*) +(defvar *mushrooms-alive*) + +;;; Elements in the maze + +(defvar *fireballs-flying*) +(defvar *dead-feebs*) +(defvar *carcasses*) + +(defvar *continue*) + Added: system.lisp ============================================================================== --- (empty file) +++ system.lisp Wed Dec 19 15:36:51 2007 @@ -0,0 +1,304 @@ +;;; -*- Common Lisp -*- + +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 this program. If not, see . +|# + + +(in-package :feebs) + +(defun reincarnate-feeb (feeb) + (let ((pos (nth (random (length *entry-points*)) *entry-points*)) + (status (feeb-status feeb))) + (place-object (feeb-image feeb) + (pos-x pos) (pos-y pos)) + (change-feeb-pos feeb (pos-x pos) (pos-y pos)) + (change-feeb-facing feeb (random 4)) + (setf (feeb-dead-p feeb) nil + (ready-to-fire status) t + (energy-reserve status) *starting-energy* + (last-move status) :dead))) + + +;;; Vision calculation. + +;;; These guys tell us offsets given an orientation. + +(defun compute-vision (feeb) + (let ((status (feeb-status feeb)) + (proximity (feeb-proximity feeb)) + (vision (feeb-vision feeb)) + (vision-left (feeb-vision-left feeb)) + (vision-right (feeb-vision-right feeb)) + (facing (feeb-facing feeb)) + vision-dx + vision-dy + (x (feeb-x-position feeb)) + (y (feeb-y-position feeb))) + ;; First fill in proximity info. + (setf (my-square proximity) + (aref *maze* x y) + (left-square proximity) + (aref *maze* (+ x (left-dx facing)) (+ y (left-dy facing))) + (right-square proximity) + (aref *maze* (+ x (right-dx facing)) (+ y (right-dy facing))) + (rear-square proximity) + (aref *maze* (+ x (behind-dx facing)) (+ y (behind-dy facing)))) + ;; The vision vector starts in the square the feeb is facing. + (setf x (+ x (forward-dx facing)) + y (+ y (forward-dy facing))) + ;; Figure out which direction to scan in. + (case (peeking status) + (:left (setf facing (left-of facing))) + (:right (setf facing (right-of facing)))) + (setf vision-dx (forward-dx facing) + vision-dy (forward-dy facing)) + ;; compute vision, vision-left and vision-right + (do* ((x x (+ x vision-dx)) + (y y (+ y vision-dy)) + (left-wall-x (+ x (left-dx facing)) (+ left-wall-x vision-dx)) + (left-wall-y (+ y (left-dy facing)) (+ left-wall-y vision-dy)) + (right-wall-x (+ x (right-dx facing)) (+ right-wall-x vision-dx)) + (right-wall-y (+ y (right-dy facing)) (+ right-wall-y vision-dy)) + (index 0 (1+ index))) + ((wallp (aref *maze* x y)) + (setf (aref vision index) (aref *maze* x y) + (aref vision-left index) :unknown + (aref vision-right index) :unknown + (line-of-sight status) index)) + (setf (aref vision index) (aref *maze* x y) + (aref vision-left index) + (side-imagify (aref *maze* left-wall-x left-wall-y) + (right-of facing)) + (aref vision-right index) + (side-imagify (aref *maze* right-wall-x right-wall-y) + (left-of facing)))))) + +;;; Compute the info to be put into the vision-left and vision-right vectors. +;;; A peeking feeb must be facing in the specified direction in order to count. + +(defun side-imagify (stuff facing) + (cond + ((wallp stuff) + stuff) + ((find-if #'(lambda (thing) + (and (feeb-image-p thing) + (peeking (feeb-status (feeb-image-feeb thing))) + (= facing (feeb-image-facing thing)) + (setf facing thing))) + stuff) + (peeking (feeb-status (feeb-image-feeb facing)))) + (t nil))) + +;;; Movement. + +;;; Each turn, the following stuff has to happen: +;;; 1. Bump the turn counter; end the game if we should. +;;; 2. Maybe grow some mushrooms. +;;; 3. Maybe disappear some carcasses. +;;; 4. Move fireballs around. +;;; 5. See if any feebs have starved. +;;; 6. See if any feebs can flame again. +;;; 7. Compute vision and stuff for feebs. +;;; 8. Collect the feebs' moves. +;;; 9. Do the feeb's moves. + +(defun play-one-turn () + ;; Grow some mushrooms: + (dotimes (x (- *number-of-mushrooms* *mushrooms-alive*)) + (let* ((site (nth (random *number-of-mushroom-sites*) *mushroom-sites*)) + (x (pos-x site)) + (y (pos-y site))) + (unless (member :mushroom (aref *maze* x y)) + (place-object :mushroom x y)))) + ;; Rot some carcasses: + (dolist (carc *carcasses*) + (when (and + (> (incf (first carc) *carcass-guaranteed-lifetime*)) + (chance *carcass-rot-probability*)) + (delete-object :carcass (second carc) (third carc)) + (setf *carcasses* (delete carc *carcasses*)) + (if *dead-feebs* + (reincarnate-feeb (pop *dead-feebs*))))) + ;; Move some fireballs: + (dolist (fireball *fireballs-flying*) + (move-one-fireball fireball)) + ;; Starve some feebs: + (dolist (feeb *feebs*) + (unless (feeb-dead-p feeb) + (when (<= (decf (energy-reserve (feeb-status feeb))) 0) + (kill-feeb feeb)))) + ;; Let some feebs regain the power to flame: + (dolist (feeb *feebs*) + (unless (and (feeb-dead-p feeb) + (ready-to-fire (feeb-status feeb))) + (when (and (> (incf (feeb-turns-since-flamed feeb)) + 1) + (chance *flame-recovery-probability*)) + (setf (ready-to-fire (feeb-status feeb)) t)))) + ;; Collect all the feebs' moves, keeping track of the time each one takes. + (let ((total-time 1)) + (dolist (feeb *feebs*) + (unless (feeb-dead-p feeb) + (compute-vision feeb) ; Compute vision for all the feeb. + (let ((time (get-internal-real-time))) + (let ( *static-parameters* *fake-maze*) + (setf (last-move (feeb-status feeb)) + (funcall (feeb-brain feeb) + (feeb-status feeb) + (feeb-proximity feeb) + (feeb-vision feeb) + (feeb-vision-left feeb) + (feeb-vision-right feeb)) + time (- (get-internal-real-time) time))) + (incf total-time time) + (setf (feeb-time feeb) time)))) + ;; Do all the feebs' moves, or perhaps abort the move according + ;; to the time taken by the feeb. + (setf total-time (float total-time)) + (dolist (feeb *feebs*) + (unless (feeb-dead-p feeb) + (if (and *slow-feeb-noop-switch* + (< (random 1.0) + (* *slow-feeb-noop-factor* + (/ (float (feeb-time feeb)) + (or *reference-time* total-time))))) + (progn + (setf (aborted (feeb-status feeb)) t) + (incf (score (feeb-status feeb)) *points-for-slow-down*)) + (progn + (setf (aborted (feeb-status feeb)) nil) + (do-move feeb (last-move (feeb-status feeb))))) + ;; Make the image consistent with the feeb. + (setf (feeb-image-facing (feeb-image feeb)) + (feeb-facing feeb)))))) + +(defun move-one-fireball (fireball) + (let ((x (fireball-image-x fireball)) + (y (fireball-image-y fireball))) + ;; Remove fireball from current square, unless it is new. + (if (fireball-image-new fireball) + (setf (fireball-image-new fireball) nil) + (delete-object fireball x y)) + ;; The fireball might dissipate. + (when (chance *fireball-dissipation-probability*) + (setq *fireballs-flying* (delete fireball *fireballs-flying*)) + (return-from move-one-fireball nil)) + ;; Now move it to new coordinates. + (incf x (fireball-image-dx fireball)) + (incf y (fireball-image-dy fireball)) + ;; If it hits rock, either reflect or dissipate. + (when (wallp (aref *maze* x y)) + (cond ((chance *fireball-reflection-probability*) + (setf (fireball-image-dx fireball) + (- (fireball-image-dx fireball))) + (setf (fireball-image-dy fireball) + (- (fireball-image-dy fireball))) + (setf (fireball-image-direction fireball) + (behind (fireball-image-direction fireball))) + (setq x (fireball-image-x fireball)) + (setq y (fireball-image-y fireball))) + (t (setq *fireballs-flying* + (delete fireball *fireballs-flying*)) + (return-from move-one-fireball nil)))) + ;; Now put the fireball into the new square. + (setf (fireball-image-x fireball) x) + (setf (fireball-image-y fireball) y) + (place-object fireball x y) + ;; And destroy whatever is there. + (delete-object :mushroom x y) + (dolist (thing (aref *maze* x y)) + (if (feeb-image-p thing) + (score-kill fireball (feeb-image-feeb thing)))))) + +;;; The fireball kills the feeb. Update score for killer and victims. +;;; No credit for the kill if you shoot yourself. + +(defun score-kill (fireball feeb) + (unless (eq (fireball-image-owner fireball) feeb) + (incf (score (feeb-status (fireball-image-owner fireball))) + *points-for-killing*) + (incf (kills (feeb-status (fireball-image-owner fireball))))) + (kill-feeb feeb)) + +;;; Doing feeb moves. + +(defun do-move (feeb move) + (let ((status (feeb-status feeb)) + (facing (feeb-facing feeb))) + ;; Peeking gets undone every move. + (setf (peeking status) + (setf (feeb-image-peeking (feeb-image feeb)) nil)) + (case move + (:turn-left + (change-feeb-facing feeb (left-of facing))) + (:turn-right + (change-feeb-facing feeb (right-of facing))) + (:turn-around + (change-feeb-facing feeb (behind facing))) + (:move-forward + (let* ((old-x (feeb-x-position feeb)) + (old-y (feeb-y-position feeb)) + (new-x (+ (forward-dx facing) old-x)) + (new-y (+ (forward-dy facing) old-y)) + (stuff (aref *maze* new-x new-y))) + (when (wallp stuff) + (return-from do-move nil)) + (delete-object (feeb-image feeb) old-x old-y) + (change-feeb-pos feeb new-x new-y) + (place-object (feeb-image feeb) new-x new-y) + ;; Look for a fireball in the destination square. + (let ((thing (find-if #'fireball-image-p stuff))) + (when thing + (score-kill thing feeb) + (return-from do-move nil))))) + (:flame + (when (ready-to-fire status) + (let* ((x (feeb-x-position feeb)) + (y (feeb-y-position feeb)) + (fireball (make-fireball-image + facing feeb x y + (forward-dx facing) (forward-dy facing)))) + ;; Queue the fireball, marked as new, but don't put it on map yet. + (push fireball *fireballs-flying*) + (decf (energy-reserve status) *flame-energy*) + (setf (ready-to-fire status) nil) + (setf (feeb-turns-since-flamed feeb) 0)))) + (:eat-mushroom + (let* ((x (feeb-x-position feeb)) + (y (feeb-y-position feeb))) + (when (member :mushroom (aref *maze* x y)) + (delete-object :mushroom x y) + (setf (energy-reserve status) + (min (+ (energy-reserve status) *mushroom-energy*) + *maximum-energy*))))) + (:eat-carcass + (let* ((x (feeb-x-position feeb)) + (y (feeb-y-position feeb))) + (when (member :carcass (aref *maze* x y)) + (setf (energy-reserve status) + (min (+ (energy-reserve status) *carcass-energy*) + *maximum-energy*))))) + ((:peek-left :peek-right) + (unless (wallp (aref *maze* (+ (feeb-x-position feeb) + (forward-dx facing)) + (+ (feeb-y-position feeb) + (forward-dy facing)))) + (setf (peeking status) + (setf (feeb-image-peeking (feeb-image feeb)) move)))) + (:wait nil) + (t (warn "Unknown feeb movement: ~a." move))))) From gmilare at common-lisp.net Thu Dec 20 20:15:24 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Thu, 20 Dec 2007 15:15:24 -0500 (EST) Subject: [the-feebs-war-cvs] r3 - Message-ID: <20071220201524.A20D93D0B8@common-lisp.net> Author: gmilare Date: Thu Dec 20 15:15:24 2007 New Revision: 3 Removed: feebs.asd Log: From gmilare at common-lisp.net Thu Dec 20 20:15:52 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Thu, 20 Dec 2007 15:15:52 -0500 (EST) Subject: [the-feebs-war-cvs] r4 - Message-ID: <20071220201552.598E73D0B8@common-lisp.net> Author: gmilare Date: Thu Dec 20 15:15:52 2007 New Revision: 4 Removed: brains.fasl Log: From gmilare at common-lisp.net Thu Dec 20 20:16:45 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Thu, 20 Dec 2007 15:16:45 -0500 (EST) Subject: [the-feebs-war-cvs] r5 - Message-ID: <20071220201645.12A4A3D0B8@common-lisp.net> Author: gmilare Date: Thu Dec 20 15:16:44 2007 New Revision: 5 Modified: brains.lisp extra.lisp graphics.lisp main.lisp package.lisp system.lisp Log: Modified: brains.lisp ============================================================================== --- brains.lisp (original) +++ brains.lisp Thu Dec 20 15:16:44 2007 @@ -5,7 +5,6 @@ ;;; Modified from "cautious-brain" - (defun auto-brain (status proximity vision vision-left vision-right) (declare (ignore vision-left vision-right)) (let ((stuff (my-square proximity))) Modified: extra.lisp ============================================================================== --- extra.lisp (original) +++ extra.lisp Thu Dec 20 15:16:44 2007 @@ -98,6 +98,9 @@ (the boolean (eq :rock thing))) +(defun chance (ratio) + (< (random (denominator ratio)) (numerator ratio))) + #| ;;; Handling the vision, vision-left and vision-right objects (defmacro with-visible-elements ((count line-of-sight) Modified: graphics.lisp ============================================================================== --- graphics.lisp (original) +++ graphics.lisp Thu Dec 20 15:16:44 2007 @@ -54,7 +54,7 @@ (make-auto-feebs (- 10 (length *feebs-to-be*))) (initialize-feebs) (loop repeat *game-length* do - (play-one-turn) (print-map) (sleep 0.3) (format t "~%~%")) + (play-one-turn) (print-map) (sleep 0.7) (format t "~%~%")) (format t "Fim de jogo!!~%~%Pontua??es:~%~%") (dolist (feeb *feebs*) (format t "~a: ~d~%" (name (feeb-status feeb)) (score (feeb-status feeb))))) @@ -62,12 +62,125 @@ #| + +(defconst *default-graphics* + (make-feeb-graphics + (load-and-convert-image "default-feeb.bmp"))) + +(defvar *cell-width* 32) +(defvar *cell-heigth* 32) + +(defstruct graphic + (walk (make-direction)) + (flaming (make-direction))) + +(defstruct (direction (:conc-name nil)) + (up (make-array 3)) + (left (make-array 3)) + (down (make-array 3)) + (right (make-array 3))) + +(defun make-feeb-graphics (surface) + + (let ((graphic (make-graphic))) + (progn + (loop for field in '(walk flaming) + and y0 from 0 by (* 4 *cell-heigth*) do + (loop for dir in '(up left right down) + and y from y0 by *cell-heigth* do + (loop for ind below 3 + and x from 0 by *cell-width* + for aux = (surface :width *cell-width* :heigth *cell-heigth*) do + (set-cell :x x :y y :width *cell-width* :heigth *cell-heigth* :surface surface) + (draw-surface surface :surface aux) + (setf (svref (slot-value (slot-value graphic field) + dir) + ind) + aux)))) + graphic))) + +(defgeneric create-graphics (feeb) &key (free-p t)) + +(defmethod create-graphics ((feeb pathname)) + (let ((surf (load-and-convert-image feeb))) + (make-feeb-grahpics surf) + (free-surface surf))) + +(defmethod create-graphics ((feeb surface) &key free-p) + (with-surface feeb + (make-feeb-graphics)) + (if free-p + (fre-surface feeb))) + + +(defvar *time* 0) + +(defun human-player (&rest args) + (declare (ignore args)) + (sdl:with-events (:wait) + (:key-down-event (:key key) + (case key + (:sdl-key-up + (return-from human-player :move-forward)) + (:sdl-key-left + (return-from human-player :turn-left)) + (:sdl-key-right + (return-from human-player :turn-right)) + (:sdl-key-up + (return-from human-player :turn-around)) + (:sdl-key-space + (return-from human-player :flame)) + (:sdl-key-return + (return-from human-player :wait)))) + (:video-expose-event + (sdl:update-display)))) + + +(defun feebs (&key (delay 5) ; 4 min of game + human-player + files &aux (time 0)) + "The main loop program. Single-step is no longer available. +If human-player is supplied, it is taken as the name of human player, +wich will controll a feeb with the keyboard. The end of the game +only occurs if the player press ESC. +If there is no human, *game-length* is used instead. +A number of auto-feebs feebs are created by the system. +Also, if there are more feebs supplied than places, +the feeb wich is killed gives room to another feeb to be born." + (initialize-feebs) + (setf (sdl:frame-rate) 10) + + (init-maze *layout*) + + (dolist (file files) + (load file)) + (if human-player + (define-feeb + human-player + #'human-player)) + + (sdl:with-init () + (sdl:with-display () + (sdl:with-events () + (:idle () + (sdl:update-display) + (if zerop time + (progn + (setf time delay) + (play-one-turn) + (when (not *continue*) + (return))) + (decf time))) + )) + + (setf *feebs-to-be* nil)) + ;;; Feeb creation. ;; This a little better version of conservative-brain ;; all others (stupid or redundant) brains of original ;; feebs.lisp were eliminated - (defun simple-brain (status proximity vision vision-left vision-right) +(defun simple-brain (status proximity vision vision-left vision-right) (declare (ignore vision-left vision-right)) (let ((stuff (my-square proximity))) (cond ((and (consp stuff) (member :mushroom stuff :test #'eq)) Modified: main.lisp ============================================================================== --- main.lisp (original) +++ main.lisp Thu Dec 20 15:16:44 2007 @@ -23,9 +23,10 @@ ;;; Some functions -(defmacro def-feeb-parm (name value doc) +(defmacro define-parameter (name value doc) `(progn (defvar ,name ,value ,doc) + (export ,name) (pushnew ',name *feeb-parameters*))) (defun list-parameter-settings () @@ -34,207 +35,42 @@ (push (cons parm (symbol-value parm)) settings)) settings)) -(defun chance (ratio) - (< (random (denominator ratio)) (numerator ratio))) - -;;; General game parameters: - -(def-feeb-parm *game-length* 320 - "Number of cycles in the simulation.") - -(def-feeb-parm *number-of-auto-feebs* 0 - "Number of dumb system-provided feebs.") - -(def-feeb-parm *slow-feeb-noop-switch* nil - "If non-null, each feeb has a chance of having its orders aborted in - proportion to the time it takes to produce them. - See *slow-feeb-noop-factor*.") - -(def-feeb-parm *slow-feeb-noop-factor* 1/4 - "If *slow-feeb-noop-switch* is non-null, a feeb's orders will be aborted - with probability equal to the product of this factor times the time - taken by this feeb divided by *reference-time*, if non-nil, or - the total time taken by all feebs this turn otherwise.") - -(def-feeb-parm *reference-time* nil - "Time taken by reference if non-nil. See *slow-feeb-noop-factor*.") - -(def-feeb-parm *sense-location-p* t - "If non-null, x-position and y-position will return nil when - some a behavior function tries to invoke it.") - -;;(def-feeb-parm *sense-facing-p* t -;; "If non-null, facing will return nil when one tries to -;; invoke it.") - -;;; Scoring: - -(def-feeb-parm *points-for-killing* 5 - "Added to one's score for killing an opponent.") - -(def-feeb-parm *points-for-dying* -3 - "Added to one's score for being killed or starving.") - -(def-feeb-parm *points-for-slow-down* -1 - "Points earned when a feeb's move is aborted due to slowness.") - -;;; Cheating - -(def-feeb-parm *exclude-cheater-p* nil - "Tells if a feeb is excluded from the game when a cheating is done.") - -(def-feeb-parm *warn-when-cheating-p* t - "Tells if a continuable error must be signaled when a cheating is done.") ;;; Characteristics of the maze: -(def-feeb-parm *may-get-maze-map-p* t +(define-parameter *may-get-maze-map-p* t "Tells if the function (get-maze-map) returns the map layout of nil during the game.") -(def-feeb-parm *maze-x-size* 32 - "Number of columns in the maze.") - -(def-feeb-parm *maze-y-size* 32 - "Number of rows in the maze.") - -(def-feeb-parm *number-of-mushrooms* 8 - "Average number of mushrooms in the maze at any given time.") - ;;; Energies: -(def-feeb-parm *flame-energy* 10 - "Energy used when a feeb flames.") -(def-feeb-parm *mushroom-energy* 50 - "Energy gained when a mushroom is eaten.") - -(def-feeb-parm *carcass-energy* 30 - "Energy gained by feeding on a carcass.") - -(def-feeb-parm *maximum-energy* 100 - "The most energy a feeb can accumulate.") +;;; Carcasses: -(def-feeb-parm *starting-energy* 50 - "Smallest amount of energy a feeb will start with.") -;;; Carcasses: +;;; Fireballs: -(def-feeb-parm *carcass-guaranteed-lifetime* 5 - "Minimum number of turns a carcass will hang around.") -(def-feeb-parm *carcass-rot-probability* 1/3 - "Chance of a carcass rotting away each turn after its guaranteed lifetime.") +;;; Tests that behavior functions might use -;;; Fireballs: +(declare (inline feeb-image-p fireball-image-p)) -(def-feeb-parm *fireball-dissipation-probability* 1/5 - "Chance that a fireball will dissipate each turn after it is fired.") +(defun feeb-image-p (thing) + (typep thing 'feeb)) -(def-feeb-parm *fireball-reflection-probability* 2/3 - "Chance that a fireball will reflect when it hits a wall.") +(defun fireball-image-p (thing) + (typep thing 'fireball)) -(def-feeb-parm *flame-recovery-probability* 1/3 - "Chance a feeb will regain its ability to flame each turn after flaming once.") -;;; Structures: - -;;; The Feeb structure contains all of the info relevant to a particular feeb. -;;; The info available to the brain function is in the Status sub-structure. - -(defstruct (feeb - (:print-function print-feeb) - (:constructor make-feeb (id brain))) - id - brain - image - status - proximity - time - last-score - last-kills - facing - x-position - y-position - (dead-p nil) - (turns-since-flamed 0) - (vision (make-array (max *maze-x-size* *maze-y-size*))) - (vision-left (make-array (max *maze-x-size* *maze-y-size*))) - (vision-right (make-array (max *maze-x-size* *maze-y-size*)))) - -(defstruct (status - (:conc-name nil) - (:constructor make-status (name graphics))) - (name "" :read-only t) - facing - graphics - x-position - y-position - peeking - line-of-sight - (energy-reserve *starting-energy*) - (score 0) - (kills 0) - (ready-to-fire t) - (aborted nil) - (last-move :dead)) - -(defun print-feeb (structure stream depth) - (declare (ignore depth)) - (format stream "#" - (name (feeb-status structure)))) - - -(defstruct (proximity - (:conc-name nil)) - my-square - rear-square - left-square - right-square) - - -;;; These image structures are used to represent feebs and fireballs in -;;; the sensory displays of other feebs. - -(defstruct (feeb-image - (:print-function print-feeb-image) - (:constructor make-feeb-image (name feeb))) - (name "" :read-only t) - facing - (feeb nil :read-only t) - peeking) - -(defun print-feeb-image (structure stream depth) - (declare (ignore depth)) - (format stream "#" - (feeb-image-name structure) - (feeb-image-facing structure))) - -(defstruct (fireball-image - (:print-function print-fireball-image) - (:constructor make-fireball-image (direction owner x y dx dy))) - direction - owner - x - y - dx - dy - (new t)) - -(defun print-fireball-image (structure stream depth) - (declare (ignore depth)) - (format stream "#" - (fireball-image-direction structure))) - -(defstruct (pos (:constructor make-pos (x y))) - x - y) +;;; The maze ;;; Changing the maze (defun change-layout (layout) + "Changes the layout of the map. See variables +*maze-0* throw *maze-5* for examples (or options) of layouts" (when *feebs-to-be* (warn "There are some feebs that have already been defined. They could have used (get-maze-map). Those are they: @@ -246,22 +82,33 @@ (error "Not all the strings in ~a have the same size." layout))) (setf *layout* layout *maze-y-size* y - *maze-x-size* x))) + *maze-x-size* x)) + (init-maze)) (defun get-maze-map () - (when *may-get-maze-map-p* - (unless (and *maze* *fake-maze*) - (init-maze)) - (let ((new-maze (make-array (list *maze-x-size* *maze-y-size*)))) - (dotimes (x *maze-x-size*) - (dotimes (y *maze-y-size*) - (setf (aref new-maze x y) (aref *fake-maze* x y)))) - new-maze))) + "Gets the current maze in the map. It returns an array +of *maze-x-size* by *maze-y-size*. Each element of the +array is one of these: + :rock - a wall + :mushroom-place - here is a place where mushrooms can grow up + :feeb-entry-place - here is a place where a feeb can reincarnate + nil - nothing special +Just remember that variables can change the behavior of this function, +like *may-get-maze-map-p* which, if nil, makes this function return +an array of nils" + (let ((new-maze (make-array (list *maze-x-size* *maze-y-size*)))) + (dotimes (x *maze-x-size*) + (dotimes (y *maze-y-size*) + (setf (aref new-maze x y) (aref *fake-maze* x y)))) + new-maze))) (defun init-maze () (setf *maze* (make-array (list *maze-x-size* *maze-y-size*)) *fake-maze* (make-array (list *maze-x-size* *maze-y-size*)) - *entry-points* nil) + *entry-points* nil + *mushroom-sites* nil + *number-of-mushroom-sites* 0 + *number-of-entry-points* 0) (do ((rows *layout* (cdr rows)) (i (1- *maze-y-size*) (1- i))) ((null rows)) @@ -271,13 +118,17 @@ (aref *fake-maze* j i) nil) (case (schar str j) (#\X - (setf (aref *maze* j i) :rock - (aref *fake-maze* j i) :rock)) + (setf (aref *fake-maze* j i) (and *may-get-maze-map-p* :rock) + (aref *maze* j i) :rock)) (#\* - (setf (aref *fake-maze* j i) :mushroom-place) + (setf (aref *fake-maze* j i) (and *may-get-maze-map-p* + :mushroom-place)) + (incf *number-of-mushroom-sites*) (push (make-pos j i) *mushroom-sites*)) (#\e - (setf (aref *fake-maze* j i) :feeb-entry-place) + (setf (aref *fake-maze* j i) (and *may-get-maze-map-p* + :feeb-entry-place)) + (incf *number-of-entry-points*) (push (make-pos j i) *entry-points*)) (#\space nil) (t @@ -294,119 +145,90 @@ *static-parameters* (loop for (symbol . value) in (list-parameter-settings) collect value)) - (init-maze) - (setf *number-of-mushroom-sites* (length *mushroom-sites*) - *number-of-entry-points* (length *entry-points*)) (create-feebs)) ; The feebs are defined here -(defun create-mushrooms () - (dotimes (i (- *number-of-mushrooms* (length *mushrooms-alive*) (random 3))) - (do ((site (nth (random *number-of-mushroom-sites*) *mushroom-sites*) - (nth (random *number-of-mushroom-sites*) *mushroom-sites*))) - ((null (aref *maze* (pos-x site) (pos-y site))) - (setf (aref *maze* (pos-x site) (pos-y site)) :mushroom))))) -;;; Setting up the feebs. -(defvar *feebs* nil - "A list of all the feebs in the current game.") +;;; Setting up the feebs. -(defvar *next-feeb-id* 0 - "A counter used to assign a unique numerical code to each feeb.") +(defvar *feebs* nil) ;;; Define-Feeb builds a list of feebs to create. Create-Feebs actually ;;; builds the feebs on this list. (defvar *feebs-to-be* nil) -(defun define-feeb (name brain &optional prepare graphs) - (if (delete-feeb name) +(defun define-feeb (name brain &optional initializer graphs) + "Defines a feeb with name NAME, behavior function BRAIN. +The INITIALIZER key option must be either a function that +will be called in the very start of the game, or nil. +If there is another feeb with the same name, overwrites it +with a case sensitive test" + (when (find name *feebs-to-be* :key #'car + :test #'string= (delete-feeb name)) (warn "Feeb ~s already exists, deleting..." name)) (push (list name brain prepare graphs) *feebs-to-be*)) (defun delete-feeb (name) - (not - (equal *feebs-to-be* - (setf *feebs-to-be* - (remove name *feebs-to-be* :key #'car :test #'string=))))) + "Deletes the feeb which has name NAME, causing it not to +be created when the game begins. Does not work for feebs in +the game" + (setf *feebs-to-be* + (remove name *feebs-to-be* :key #'car :test #'string=))) + +(defun list-of-feebs () + "Returns a copy of the list of feebs that will be created +when the game begins." + (loop for (name . rest) in *feebs-to-be* + collect name)) + +(defun delete-all-feebs () + "Deletes all feebs that are to be defined when the game begins." + (setf *feebs-to-be* nil)) (defun create-feebs () - (flet ((create-feeb (name brain prepare graphs) - (let ((pos (pick-random-entry-point)) - (feeb (make-feeb *next-feeb-id* brain))) - (incf *next-feeb-id*) - (setf (feeb-image feeb) - (make-feeb-image name feeb) - (feeb-status feeb) - (make-status name nil); (sdl:load-and-convert-image graphs)) - (feeb-proximity feeb) - (make-proximity)) - (change-feeb-pos feeb (pos-x pos) (pos-y pos)) - (change-feeb-facing feeb (random 4)) - (push feeb *feebs*) - (place-object (feeb-image feeb) (pos-x pos) (pos-y pos)) - (when prepare - (let (*static-parameters* *fake-maze*) - (funcall prepare)) - (check-cheating name))))) - (setf *feebs* nil - *next-feeb-id* 0) - (dolist (feeb-spec (reverse *feebs-to-be*)) - (apply #'create-feeb feeb-spec)))) - -;;; Start at some randomly chosen entry point. If this one is occupied, -;;; scan successive entry points until a winner is found. Circle back -;;; to start of list if necessary. - -(defun pick-random-entry-point () - (do ((points (nth (random *number-of-entry-points*) *entry-points*) - (nth (random *number-of-entry-points*) *entry-points*))) - (nil) - (when (null (aref *maze* (pos-x points) - (pos-y points))) - (return points)))) - -;;; Movement interface. - -(defun delete-object (thing x y) - (when (eq thing :mushroom) - (decf *mushrooms-alive*)) - (setf (aref *maze* x y) - (delete thing (aref *maze* x y)))) - -(defun place-object (thing x j) - (when (eq thing :mushroom) - (incf *mushrooms-alive*)) - (push thing (aref *maze* x j))) - -;;; Functions to change optional structure in status - -(defun change-feeb-pos (feeb x y) - (setf (feeb-x-position feeb) x - (feeb-y-position feeb) y) - (if *sense-location-p* - (setf (x-position (feeb-status feeb)) x - (y-position (feeb-status feeb)) y))) - -(defun change-feeb-facing (feeb facing) - (setf (feeb-facing feeb) -;; ;; use this code to make *sense-facing-p* available -;; ;; but be carefull - it does not really work -;; (if (or *sense-location-p* *sense-facing-p*) -;; (setf (facing (feeb-status feeb)) -;; facing) -;; facing) - (setf (facing (feeb-status feeb)) - (setf (feeb-image-facing (feeb-image feeb)) - facing)))) - -(defun kill-feeb (feeb) - (setf *dead-feebs* (nconc *dead-feebs* (list feeb)) - (feeb-dead-p feeb) t) - (let* ((status (feeb-status feeb)) - (x (feeb-x-position feeb)) - (y (feeb-y-position feeb))) - (push (list 0 x y) *carcasses*) - (incf (score status) *points-for-dying*) - (delete-object (feeb-image feeb) x y) - (place-object :carcass x y))) + (let ((entries (sort *entry-points* #'(lambda (x y) + (declare (ignore x y)) + (zerop (random 2)))))) + (setf *feebs* nil) + (dolist (feeb-spec *feebs-to-be*) + (let ((pos (pop entries))) + (apply 'create-feeb (car pos) (cdr pos) feeb-spec))))) + + +(defun play-one-turn () + ;; This is defined by rules + (start-turn) + ;; Maybe grow up mushrooms + (let ((m-sites (sort *mushroom-sites* + #'(lambda (x y) + (declare (ignore x y)) + (zerop (random 2)))))) + (dotimes (i *mushrooms-to-grow*) + (let ((site (pop m-sites))) + (create-mushroom (car site) (cdr site))))) + ;; Rot some carcasses: + (loop for carc in *carcasses* + with ncarcasses do + (unless (rot-carcass (second carc) (third carc) (first carc)) + (push carc ncarcasses) + (incf (first carc)) + (reincarnate-feeb (pop *dead-feebs*)))) + ;; Move some fireballs: + (dolist (fireball *fireballs-flying*) + (move-fireball fireball)) + ;; Playing with the feebs: + (dolist (feeb *feebs*) + (unless (feeb-dead-p feeb) + ;; Starve the feeb: + (when (<= (decf (feeb-energy-reserve feeb)) 0) + (kill-feeb feeb :starve)) + ;; Compute vision for the feeb: + (compute-vision feeb) + ;; Collect the feeb's move + (make-move-choice feeb))) + ;; Do all the feebs' moves. + (dolist (feeb *feebs*) + (unless (feeb-dead-p feeb) + (setf (feeb-peeking feeb) nil) + (move-feeb feeb (feeb-last-move feeb))))) Modified: package.lisp ============================================================================== --- package.lisp (original) +++ package.lisp Thu Dec 20 15:16:44 2007 @@ -45,7 +45,7 @@ (defpackage :feebs - (:use :common-lisp) + (:use :common-lisp :lispbuilder-sdl :lispbuilder-sdl-image :cffi) ;; Export everything we want the players to get their hands on. (:export *number-of-feebs* *game-length* *number-of-auto-feebs* @@ -64,8 +64,10 @@ ;; Probabilities *carcass-guaranteed-lifetime* *carcass-rot-probability* + *fireball-guaranteed-lifetime* *fireball-dissipation-probability* *fireball-reflection-probability* + *flame-no-recovery-time* *flame-recovery-probability* ;; Difficulty variables @@ -122,7 +124,7 @@ behind-dx behind-dy ;; Others - wallp + wallp chance ;; Graphics for alpha release simple-play print-map)) @@ -136,6 +138,9 @@ (defconstant south 2) (defconstant west 3) +;;; This is t if someone call (asdf:oos 'asdf:load-op 'feebs-c-interface) + +(defvar *c-interface-available* nil) ;;; Parameters that affect strategy of the game. @@ -190,8 +195,10 @@ "XXXXX XXXXXXXXXXXXX X" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) -(defparameter *maze-x-size* 32) -(defparameter *maze-y-size* 32) +(defparameter *maze-x-size* 32 + "Horizontal size of the maze") +(defparameter *maze-y-size* 32 + "Vertical size of the maze") ;;; Quantities during the game Modified: system.lisp ============================================================================== --- system.lisp (original) +++ system.lisp Thu Dec 20 15:16:44 2007 @@ -21,26 +21,205 @@ (in-package :feebs) -(defun reincarnate-feeb (feeb) - (let ((pos (nth (random (length *entry-points*)) *entry-points*)) + +;;; We start defining the main system rules by defining the classes + +;;; This class is used by the system + +(defclass object () + ((direction :accessor object-direction) + (x-position :accessor object-x-position) + (y-position :accessor object-y-position) + (lifetime :accessor object-lifetime :initform 0))) + +(defclass feeb (object) + (;; These are structures accessible from behavior functions. + ;; These (whose :reader start with feeb-image) + ;; are intended to be accessed by other feebs + (name :accessor feeb-name :reader name :initarg :name + :reader feeb-image-name) + (direction :reader facing :reader feeb-image-facing + :initform (random 4)) + (peeking :accessor feeb-peeking :reader peeking + :reader feeb-image-peeking) + + ;; These are intended to be accessed only by the feeb itself + (x-position :reader x-position :initform 0 :initarg :x-position) + (y-position :reader y-position :initform 0 :initarg :y-position) + (line-of-sight :accessor feeb-line-of-sight :reader line-of-sight + :initform 0) + (energy-reserve :accessor feeb-energy-reserve :reader energy-reserve + :initform *starting-energy*) + (ready-to-fire :accessor feeb-ready-to-fire :reader ready-to-fire + :initform t) + (aborted :accessor feeb-aborted :reader aborted) + (last-move :accessor feeb-last-move :reader last-move + :initform :dead) + + ;; These are available for the system only + (brain :accessor feeb-brain :initarg :brain) + (graphics :accessor feeb-graphics :initarg :graphics) + (time :accessor feeb-time :initform 0) + (last-score :accessor feeb-last-score :initform 0) + (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) + (playing-p :accessor feeb-playing-p) + (turns-since-flamed :accessor feeb-turns-since-flamed :initform 0) + (proximity :accessor feeb-proximity :initform (make-proximity)) + (vision :accessor feeb-vision + :initform (make-array (list (max *maze-y-size* *maze-x-size*)))) + (vision-left :accessor feeb-vision-left + :initform (make-array (list (max *maze-y-size* *maze-x-size*)))) + (vision-right :accessor feeb-vision-right + :initform (make-array (list (max *maze-y-size* *maze-x-size*)))))) + +;;; These make sure that these accessors are just available +;;; for the feeb itself + +(defmethod name :around ((fb feeb)) + (if (feeb-playing-p fb) ;; check if the feeb itself is accessing its name + (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 + +(defun create-mushroom (x y) + (unless (member :mushroom (aref *maze* x y)) + (place-object :mushroom x y) + t)) + +(defun rot-carcass (x y) + (delete-object :carcass x y) + t) + +(defun delete-object (thing x y) + (when (eq thing :mushroom) + (decf *mushrooms-alive*)) + (setf (aref *maze* x y) + (delete thing (aref *maze* x y)))) + +(defun place-object (thing x j) + (when (eq thing :mushroom) + (incf *mushrooms-alive*)) + (push thing (aref *maze* x j))) + +(defun change-object-pos (obj x y) + (delete-object obj (object-x-position obj) + (object-y-position obj)) + (place-object obj x y) + (setf (object-x-position obj) x + (object-y-position obj) y)) + +(defun get-forward-pos (object) + (let ((new-x (+ (forward-dx (object-direction object)) + (object-x-position object))) + (new-y (+ (forward-dy (object-direction object)) + (object-y-position object)))) + (values (aref *maze* new-x new-y) new-x new-y))) + + +;;; --**-- System Rules --**-- + +;;; -*- General Rules -*- + +(defmethod start-round () + t) + +(defmethod start-turn () + t) + +(defmethod create-feeb (x-pos y-pos name brain prepare graphs) + (let ((feeb (make-instance 'feeb + :name name + :brain brain + :graphics (if graphs + (sdl:load-and-convert-image graphs)) + :x-position x-pos + :y-position y-pos))) + (push feeb *feebs*) + (place-object (feeb-image feeb) x-pos y-pos) + (when prepare + (funcall prepare)))) + + + +;;; -*- Dying and Killing -*- + +;;; Reincarnating + +(defmethod reincarnate-feeb ((feeb feeb)) + (let ((pos (nth (random *number-of-entry-points*) *entry-points*)) (status (feeb-status feeb))) - (place-object (feeb-image feeb) - (pos-x pos) (pos-y pos)) - (change-feeb-pos feeb (pos-x pos) (pos-y pos)) - (change-feeb-facing feeb (random 4)) - (setf (feeb-dead-p feeb) nil + (change-object-pos feeb (pos-x pos) (pos-y pos)) + (setf (feeb-facing feeb) (random 4) + (feeb-dead-p feeb) nil (ready-to-fire status) t (energy-reserve status) *starting-energy* (last-move status) :dead))) +;;; Dying + +(defmethod destroy-object ((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)) + (y (feeb-y-position feeb))) + (push (list 0 x y) *carcasses*) + (delete-object (feeb-image feeb) x y) + (place-object :carcass x y))) -;;; Vision calculation. -;;; These guys tell us offsets given an orientation. + +;;; -*- Vision Calculation -*- + +;;; Computes what the feeb is seeing (defun compute-vision (feeb) - (let ((status (feeb-status feeb)) - (proximity (feeb-proximity feeb)) + (let ((proximity (feeb-proximity feeb)) (vision (feeb-vision feeb)) (vision-left (feeb-vision-left feeb)) (vision-right (feeb-vision-right feeb)) @@ -62,7 +241,7 @@ (setf x (+ x (forward-dx facing)) y (+ y (forward-dy facing))) ;; Figure out which direction to scan in. - (case (peeking status) + (case (feeb-peeking feeb) (:left (setf facing (left-of facing))) (:right (setf facing (right-of facing)))) (setf vision-dx (forward-dx facing) @@ -92,213 +271,119 @@ ;;; A peeking feeb must be facing in the specified direction in order to count. (defun side-imagify (stuff facing) - (cond - ((wallp stuff) - stuff) - ((find-if #'(lambda (thing) - (and (feeb-image-p thing) - (peeking (feeb-status (feeb-image-feeb thing))) - (= facing (feeb-image-facing thing)) - (setf facing thing))) - stuff) - (peeking (feeb-status (feeb-image-feeb facing)))) - (t nil))) - -;;; Movement. - -;;; Each turn, the following stuff has to happen: -;;; 1. Bump the turn counter; end the game if we should. -;;; 2. Maybe grow some mushrooms. -;;; 3. Maybe disappear some carcasses. -;;; 4. Move fireballs around. -;;; 5. See if any feebs have starved. -;;; 6. See if any feebs can flame again. -;;; 7. Compute vision and stuff for feebs. -;;; 8. Collect the feebs' moves. -;;; 9. Do the feeb's moves. - -(defun play-one-turn () - ;; Grow some mushrooms: - (dotimes (x (- *number-of-mushrooms* *mushrooms-alive*)) - (let* ((site (nth (random *number-of-mushroom-sites*) *mushroom-sites*)) - (x (pos-x site)) - (y (pos-y site))) - (unless (member :mushroom (aref *maze* x y)) - (place-object :mushroom x y)))) - ;; Rot some carcasses: - (dolist (carc *carcasses*) - (when (and - (> (incf (first carc) *carcass-guaranteed-lifetime*)) - (chance *carcass-rot-probability*)) - (delete-object :carcass (second carc) (third carc)) - (setf *carcasses* (delete carc *carcasses*)) - (if *dead-feebs* - (reincarnate-feeb (pop *dead-feebs*))))) - ;; Move some fireballs: - (dolist (fireball *fireballs-flying*) - (move-one-fireball fireball)) - ;; Starve some feebs: - (dolist (feeb *feebs*) - (unless (feeb-dead-p feeb) - (when (<= (decf (energy-reserve (feeb-status feeb))) 0) - (kill-feeb feeb)))) - ;; Let some feebs regain the power to flame: - (dolist (feeb *feebs*) - (unless (and (feeb-dead-p feeb) - (ready-to-fire (feeb-status feeb))) - (when (and (> (incf (feeb-turns-since-flamed feeb)) - 1) - (chance *flame-recovery-probability*)) - (setf (ready-to-fire (feeb-status feeb)) t)))) - ;; Collect all the feebs' moves, keeping track of the time each one takes. - (let ((total-time 1)) - (dolist (feeb *feebs*) - (unless (feeb-dead-p feeb) - (compute-vision feeb) ; Compute vision for all the feeb. - (let ((time (get-internal-real-time))) - (let ( *static-parameters* *fake-maze*) - (setf (last-move (feeb-status feeb)) - (funcall (feeb-brain feeb) - (feeb-status feeb) - (feeb-proximity feeb) - (feeb-vision feeb) - (feeb-vision-left feeb) - (feeb-vision-right feeb)) - time (- (get-internal-real-time) time))) - (incf total-time time) - (setf (feeb-time feeb) time)))) - ;; Do all the feebs' moves, or perhaps abort the move according - ;; to the time taken by the feeb. - (setf total-time (float total-time)) - (dolist (feeb *feebs*) - (unless (feeb-dead-p feeb) - (if (and *slow-feeb-noop-switch* - (< (random 1.0) - (* *slow-feeb-noop-factor* - (/ (float (feeb-time feeb)) - (or *reference-time* total-time))))) - (progn - (setf (aborted (feeb-status feeb)) t) - (incf (score (feeb-status feeb)) *points-for-slow-down*)) - (progn - (setf (aborted (feeb-status feeb)) nil) - (do-move feeb (last-move (feeb-status feeb))))) - ;; Make the image consistent with the feeb. - (setf (feeb-image-facing (feeb-image feeb)) - (feeb-facing feeb)))))) - -(defun move-one-fireball (fireball) - (let ((x (fireball-image-x fireball)) - (y (fireball-image-y fireball))) - ;; Remove fireball from current square, unless it is new. - (if (fireball-image-new fireball) - (setf (fireball-image-new fireball) nil) - (delete-object fireball x y)) - ;; The fireball might dissipate. - (when (chance *fireball-dissipation-probability*) - (setq *fireballs-flying* (delete fireball *fireballs-flying*)) - (return-from move-one-fireball nil)) - ;; Now move it to new coordinates. - (incf x (fireball-image-dx fireball)) - (incf y (fireball-image-dy fireball)) + (if (wallp stuff) + stuff + (loop for thing in stuff + and elt = (and (feeb-image-p thing) + (= facing (feeb-image-facing thing)) + (feeb-image-peeking thing)) + if elt + return it))) + +(defparameter *mushrooms-to-grow* 0) + +(defun number-of-mushrooms (n) + (setf *mushrooms-to-grow* n)) + + +;;; Lets the feeb make a choice + +(defmethod make-move-choice ((feeb feeb)) + (setf (last-move (feeb-status feeb)) + (funcall (feeb-brain feeb) + (feeb-status feeb) + (feeb-proximity feeb) + (feeb-vision feeb) + (feeb-vision-left feeb) + (feeb-vision-right feeb)))) + + + +;;; Moves the fireball + +(defmethod make-move ((fireball fireball)) + ;; move it to new coordinates. + (let ((x (incf (fireball-x fireball) + (forward-dx (fireball-direction fireball)))) + (y (incf (fireball-y fireball) + (forward-dy (fireball-direction fireball))))) ;; If it hits rock, either reflect or dissipate. (when (wallp (aref *maze* x y)) - (cond ((chance *fireball-reflection-probability*) - (setf (fireball-image-dx fireball) - (- (fireball-image-dx fireball))) - (setf (fireball-image-dy fireball) - (- (fireball-image-dy fireball))) - (setf (fireball-image-direction fireball) - (behind (fireball-image-direction fireball))) - (setq x (fireball-image-x fireball)) - (setq y (fireball-image-y fireball))) - (t (setq *fireballs-flying* - (delete fireball *fireballs-flying*)) - (return-from move-one-fireball nil)))) + (if (and (> (incf (fireball-age fireball)) + *fireball-guaranteed-lifetime*) + (chance *fireball-reflection-probability*)) + (setf (fireball-direction fireball) + (behind (fireball-direction fireball)) + x (fireball-x fireball) + y (fireball-y fireball)) + (progn + (setf *fireballs-flying* + (delete fireball *fireballs-flying*)) + (return-from move-one-fireball)))) ;; Now put the fireball into the new square. - (setf (fireball-image-x fireball) x) - (setf (fireball-image-y fireball) y) - (place-object fireball x y) - ;; And destroy whatever is there. - (delete-object :mushroom x y) - (dolist (thing (aref *maze* x y)) - (if (feeb-image-p thing) - (score-kill fireball (feeb-image-feeb thing)))))) - -;;; The fireball kills the feeb. Update score for killer and victims. -;;; No credit for the kill if you shoot yourself. - -(defun score-kill (fireball feeb) - (unless (eq (fireball-image-owner fireball) feeb) - (incf (score (feeb-status (fireball-image-owner fireball))) - *points-for-killing*) - (incf (kills (feeb-status (fireball-image-owner fireball))))) - (kill-feeb feeb)) + (setf (fireball-x fireball) x + (fireball-y fireball) y) + (change-object-pos fireball x y))) ;;; Doing feeb moves. -(defun do-move (feeb move) - (let ((status (feeb-status feeb)) - (facing (feeb-facing feeb))) - ;; Peeking gets undone every move. +(defmethod make-move ((feeb feeb) (move (eql :turn-right))) + (setf (feeb-facing feeb) (right-of facing)) (call-next-method)) + +(defmethod make-move ((feeb feeb) (move (eql :turn-around))) + (setf (feeb-facing feeb) (behind facing)) (call-next-method)) + +(defmethod make-move (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) + (let ((thing (find-if #'fireball-image-p stuff))) + (when thing (kill-feeb feeb thing) + (return-from make-move t)))) + (call-next-method)) + +(defmethod make-move ((feeb feeb) (move (eql :flame))) + (let ((x (feeb-x-position feeb)) + (y (feeb-y-position feeb)) + (fireball + (make-fireball-image (feeb-facing feeb) + feeb x y (forward-dx facing) + (forward-dy facing)))) + (push fireball *fireballs-flying*)) + (call-next-method)) + +(defmethod make-move ((feeb feeb) (move (eql :eat-mushroom))) + (let ((x (feeb-x-position feeb)) + (y (feeb-y-position feeb))) + (when (member :mushroom (aref *maze* x y)) + (delete-object :mushroom x y) + t))) + +(defmethod make-move ((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))) + +(defmethod make-move ((feeb feeb) (move (eql :peek-left))) + (unless + (wallp + (aref *maze* (+ (feeb-x-position feeb) + (forward-dx (feeb-facing feeb))) + (+ (feeb-y-position feeb) + (forward-dy (feeb-facing feeb))))) + (setf (peeking status) + (setf (feeb-image-peeking (feeb-image feeb)) move))) + (call-next-method)) + +(defmethod make-move ((feeb feeb) (move (eql :peek-right))) + (unless + (wallp + (aref *maze* (+ (feeb-x-position feeb) + (forward-dx (feeb-facing feeb))) + (+ (feeb-y-position feeb) + (forward-dy (feeb-facing feeb))))) (setf (peeking status) - (setf (feeb-image-peeking (feeb-image feeb)) nil)) - (case move - (:turn-left - (change-feeb-facing feeb (left-of facing))) - (:turn-right - (change-feeb-facing feeb (right-of facing))) - (:turn-around - (change-feeb-facing feeb (behind facing))) - (:move-forward - (let* ((old-x (feeb-x-position feeb)) - (old-y (feeb-y-position feeb)) - (new-x (+ (forward-dx facing) old-x)) - (new-y (+ (forward-dy facing) old-y)) - (stuff (aref *maze* new-x new-y))) - (when (wallp stuff) - (return-from do-move nil)) - (delete-object (feeb-image feeb) old-x old-y) - (change-feeb-pos feeb new-x new-y) - (place-object (feeb-image feeb) new-x new-y) - ;; Look for a fireball in the destination square. - (let ((thing (find-if #'fireball-image-p stuff))) - (when thing - (score-kill thing feeb) - (return-from do-move nil))))) - (:flame - (when (ready-to-fire status) - (let* ((x (feeb-x-position feeb)) - (y (feeb-y-position feeb)) - (fireball (make-fireball-image - facing feeb x y - (forward-dx facing) (forward-dy facing)))) - ;; Queue the fireball, marked as new, but don't put it on map yet. - (push fireball *fireballs-flying*) - (decf (energy-reserve status) *flame-energy*) - (setf (ready-to-fire status) nil) - (setf (feeb-turns-since-flamed feeb) 0)))) - (:eat-mushroom - (let* ((x (feeb-x-position feeb)) - (y (feeb-y-position feeb))) - (when (member :mushroom (aref *maze* x y)) - (delete-object :mushroom x y) - (setf (energy-reserve status) - (min (+ (energy-reserve status) *mushroom-energy*) - *maximum-energy*))))) - (:eat-carcass - (let* ((x (feeb-x-position feeb)) - (y (feeb-y-position feeb))) - (when (member :carcass (aref *maze* x y)) - (setf (energy-reserve status) - (min (+ (energy-reserve status) *carcass-energy*) - *maximum-energy*))))) - ((:peek-left :peek-right) - (unless (wallp (aref *maze* (+ (feeb-x-position feeb) - (forward-dx facing)) - (+ (feeb-y-position feeb) - (forward-dy facing)))) - (setf (peeking status) - (setf (feeb-image-peeking (feeb-image feeb)) move)))) - (:wait nil) - (t (warn "Unknown feeb movement: ~a." move))))) + (setf (feeb-image-peeking (feeb-image feeb)) move))) + (call-next-method)) From gmilare at common-lisp.net Thu Dec 20 20:17:10 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Thu, 20 Dec 2007 15:17:10 -0500 (EST) Subject: [the-feebs-war-cvs] r6 - Message-ID: <20071220201710.CBE533D0B8@common-lisp.net> Author: gmilare Date: Thu Dec 20 15:17:10 2007 New Revision: 6 Added: feebs.asd Log: Added: feebs.asd ============================================================================== --- (empty file) +++ feebs.asd Thu Dec 20 15:17:10 2007 @@ -0,0 +1,32 @@ +;;; -*- Common Lisp -*- + +(defpackage :feebs-system + (:use :cl :asdf)) + +(in-package :feebs-system) + +(defsystem feebs + :description "The Feebs War is an extension of Planetof the Feebs" + :version "1.0" + :author "Gustavo Henrique Milar? " + :licence "GPL" + :depends-on (lispbuilder-sdl lispbuilder-sdl-image) + + :components + (;; source + (:cl-source-file "package") + (:cl-source-file "rules" :depends-on ("package")) + (:cl-source-file "system" :depends-on ("rules")) + (:cl-source-file "main" :depends-on ("rules")) + (:cl-source-file "extra" :depends-on ("rules")) + + (:cl-source-file "mazes" :depends-on ("extra")) + (:cl-source-file "brains" :depends-on ("extra")) + + (:file "graphics" :depends-on ("main")) + + ;; GPL + (:doc-file "licence") + + ;; documentation + (:doc-file "feebs.tex"))) From gmilare at common-lisp.net Sun Dec 30 01:30:34 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Sat, 29 Dec 2007 20:30:34 -0500 (EST) Subject: [the-feebs-war-cvs] r7 - Message-ID: <20071230013034.A67417E0A8@common-lisp.net> Author: gmilare Date: Sat Dec 29 20:30:32 2007 New Revision: 7 Modified: brains.lisp extra.lisp feebs.asd feebs.tex graphics.lisp main.lisp mazes.lisp package.lisp system.lisp Log: Modified: brains.lisp ============================================================================== --- brains.lisp (original) +++ brains.lisp Sat Dec 29 20:30:32 2007 @@ -1,5 +1,24 @@ ;;; -*- Common Lisp -*- +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 The Feebs War. If not, see . +|# + + (in-package :feebs) @@ -43,4 +62,4 @@ (dotimes (i n) (define-feeb (format nil "System Feeb # ~d" i) - #'auto-brain))) \ No newline at end of file + #'auto-brain))) Modified: extra.lisp ============================================================================== --- extra.lisp (original) +++ extra.lisp Sat Dec 29 20:30:32 2007 @@ -15,7 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with The Feebs War. If not, see . |# @@ -118,7 +118,7 @@ ((= ,count line-of-sight) , at finalize) (declare (list ,v ,vl ,vr) - (fixnum ,count)) ; can be assumed fixnum unless you have a mega PC + (fixnum ,count)) (dolist (,vis ,v) , at vis-body) (dolist (,vis-l ,vl) Modified: feebs.asd ============================================================================== --- feebs.asd (original) +++ feebs.asd Sat Dec 29 20:30:32 2007 @@ -5,12 +5,12 @@ (in-package :feebs-system) -(defsystem feebs - :description "The Feebs War is an extension of Planetof the Feebs" +(defsystem the-feebs-war + :description "The Feebs War is a continuation of Planet of the Feebs." :version "1.0" :author "Gustavo Henrique Milar? " :licence "GPL" - :depends-on (lispbuilder-sdl lispbuilder-sdl-image) +; :depends-on (pal) :components (;; source Modified: feebs.tex ============================================================================== --- feebs.tex (original) +++ feebs.tex Sat Dec 29 20:30:32 2007 @@ -29,7 +29,7 @@ % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License -% along with this program. If not, see . +% along with The Feebs War. If not, see . Modified: graphics.lisp ============================================================================== --- graphics.lisp (original) +++ graphics.lisp Sat Dec 29 20:30:32 2007 @@ -15,7 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with The Feebs War. If not, see . |# (in-package :feebs) @@ -37,10 +37,9 @@ (list " XX")) ((feeb-image-p (car elt)) (list "F~1d~a" - (feeb-id (feeb-image-feeb (car elt))) - (print-direction (feeb-image-facing (car elt))))) + (print-direction (feeb-facing (car elt))))) ((fireball-image-p (car elt)) - (list " *~a" (print-direction (fireball-image-direction (car elt))))) + (list " *~a" (print-direction (fireball-direction (car elt))))) ((eq (car elt) :mushroom) (list " mm")) ((eq (car elt) :carcass) @@ -57,7 +56,7 @@ (play-one-turn) (print-map) (sleep 0.7) (format t "~%~%")) (format t "Fim de jogo!!~%~%Pontua??es:~%~%") (dolist (feeb *feebs*) - (format t "~a: ~d~%" (name (feeb-status feeb)) (score (feeb-status feeb))))) + (format t "~a: ~d~%" (feeb-name feeb) (feeb-score feeb)))) #| Modified: main.lisp ============================================================================== --- main.lisp (original) +++ main.lisp Sat Dec 29 20:30:32 2007 @@ -15,7 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with The Feebs War. If not, see . |# @@ -23,9 +23,10 @@ ;;; Some functions -(defmacro define-parameter (name value doc) +(defmacro define-parameter (name &optional value doc) `(progn - (defvar ,name ,value ,doc) + (defvar ,name ,value + ,@(if doc '(doc))) (export ,name) (pushnew ',name *feeb-parameters*))) @@ -43,15 +44,6 @@ during the game.") -;;; Energies: - - -;;; Carcasses: - - -;;; Fireballs: - - ;;; Tests that behavior functions might use @@ -110,7 +102,7 @@ *number-of-mushroom-sites* 0 *number-of-entry-points* 0) (do ((rows *layout* (cdr rows)) - (i (1- *maze-y-size*) (1- i))) + (i (1- *maze-y-size*) (1- i))) ; inverting the y axis ((null rows)) (let ((str (car rows))) (dotimes (j (length str)) @@ -118,16 +110,18 @@ (aref *fake-maze* j i) nil) (case (schar str j) (#\X - (setf (aref *fake-maze* j i) (and *may-get-maze-map-p* :rock) + (setf (aref *fake-maze* j i) + (and *may-get-maze-map-p* :rock) (aref *maze* j i) :rock)) (#\* - (setf (aref *fake-maze* j i) (and *may-get-maze-map-p* - :mushroom-place)) + (setf (aref *fake-maze* j i) + (and *may-get-maze-map-p* :mushroom-place)) (incf *number-of-mushroom-sites*) (push (make-pos j i) *mushroom-sites*)) (#\e - (setf (aref *fake-maze* j i) (and *may-get-maze-map-p* - :feeb-entry-place)) + (setf (aref *fake-maze* j i) + (and *may-get-maze-map-p* + :feeb-entry-place)) (incf *number-of-entry-points*) (push (make-pos j i) *entry-points*)) (#\space nil) @@ -158,21 +152,19 @@ (defvar *feebs-to-be* nil) -(defun define-feeb (name brain &optional initializer graphs) +(defun define-feeb (name brain &optional graphics) "Defines a feeb with name NAME, behavior function BRAIN. -The INITIALIZER key option must be either a function that -will be called in the very start of the game, or nil. If there is another feeb with the same name, overwrites it -with a case sensitive test" +with a case sensitive test." (when (find name *feebs-to-be* :key #'car :test #'string= (delete-feeb name)) (warn "Feeb ~s already exists, deleting..." name)) - (push (list name brain prepare graphs) *feebs-to-be*)) + (push (list name brain graphs) *feebs-to-be*)) (defun delete-feeb (name) "Deletes the feeb which has name NAME, causing it not to -be created when the game begins. Does not work for feebs in -the game" +be created when the game begins. Does not work for feebs +already in the game." (setf *feebs-to-be* (remove name *feebs-to-be* :key #'car :test #'string=))) @@ -187,48 +179,68 @@ (setf *feebs-to-be* nil)) (defun create-feebs () - (let ((entries (sort *entry-points* #'(lambda (x y) - (declare (ignore x y)) - (zerop (random 2)))))) + (flet ((create-feeb (x-pos y-pos name brain graphs) + (let ((feeb (make-instance 'feeb + :name name + :brain brain + :direction (random 4) + :graphics graphs + :x-position x-pos + :y-position y-pos))) + (push feeb *feebs*) + (if (and x-pos y-pos) + (create-object feeb x-pos y-pos) + (push feeb *dead-feebs*))))) + (let ((entries (sort *entry-points* ; random positions + #'(lambda (x y) + (declare (ignore x y)) + (zerop (random 2)))))) (setf *feebs* nil) (dolist (feeb-spec *feebs-to-be*) - (let ((pos (pop entries))) - (apply 'create-feeb (car pos) (cdr pos) feeb-spec))))) + (let ((pos (pop entries)))) + (apply 'create-feeb (car pos) (cdr pos) feeb-spec)))) + + + +;;; The Game + +(let ((mushrooms 0)) +(defun number-of-mushrooms (n) + (setf *mushrooms-to-grow* n)) (defun play-one-turn () - ;; This is defined by rules + (setf mushrooms 0) ; restart the count + ;; This is defined by rules: (start-turn) - ;; Maybe grow up mushrooms + ;; Maybe grow up mushrooms: (let ((m-sites (sort *mushroom-sites* #'(lambda (x y) (declare (ignore x y)) (zerop (random 2)))))) - (dotimes (i *mushrooms-to-grow*) + (dotimes (i mushrooms) (let ((site (pop m-sites))) (create-mushroom (car site) (cdr site))))) - ;; Rot some carcasses: + ;; Maybe rot some carcasses + ;; FIXME: put this in rules.lisp with better code (loop for carc in *carcasses* with ncarcasses do - (unless (rot-carcass (second carc) (third carc) (first carc)) - (push carc ncarcasses) - (incf (first carc)) - (reincarnate-feeb (pop *dead-feebs*)))) + (if (rot-carcass-p (first carc)) + (delete-object :carcass (second carc) (third carc))) + (progn + (push carc ncarcasses) + (incf (first carc))))) ;; Move some fireballs: (dolist (fireball *fireballs-flying*) - (move-fireball fireball)) - ;; Playing with the feebs: - (dolist (feeb *feebs*) - (unless (feeb-dead-p feeb) - ;; Starve the feeb: - (when (<= (decf (feeb-energy-reserve feeb)) 0) - (kill-feeb feeb :starve)) - ;; Compute vision for the feeb: - (compute-vision feeb) - ;; Collect the feeb's move - (make-move-choice feeb))) - ;; Do all the feebs' moves. - (dolist (feeb *feebs*) - (unless (feeb-dead-p feeb) - (setf (feeb-peeking feeb) nil) - (move-feeb feeb (feeb-last-move feeb))))) + (move-object fireball (make-move-choice fireball))) + (progn + ;; Starve the feeb: + (when (<= (decf (feeb-energy-reserve feeb)) 0) + (destroy-object feeb :starve)) + ;; Compute vision for the feeb: + (compute-vision feeb) + ;; Collect the feeb's move + (setf (feeb-peeking feeb) nil) + (move-object feeb (setf (feeb-last-move feeb) + (make-move-choice feeb))))))) +) \ No newline at end of file Modified: mazes.lisp ============================================================================== --- mazes.lisp (original) +++ mazes.lisp Sat Dec 29 20:30:32 2007 @@ -1,17 +1,35 @@ ;;; -*- Common Lisp -*- -;;; Mazes for Planet of the Feebs. -;;; A somewhat educational simulation game. -;;; +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 The Feebs War. If not, see . +|# + ;;; Created by Jim Healy, July 1987. ;;; ;;; ************************************************** -;;; Maze guidelines: -;;; Maze should be *maze-i-size* by *maze-j-size* -;;; (currently 32 x 32). +;;; Maze guidelines: ;;; X represents a wall. ;;; * represents a mushroom patch. ;;; e is a feeb entry point. +;;; +;;; The maze should be a rectangle bounded by walls +;;; in each side. +;;; These mazes are all 32x32, but you may build +;;; a maze of any size you wish. ;;; ************************************************** ;;; Maze1 has a good number of dead ends and little nooks. @@ -236,3 +254,9 @@ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) |# + +;;; Or this function: + +(defun make-template (x-size y-size) + (loop repeat y-size collect + (make-string x-size :initial-element #\#))) Modified: package.lisp ============================================================================== --- package.lisp (original) +++ package.lisp Sat Dec 29 20:30:32 2007 @@ -15,20 +15,9 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with The Feebs War. If not, see . |# - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;;; ;;; -;;; The Feebs War ;;; -;;; ;;; -;;; Written by Gustavo Henrique Milar?? ;;; -;;; ;;; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -;;; The GPL should in the file "license", provided with the software. - ;;; based on Planet of the Feebs ;;; About Planet of the Feebs: @@ -39,13 +28,10 @@ ;; Modified by Jim Healy. ;; ;; Graphics ported to X11 by Fred Gilham 8-FEB-1998. -;; -;; -;;; This project exists thanks to them (defpackage :feebs - (:use :common-lisp :lispbuilder-sdl :lispbuilder-sdl-image :cffi) + (:use :common-lisp) ;; Export everything we want the players to get their hands on. (:export *number-of-feebs* *game-length* *number-of-auto-feebs* @@ -138,9 +124,6 @@ (defconstant south 2) (defconstant west 3) -;;; This is t if someone call (asdf:oos 'asdf:load-op 'feebs-c-interface) - -(defvar *c-interface-available* nil) ;;; Parameters that affect strategy of the game. Modified: system.lisp ============================================================================== --- system.lisp (original) +++ system.lisp Sat Dec 29 20:30:32 2007 @@ -15,7 +15,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with The Feebs War. If not, see . |# @@ -29,8 +29,7 @@ (defclass object () ((direction :accessor object-direction) (x-position :accessor object-x-position) - (y-position :accessor object-y-position) - (lifetime :accessor object-lifetime :initform 0))) + (y-position :accessor object-y-position))) (defclass feeb (object) (;; These are structures accessible from behavior functions. @@ -79,7 +78,7 @@ ;;; for the feeb itself (defmethod name :around ((fb feeb)) - (if (feeb-playing-p fb) ;; check if the feeb itself is accessing its name + (if (feeb-playing-p fb) (call-next-method))) (defmethod facing :around ((fb feeb)) @@ -131,10 +130,6 @@ (place-object :mushroom x y) t)) -(defun rot-carcass (x y) - (delete-object :carcass x y) - t) - (defun delete-object (thing x y) (when (eq thing :mushroom) (decf *mushrooms-alive*)) @@ -159,7 +154,8 @@ (new-y (+ (forward-dy (object-direction object)) (object-y-position object)))) (values (aref *maze* new-x new-y) new-x new-y))) - + + ;;; --**-- System Rules --**-- @@ -171,34 +167,25 @@ (defmethod start-turn () t) -(defmethod create-feeb (x-pos y-pos name brain prepare graphs) - (let ((feeb (make-instance 'feeb - :name name - :brain brain - :graphics (if graphs - (sdl:load-and-convert-image graphs)) - :x-position x-pos - :y-position y-pos))) - (push feeb *feebs*) - (place-object (feeb-image feeb) x-pos y-pos) - (when prepare - (funcall prepare)))) +;;; -*- Being Born and Dying -*- + +;;; Creating -;;; -*- Dying and Killing -*- +(defmethod create-object (object x-pos y-pos) + (change-object-pos object x-pos y-pos)) ;;; Reincarnating (defmethod reincarnate-feeb ((feeb feeb)) - (let ((pos (nth (random *number-of-entry-points*) *entry-points*)) - (status (feeb-status feeb))) - (change-object-pos feeb (pos-x pos) (pos-y pos)) - (setf (feeb-facing feeb) (random 4) - (feeb-dead-p feeb) nil - (ready-to-fire status) t - (energy-reserve status) *starting-energy* - (last-move status) :dead))) + (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)) ;;; Dying @@ -210,7 +197,8 @@ (y (feeb-y-position feeb))) (push (list 0 x y) *carcasses*) (delete-object (feeb-image feeb) x y) - (place-object :carcass x y))) + (place-object :carcass x y)) + (call-next-method)) @@ -262,7 +250,7 @@ (setf (aref vision index) (aref *maze* x y) (aref vision-left index) (side-imagify (aref *maze* left-wall-x left-wall-y) - (right-of facing)) + (right-of facing)) (aref vision-right index) (side-imagify (aref *maze* right-wall-x right-wall-y) (left-of facing)))))) @@ -280,67 +268,55 @@ if elt return it))) -(defparameter *mushrooms-to-grow* 0) -(defun number-of-mushrooms (n) - (setf *mushrooms-to-grow* n)) +;;; -*- Movement -*- ;;; Lets the feeb make a choice (defmethod make-move-choice ((feeb feeb)) - (setf (last-move (feeb-status feeb)) - (funcall (feeb-brain feeb) - (feeb-status feeb) - (feeb-proximity feeb) - (feeb-vision feeb) - (feeb-vision-left feeb) - (feeb-vision-right feeb)))) - - - -;;; Moves the fireball - -(defmethod make-move ((fireball fireball)) - ;; move it to new coordinates. - (let ((x (incf (fireball-x fireball) - (forward-dx (fireball-direction fireball)))) - (y (incf (fireball-y fireball) - (forward-dy (fireball-direction fireball))))) - ;; If it hits rock, either reflect or dissipate. - (when (wallp (aref *maze* x y)) - (if (and (> (incf (fireball-age fireball)) - *fireball-guaranteed-lifetime*) - (chance *fireball-reflection-probability*)) - (setf (fireball-direction fireball) - (behind (fireball-direction fireball)) - x (fireball-x fireball) - y (fireball-y fireball)) - (progn - (setf *fireballs-flying* - (delete fireball *fireballs-flying*)) - (return-from move-one-fireball)))) - ;; Now put the fireball into the new square. - (setf (fireball-x fireball) x - (fireball-y fireball) y) - (change-object-pos fireball x y))) - -;;; Doing feeb moves. - -(defmethod make-move ((feeb feeb) (move (eql :turn-right))) - (setf (feeb-facing feeb) (right-of facing)) (call-next-method)) + (funcall (feeb-brain feeb) + (feeb-status feeb) + (feeb-proximity feeb) + (feeb-vision feeb) + (feeb-vision-left feeb) + (feeb-vision-right feeb))) + +;;; Moving + +(defmethod make-move (object (move (eql :turn-right))) + (setf (object-direction object) + (right-of (object-direction object))) + t) -(defmethod make-move ((feeb feeb) (move (eql :turn-around))) - (setf (feeb-facing feeb) (behind facing)) (call-next-method)) +(defmethod make-move (object (move (eql :turn-around))) + (setf (object-direction object) + (behind (object-direction object))) + t) (defmethod make-move (object (move (eql :move-forward))) - (multiple-value-bind (stuff new-x new-y) (get-forward-pos object) + (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) - (let ((thing (find-if #'fireball-image-p stuff))) - (when thing (kill-feeb feeb thing) - (return-from make-move t)))) + (change-object-pos object new-x new-y)) + t) + +;;; Fireball + +(defmethod make-move ((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 + +(defmethod make-move ((feeb feeb) (move (eql :move-forward))) + (let ((thing (find-if #'fireball-image-p stuff))) + (when thing (destroy-object feeb thing) + (return-from make-move t))) (call-next-method)) (defmethod make-move ((feeb feeb) (move (eql :flame))) @@ -350,8 +326,8 @@ (make-fireball-image (feeb-facing feeb) feeb x y (forward-dx facing) (forward-dy facing)))) - (push fireball *fireballs-flying*)) - (call-next-method)) + (push fireball *fireballs-flying*) + t)) (defmethod make-move ((feeb feeb) (move (eql :eat-mushroom))) (let ((x (feeb-x-position feeb)) @@ -367,23 +343,15 @@ t))) (defmethod make-move ((feeb feeb) (move (eql :peek-left))) - (unless - (wallp - (aref *maze* (+ (feeb-x-position feeb) - (forward-dx (feeb-facing feeb))) - (+ (feeb-y-position feeb) - (forward-dy (feeb-facing feeb))))) - (setf (peeking status) - (setf (feeb-image-peeking (feeb-image feeb)) move))) - (call-next-method)) + (multiple-value-bind (x y stuff) + (get-forward-pos feeb) + (unless (wallp stuff) + (setf (peeking feeb) move))) + t) (defmethod make-move ((feeb feeb) (move (eql :peek-right))) - (unless - (wallp - (aref *maze* (+ (feeb-x-position feeb) - (forward-dx (feeb-facing feeb))) - (+ (feeb-y-position feeb) - (forward-dy (feeb-facing feeb))))) - (setf (peeking status) - (setf (feeb-image-peeking (feeb-image feeb)) move))) - (call-next-method)) + (multiple-value-bind (x y stuff) + (get-forward-pos feeb) + (unless (wallp stuff) + (setf (peeking feeb) move))) + t) From gmilare at common-lisp.net Sun Dec 30 01:34:57 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Sat, 29 Dec 2007 20:34:57 -0500 (EST) Subject: [the-feebs-war-cvs] r8 - feebs Message-ID: <20071230013457.987A67E0A8@common-lisp.net> Author: gmilare Date: Sat Dec 29 20:34:57 2007 New Revision: 8 Removed: feebs/ Log: From gmilare at common-lisp.net Sun Dec 30 22:43:46 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Sun, 30 Dec 2007 17:43:46 -0500 (EST) Subject: [the-feebs-war-cvs] r9 - Message-ID: <20071230224346.E01F62F047@common-lisp.net> Author: gmilare Date: Sun Dec 30 17:43:46 2007 New Revision: 9 Modified: feebs.asd main.lisp mazes.lisp system.lisp Log: Modified: feebs.asd ============================================================================== --- feebs.asd (original) +++ feebs.asd Sun Dec 30 17:43:46 2007 @@ -15,12 +15,12 @@ :components (;; source (:cl-source-file "package") - (:cl-source-file "rules" :depends-on ("package")) - (:cl-source-file "system" :depends-on ("rules")) - (:cl-source-file "main" :depends-on ("rules")) - (:cl-source-file "extra" :depends-on ("rules")) - - (:cl-source-file "mazes" :depends-on ("extra")) + (:cl-source-file "system" :depends-on ("package")) + (:cl-source-file "main" :depends-on ("system")) + (:cl-source-file "rules" :depends-on ("main")) + + (:cl-source-file "extra") + (:cl-source-file "mazes") (:cl-source-file "brains" :depends-on ("extra")) (:file "graphics" :depends-on ("main")) Modified: main.lisp ============================================================================== --- main.lisp (original) +++ main.lisp Sun Dec 30 17:43:46 2007 @@ -44,7 +44,6 @@ during the game.") - ;;; Tests that behavior functions might use (declare (inline feeb-image-p fireball-image-p)) @@ -82,12 +81,11 @@ of *maze-x-size* by *maze-y-size*. Each element of the array is one of these: :rock - a wall - :mushroom-place - here is a place where mushrooms can grow up - :feeb-entry-place - here is a place where a feeb can reincarnate + :mushroom-place - place where mushrooms can grow up + :feeb-entry-place -place where a feeb can reincarnate nil - nothing special -Just remember that variables can change the behavior of this function, -like *may-get-maze-map-p* which, if nil, makes this function return -an array of nils" +Just remember that if *may-get-maze-map-p* is nil, +this function return an array of nils" (let ((new-maze (make-array (list *maze-x-size* *maze-y-size*)))) (dotimes (x *maze-x-size*) (dotimes (y *maze-y-size*) @@ -152,14 +150,14 @@ (defvar *feebs-to-be* nil) -(defun define-feeb (name brain &optional graphics) +(defun define-feeb (name brain &key graphics (class 'feeb)) "Defines a feeb with name NAME, behavior function BRAIN. If there is another feeb with the same name, overwrites it with a case sensitive test." (when (find name *feebs-to-be* :key #'car :test #'string= (delete-feeb name)) (warn "Feeb ~s already exists, deleting..." name)) - (push (list name brain graphs) *feebs-to-be*)) + (push (list name brain graphics class) *feebs-to-be*)) (defun delete-feeb (name) "Deletes the feeb which has name NAME, causing it not to @@ -179,8 +177,8 @@ (setf *feebs-to-be* nil)) (defun create-feebs () - (flet ((create-feeb (x-pos y-pos name brain graphs) - (let ((feeb (make-instance 'feeb + (flet ((create-feeb (x-pos y-pos name brain graphs class) + (let ((feeb (make-instance class :name name :brain brain :direction (random 4) @@ -206,41 +204,43 @@ (let ((mushrooms 0)) -(defun number-of-mushrooms (n) - (setf *mushrooms-to-grow* n)) + (defun number-of-mushrooms (n) + (setf *mushrooms-to-grow* n)) -(defun play-one-turn () - (setf mushrooms 0) ; restart the count - ;; This is defined by rules: - (start-turn) - ;; Maybe grow up mushrooms: - (let ((m-sites (sort *mushroom-sites* - #'(lambda (x y) - (declare (ignore x y)) - (zerop (random 2)))))) - (dotimes (i mushrooms) - (let ((site (pop m-sites))) - (create-mushroom (car site) (cdr site))))) - ;; Maybe rot some carcasses - ;; FIXME: put this in rules.lisp with better code - (loop for carc in *carcasses* - with ncarcasses do - (if (rot-carcass-p (first carc)) - (delete-object :carcass (second carc) (third carc))) - (progn - (push carc ncarcasses) - (incf (first carc))))) - ;; Move some fireballs: + (defun play-one-turn () + (setf mushrooms 0) ; restart the count + ;; This is defined by rules: + (start-turn) + ;; Maybe grow up mushrooms: + (let ((m-sites (sort *mushroom-sites* + #'(lambda (x y) + (declare (ignore x y)) + (zerop (random 2)))))) + (dotimes (i mushrooms) + (let ((site (pop m-sites))) + (create-mushroom (car site) (cdr site))))) + ;; Maybe rot some carcasses + ;; FIXME: Ugly code code, and + (loop for carc in *carcasses* + with ncarcasses do + (if (rot-carcass-p (first carc)) + (progn + (delete-object :carcass (second carc) (third carc)) + (reincarnate-feeb (pop *dead-feebs*))) + (progn + (push carc ncarcasses) + (incf (first carc))))) + ;; Move some fireballs: (dolist (fireball *fireballs-flying*) (move-object fireball (make-move-choice fireball))) - (progn - ;; Starve the feeb: - (when (<= (decf (feeb-energy-reserve feeb)) 0) - (destroy-object feeb :starve)) - ;; Compute vision for the feeb: - (compute-vision feeb) - ;; Collect the feeb's move - (setf (feeb-peeking feeb) nil) - (move-object feeb (setf (feeb-last-move feeb) - (make-move-choice feeb))))))) + (progn + ;; Starve the feeb: + (when (<= (decf (feeb-energy-reserve feeb)) 0) + (destroy-object feeb :starve)) + ;; Compute vision for the feeb: + (compute-vision feeb) + ;; Collect the feeb's move + (setf (feeb-peeking feeb) nil) + (move-object feeb (setf (feeb-last-move feeb) + (make-move-choice feeb))))))) ) \ No newline at end of file Modified: mazes.lisp ============================================================================== --- mazes.lisp (original) +++ mazes.lisp Sun Dec 30 17:43:46 2007 @@ -18,6 +18,7 @@ along with The Feebs War. If not, see . |# +;;; The mazes were ;;; Created by Jim Healy, July 1987. ;;; ;;; ************************************************** @@ -219,44 +220,114 @@ "X e * X" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) -;;; Use this template to create new mazes. - -#| (defparameter *maze-template* - '("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" - "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) |# - -;;; Or this function: +;;; Use this function to create new mazes +;;; of any size. (defun make-template (x-size y-size) - (loop repeat y-size collect - (make-string x-size :initial-element #\#))) + "Prints map template of the requested size. +Use this to create new mazes." + (dotimes (i y-size) + (format t "~@?~a~@?~%" + (if (zerop i) + "~4t'(\"" + "~6t\"") + (make-string x-size :initial-element #\X) + (if (= i y-size) + "\")" + "\"")))) + +(defun density (maze) + (loop for line in maze summing + (float (/ (loop for elt across line counting + (char/= #\X elt)) + (length line) (length maze))))) + +(defun bound-random (min avg max) + (let ((sort (random 2.0))) + (round + (if (< sort 1.0) + (+ min (* sort (- avg min))) + (+ avg (* (1- sort) (- max avg))))))) + +(defmacro ensure-bound (elt min max) + `(setf ,elt (max ,min (min ,max ,elt)))) + +(defun horiz-corridor (map y x1 x2) + (do ((x x1 (if (< x1 x2) (1+ x) (1- x)))) + ((= x x2)) + ;; we need to guarantee that everything in map is + ;; corridors, that is, can't have something like + ;; XXXXXXXX + ;; XXX X + ;; X XXX + ;; XXXXXXXX + ;; that big blank square isn't good due + ;; to the limited vision of the feebs + (and (not (aref map x (1- y))) ; blank square up + (or (and (not (aref map (1+ x) y)) ; blank square to the right + (not (aref map (1+ x) (1- y)))) ; blank square up-right + (and (not (aref map (1- x) (1- y))) ; blank square up-left + (not (aref map (1- x) y)))) ; blank square to the left + (return)) ; can't make a blank square here, stop + (and (not (aref map x (1+ y))) ; blank square down + (if (or (and (not (aref map (1+ x) y)) ; blank square to the right + (not (aref map (1+ x) (1+ y)))) ; blank square down-right + (and (not (aref map (1- x) (1+ y))) ; blank square down-left + (not (aref map (1- x) y)))) ; blank square to the left + (return))) ; can't make a blank square here, stop + (setf (aref map x y) nil)) + map) + +(defun vert-corridor (map x y1 y2) + (do ((y y1 (if (< y1 y2) (1+ y) (1- y)))) + ((= y y2)) + (and (not (aref map (1- x) y)) + (or (and (not (aref map x (1+ y))) + (not (aref map (1- x) (1+ y)))) + (and (not (aref map (1- x) (1- y))) + (not (aref map x (1- y))))) + (return)) + (and (not (aref map (1+ x) y)) + (if (or (and (not (aref map x (1+ y))) + (not (aref map (1+ x) (1+ y)))) + (and (not (aref map (1+ x) (1- y))) + (not (aref map x (1- y))))) + (return))) + (setf (aref map x y) nil)) + map) + +(defun generate-maze (x-size y-size + &key (density 0.4) + (corridor-x-min 1) + (corridor-x-max (- x-size 2)) + (corridor-x-avg (floor x-size 2)) + (corridor-y-min 1) + (corridor-y-max (- y-size 2)) + (corridor-y-avg (floor y-size 2))) + "Generates a maze of size X-SIZE x Y-SIZE (at least 10x10) +with no entry points and no mushroom sites. +DENSITY decides aproximatelly the ratio + (blank squares) / (total squares) +recomended to be between 0.25 and 0.45. +The horizontal corridors will be between +CORRIDOR-X-MIN and CORRIDOR-X-MAX with average CORRIDOR-X-AVG; +similarly for vertical corridors." + (if (or (< x 10) (< y 10)) + (error "Too small - should be at least 10x10.")) + ;; Certifying the values to be acceptable + (ensure-bound density 0.1 0.5) + (ensure-bound corridor-x-min 1 (- x-size 2)) + (ensure-bound corridor-x-avg 2 (- x-size 2)) + (ensure-bound corridor-x-max 3 (- x-size 2)) + (ensure-bound corridor-y-min 1 (- y-size 2)) + (ensure-bound corridor-y-avg 2 (- y-size 2)) + (ensure-bound corridor-y-max 3 (- y-size 2)) + ;; Beginning with an array of walls + (let ((map (make-array (list x-size y-size) + :initial-element t + :element-type 'boolean))) + (do* ((y 1 (1+ (random (- y-size 1)))) ; position of horizontal corridor + (x 1 (1+ (random (- x-size 1)))) ; position of vertical corridor + (x1 + (setf map (horiz-corridor + map 1 (1+ (random (- x-size 1))) \ No newline at end of file Modified: system.lisp ============================================================================== --- system.lisp (original) +++ system.lisp Sun Dec 30 17:43:46 2007 @@ -161,11 +161,8 @@ ;;; -*- General Rules -*- -(defmethod start-round () - t) - -(defmethod start-turn () - t) +(defgeneric start-turn (&key &allow-other-keys) + (:method () t)) @@ -173,32 +170,35 @@ ;;; Creating -(defmethod create-object (object x-pos y-pos) - (change-object-pos object x-pos y-pos)) +(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))) ;;; Reincarnating -(defmethod reincarnate-feeb ((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)) +(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))) ;;; Dying -(defmethod destroy-object ((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)) - (y (feeb-y-position feeb))) - (push (list 0 x y) *carcasses*) - (delete-object (feeb-image feeb) x y) - (place-object :carcass x y)) - (call-next-method)) +(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)) + (y (feeb-y-position feeb))) + (push (list 0 x y) *carcasses*) + (delete-object (feeb-image feeb) x y) + (place-object :carcass x y)) + (call-next-method))) @@ -274,84 +274,87 @@ ;;; Lets the feeb make a choice -(defmethod make-move-choice ((feeb feeb)) - (funcall (feeb-brain feeb) - (feeb-status feeb) - (feeb-proximity feeb) - (feeb-vision feeb) - (feeb-vision-left feeb) - (feeb-vision-right feeb))) +(defgeneric make-move-choice (object &key &allow-other-keys) + (:method ((feeb feeb)) + (funcall (feeb-brain feeb) + (feeb-status feeb) + (feeb-proximity feeb) + (feeb-vision feeb) + (feeb-vision-left feeb) + (feeb-vision-right feeb)))) ;;; Moving -(defmethod make-move (object (move (eql :turn-right))) - (setf (object-direction object) - (right-of (object-direction object))) - t) - -(defmethod make-move (object (move (eql :turn-around))) - (setf (object-direction object) - (behind (object-direction object))) - t) - -(defmethod make-move (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) +(defgeneric make-move (object move) + (:method (object (move (eql :turn-right))) + (setf (object-direction object) + (right-of (object-direction object))) + t) + + (:method (object (move (eql :turn-around))) + (setf (object-direction object) + (behind (object-direction object))) + t) + + (: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 -(defmethod make-move ((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))))) + (: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 -(defmethod make-move ((feeb feeb) (move (eql :move-forward))) - (let ((thing (find-if #'fireball-image-p stuff))) - (when thing (destroy-object feeb thing) - (return-from make-move t))) - (call-next-method)) - -(defmethod make-move ((feeb feeb) (move (eql :flame))) - (let ((x (feeb-x-position feeb)) - (y (feeb-y-position feeb)) - (fireball - (make-fireball-image (feeb-facing feeb) - feeb x y (forward-dx facing) - (forward-dy facing)))) - (push fireball *fireballs-flying*) - t)) - -(defmethod make-move ((feeb feeb) (move (eql :eat-mushroom))) - (let ((x (feeb-x-position feeb)) - (y (feeb-y-position feeb))) - (when (member :mushroom (aref *maze* x y)) - (delete-object :mushroom x y) - t))) - -(defmethod make-move ((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))) - -(defmethod make-move ((feeb feeb) (move (eql :peek-left))) - (multiple-value-bind (x y stuff) - (get-forward-pos feeb) - (unless (wallp stuff) - (setf (peeking feeb) move))) - t) - -(defmethod make-move ((feeb feeb) (move (eql :peek-right))) - (multiple-value-bind (x y stuff) - (get-forward-pos feeb) - (unless (wallp stuff) - (setf (peeking feeb) move))) - t) + (:method ((feeb feeb) (move (eql :move-forward))) + (let ((thing (find-if #'fireball-image-p stuff))) + (when thing (destroy-object feeb thing) + (return-from make-move t))) + (call-next-method)) + + (:method ((feeb feeb) (move (eql :flame))) + (let ((x (feeb-x-position feeb)) + (y (feeb-y-position feeb)) + (fireball + (make-fireball-image (feeb-facing feeb) + feeb x y (forward-dx facing) + (forward-dy facing)))) + (push fireball *fireballs-flying*) + t)) + + (: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)) + (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))) + + (:method ((feeb feeb) (move (eql :peek-left))) + (multiple-value-bind (x y stuff) + (get-forward-pos feeb) + (unless (wallp stuff) + (setf (peeking feeb) move))) + t) + + (:method make-move ((feeb feeb) (move (eql :peek-right))) + (multiple-value-bind (x y stuff) + (get-forward-pos feeb) + (unless (wallp stuff) + (setf (peeking feeb) move))) + t) + ) ; end of make-move generic function From gmilare at common-lisp.net Mon Dec 31 00:21:19 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Sun, 30 Dec 2007 19:21:19 -0500 (EST) Subject: [the-feebs-war-cvs] r10 - Message-ID: <20071231002119.77CAD140F2@common-lisp.net> Author: gmilare Date: Sun Dec 30 19:21:19 2007 New Revision: 10 Modified: main.lisp mazes.lisp Log: Functions make-template, generate-maze added and tested. Modified: main.lisp ============================================================================== --- main.lisp (original) +++ main.lisp Sun Dec 30 19:21:19 2007 @@ -196,7 +196,7 @@ (setf *feebs* nil) (dolist (feeb-spec *feebs-to-be*) (let ((pos (pop entries)))) - (apply 'create-feeb (car pos) (cdr pos) feeb-spec)))) + (apply 'create-feeb (car pos) (cdr pos) feeb-spec))))) @@ -231,16 +231,19 @@ (push carc ncarcasses) (incf (first carc))))) ;; Move some fireballs: - (dolist (fireball *fireballs-flying*) - (move-object fireball (make-move-choice fireball))) - (progn - ;; Starve the feeb: - (when (<= (decf (feeb-energy-reserve feeb)) 0) - (destroy-object feeb :starve)) - ;; Compute vision for the feeb: - (compute-vision feeb) - ;; Collect the feeb's move - (setf (feeb-peeking feeb) nil) - (move-object feeb (setf (feeb-last-move feeb) - (make-move-choice feeb))))))) + (dolist (fireball *fireballs-flying*) + (move-object fireball (make-move-choice fireball))) + (dolist (feeb *feebs*) + (unless (feeb-dead-p feeb) + ;; Starve the feeb: + (when (<= (decf (feeb-energy-reserve feeb)) 0) + (destroy-object feeb :starve)) + ;; Compute vision for the feeb: + (compute-vision feeb))) + (dolist (feeb *feebs*) + (unless (feeb *feebs*) + ;; Collect the feeb's move + (setf (feeb-peeking feeb) nil) + (move-object feeb (setf (feeb-last-move feeb) + (make-move-choice feeb)))))) ) \ No newline at end of file Modified: mazes.lisp ============================================================================== --- mazes.lisp (original) +++ mazes.lisp Sun Dec 30 19:21:19 2007 @@ -236,21 +236,32 @@ "\")" "\"")))) -(defun density (maze) - (loop for line in maze summing - (float (/ (loop for elt across line counting - (char/= #\X elt)) - (length line) (length maze))))) - -(defun bound-random (min avg max) - (let ((sort (random 2.0))) - (round - (if (< sort 1.0) - (+ min (* sort (- avg min))) - (+ avg (* (1- sort) (- max avg))))))) +(defun density (maze xs ys) + (let ((sum 0)) + (dotimes (x xs) + (dotimes (y ys) + (if (not (aref maze x y)) + (incf sum)))) + (float (/ sum (* xs ys))))) + +(defun bound-random (start min avg max) + (+ start + (* (expt -1 (random 2)) + (let ((sort (random 2.0))) + (round + (if (< sort 1.0) + (+ min (* sort (- avg min))) + (+ avg (* (1- sort) (- max avg))))))))) + +(defun random-elt (seq) + (if seq + (elt seq (random (length seq))))) (defmacro ensure-bound (elt min max) - `(setf ,elt (max ,min (min ,max ,elt)))) + `(setf ,elt (bound ,elt ,min ,max))) + +(defun bound (elt min max) + (max min (min max elt))) (defun horiz-corridor (map y x1 x2) (do ((x x1 (if (< x1 x2) (1+ x) (1- x)))) @@ -270,11 +281,11 @@ (not (aref map (1- x) y)))) ; blank square to the left (return)) ; can't make a blank square here, stop (and (not (aref map x (1+ y))) ; blank square down - (if (or (and (not (aref map (1+ x) y)) ; blank square to the right - (not (aref map (1+ x) (1+ y)))) ; blank square down-right - (and (not (aref map (1- x) (1+ y))) ; blank square down-left - (not (aref map (1- x) y)))) ; blank square to the left - (return))) ; can't make a blank square here, stop + (or (and (not (aref map (1+ x) y)) ; blank square to the right + (not (aref map (1+ x) (1+ y)))) ; blank square down-right + (and (not (aref map (1- x) (1+ y))) ; blank square down-left + (not (aref map (1- x) y)))) ; blank square to the left + (return)) ; can't make a blank square here, stop (setf (aref map x y) nil)) map) @@ -296,38 +307,77 @@ (setf (aref map x y) nil)) map) +(defun translate (map xs ys) + (loop for y from (1- ys) downto 0 collect + (let ((str (make-string xs))) + (dotimes (x xs str) + (setf (aref str x) + (if (aref map x y) + #\X + #\Space)))))) + +;;; This one generates a almost ready-to-use map + (defun generate-maze (x-size y-size &key (density 0.4) (corridor-x-min 1) (corridor-x-max (- x-size 2)) - (corridor-x-avg (floor x-size 2)) + (corridor-x-avg (floor x-size 4)) (corridor-y-min 1) (corridor-y-max (- y-size 2)) - (corridor-y-avg (floor y-size 2))) + (corridor-y-avg (floor y-size 4))) "Generates a maze of size X-SIZE x Y-SIZE (at least 10x10) with no entry points and no mushroom sites. DENSITY decides aproximatelly the ratio (blank squares) / (total squares) recomended to be between 0.25 and 0.45. -The horizontal corridors will be between -CORRIDOR-X-MIN and CORRIDOR-X-MAX with average CORRIDOR-X-AVG; -similarly for vertical corridors." - (if (or (< x 10) (< y 10)) +The horizontal corridors will be between CORRIDOR-X-MIN +and CORRIDOR-X-MAX around CORRIDOR-X-AVG, when +possible; similarly for vertical corridors." + (if (or (< x-size 10) (< y-size 10)) (error "Too small - should be at least 10x10.")) ;; Certifying the values to be acceptable - (ensure-bound density 0.1 0.5) - (ensure-bound corridor-x-min 1 (- x-size 2)) - (ensure-bound corridor-x-avg 2 (- x-size 2)) - (ensure-bound corridor-x-max 3 (- x-size 2)) - (ensure-bound corridor-y-min 1 (- y-size 2)) - (ensure-bound corridor-y-avg 2 (- y-size 2)) - (ensure-bound corridor-y-max 3 (- y-size 2)) + (ensure-bound corridor-x-avg + (ensure-bound corridor-x-min 1 (- x-size 2)) + (ensure-bound corridor-x-max 3 (- x-size 2))) + (ensure-bound corridor-y-avg + (ensure-bound corridor-y-min 1 (- y-size 2)) + (ensure-bound corridor-y-max 3 (- y-size 2))) ;; Beginning with an array of walls (let ((map (make-array (list x-size y-size) :initial-element t :element-type 'boolean))) - (do* ((y 1 (1+ (random (- y-size 1)))) ; position of horizontal corridor - (x 1 (1+ (random (- x-size 1)))) ; position of vertical corridor - (x1 - (setf map (horiz-corridor - map 1 (1+ (random (- x-size 1))) \ No newline at end of file + (do* ((i 1 (1+ i)) + (y 1 y*) ; position of horizontal corridor + (y* (- y-size 2) (1+ (random (- y-size 2)))) + (x1 (1+ (random (- x-size 2))) ; start position of horiz corridor + x1*) + (x1* (1+ (random (- x-size 2))) + (random-elt + (loop for x from 1 to (- x-size 2) ; any blank space + if (not (aref map x y)) collect x))) ; in line + (x2 (if x1 (bound-random x1 corridor-x-min + corridor-x-avg corridor-x-max)) + (if x1 (bound-random x1 corridor-x-min + corridor-x-avg corridor-x-max))) + (x 1 x*) ; position of vertical corridor + (x* (- x-size 2) (1+ (random (- x-size 2)))) + (y1 (1+ (random (- y-size 2))) + y1*) + (y1* (1+ (random (- y-size 2))) + (random-elt + (loop for y from 1 to (- y-size 2) + if (not (aref map x y)) collect y))) + (y2 (if y1 (bound-random y1 corridor-y-min + corridor-y-avg corridor-y-max)) + (if y1 (bound-random y1 corridor-y-min + corridor-y-avg corridor-y-max)))) + ((or (>= (density map x-size y-size) density) + (> i (* density x-size y-size))) ; quits after trying TOO MUCH + (translate map x-size y-size)) + (if x1 + (setf map (horiz-corridor map y x1 + (bound x2 1 (- x-size 2))))) + (if y1 + (setf map (vert-corridor map x y1 + (bound y2 1 (- x-size 2)))))))) From gmilare at common-lisp.net Mon Dec 31 21:35:36 2007 From: gmilare at common-lisp.net (gmilare at common-lisp.net) Date: Mon, 31 Dec 2007 16:35:36 -0500 (EST) Subject: [the-feebs-war-cvs] r11 - Message-ID: <20071231213536.67C0D7A00A@common-lisp.net> Author: gmilare Date: Mon Dec 31 16:35:35 2007 New Revision: 11 Added: images.lisp rules.lisp Modified: feebs.tex main.lisp mazes.lisp package.lisp system.lisp Log: Modified: feebs.tex ============================================================================== --- feebs.tex (original) +++ feebs.tex Mon Dec 31 16:35:35 2007 @@ -60,10 +60,9 @@ \textit{The Feebs War} is a modified version of Planet of the Feebs \url{http://www.cliki.net/}, a game made for people learn and improve their lisp and code manipulation tecniques. The graphics are now displayed -using PAL \url{http://common-lisp.net/project/pal/}'s libraries, +using Lispbuilder \url{http://lispbuilder.sourceforge.net}'s libraries, so the problems with portability from CMUCL and X Window Sistem do -not exist anymore. Also the code is cleaner and simpler both to make -a feeb and to read the code. +not exist anymore. Also the code is cleaner and more extensible. \end{abstract} \tableofcontents{} @@ -72,16 +71,17 @@ The Feebs are intelligent and hostile creatures that live inside maze tunnels. They also have no mercy with each other, so they frequently -throw a letal flame from through their mouth, and, after that, they -can eat the carcass left. But throwing flames have an energy cost, -so they must keep tracking for food. +throw a letal flame from through their mouth, getting rid of their +opponent and eatting the carcass left. But throwing flames have an +energy cost, so they must keep tracking for food. This game is intended to help lisp newbies (or maybe a little more advanced lispers) to learn lisp. A player must create a function that receives what his/her feeb is seeing and feeling, and returns what it will do next. To create the better feeb, one can create variables to store data from previous moves (or not), and can also use all the -power of lisp to improve his/her creature. +power of lisp to improve his/her creature. But the most important +is to make good choices and be aware of danger! \subsection{Changes from \emph{Planet of the Feebs}} @@ -100,22 +100,22 @@ So, these are (some of) the changes: \begin{itemize} -\item The graphics are not based on X Window Sistem anymore, but on PAL, +\item The graphics are not based on X Window Sistem anymore, but on \textit{Lispbuilder}, and there are no CMUCL's event handler. This way, the code is more -portable and graphics can be improved without those hundreds of lines -that the original version has. Just creating some .bmp or .jpg files -of a feeb and your feeb is much more personalized! +portable and graphics can be improved. Just creating some image +files of a feeb and your feeb is much more personalized! \item Every element of the map (except walls) is a list, so the brain of a feeb doesn't need to test all the time if the element is an atom or a list (wich, in my opinion, is really boring, unlispy and unnecessary 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 Someone watching the game can control a Feeb with the keyboard, if -he/she wants to, and say when the game must finish. +\item Many functions and variables are changed and others were added \item This document 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 search for some information. +is easier to understand 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! \end{itemize} \section{The Game} @@ -130,27 +130,34 @@ After all feebs move, the flames thrown before also move (or dissipate), carcasses may rot and mushrooms may grow, accordingly to some rules. -To see what values are taken, one can use \textsf{\textbf{(list-parameter-settings)}}. -Using \textsf{\textbf{setf}} gives the possibility to change them -and \textsf{\textbf{documentation}} can be used to know them. Just -remember that every probability must be a rational number (like 1/2). -These parameters are just for one to know how the game is going to -be, but in the begining there is no need to explicitly use them when -creating the brain of a feeb. +The game rules are defined by parameters. These parameters can be read +by the command \textsf{\textbf{(get-feeb-parm~}'parameter\textbf{)}} +To see all parameters, values and also all the documentation, one can use +\textsf{\textbf{(list-parameter-settings)}}. Using +\textsf{\textbf{(change-feeb-parm}'parameter~value\textbf{)}} +gives the possibility to change them (but not during the game) and +\textsf{\textbf{(documentation~}'parameter~'feeb-parm\textbf{)}} +can be used to know them. Just remember that every probability +must be a rational number (like 1/2). + +But don't panic! These parameters are just for one to know how +the game is going to be, but in the begining there is no need +to explicitly use them when creating the brain of a feeb. +The best way to create a feeb is watching a game (among system feebs), +improving it (it is defined in file brains.lisp) a little more, +testing the changes... These are some global parameters: \begin{lyxlist}{00.00.0000} -\item [{\textsf{\textbf{{*}game-length{*}}}}] Number of turns the game -will last, or nil if there is a human player. -\item [{\textsf{\textbf{{*}points-for-killing{*}}}}] How many points some +\item [{\textsf{\textbf{'game-length}}}] Number of turns the game +will last. +\item [{\textsf{\textbf{'points-for-killing}}}] How many points some feeb earn for killing someone. -\item [{\textsf{\textbf{{*}points-for-dying{*}}}}] How many points some +\item [{\textsf{\textbf{'points-for-dying}}}] How many points some feeb earn for dying (usually negative). -\item [{\textsf{\textbf{{*}maze-x-size{*}}}}] Horizontal size of the maze. -\item [{\textsf{\textbf{{*}maze-y-size{*}}}}] Vertical size of the maze. -\item [{\textsf{\textbf{(get-maze-map)}}}] This command can be used to -get the map (see section \ref{sub:Map}). +\item [{\textsf{\textbf{'maze-x-size}}}] Horizontal size of the maze. +\item [{\textsf{\textbf{'maze-y-size}}}] Vertical size of the maze. \end{lyxlist} \subsection{Throwing flame} @@ -162,28 +169,27 @@ 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 killing feebs it encounters, transforming them into carcass. If there -is a wall, the flame can reflect, and will turn 180 degrees. +is a wall, the flame can reflect, and, if so, it will turn 180 degrees. -Once a feeb is killed, in it's place in the maze there will appear -a carcass. The feeb goes to the end of the killed feebs line. Whenever -a carcass rots, the first feeb in line will reincarnate. So, dying -is not so terrible. +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. These are the parameters related to flames: \begin{lyxlist}{00.00.0000} -\item [{\textsf{\textbf{{*}flame-energy{*}}}}] Amount of energy lost after +\item [{\textsf{\textbf{'flame-energy}}}] Amount of energy lost after throwing a flame. -\item [{\textsf{\textbf{{*}fireball-guaranteed-lifetime{*}}}}] Number of +\item [{\textsf{\textbf{'fireball-guaranteed-lifetime}}}] Number of turns that a fireball is guaranteed not to dissipate, unless it encounters a wall. -\item [{\textsf{\textbf{{*}fireball-dissipation-probability{*}}}}] Probability +\item [{\textsf{\textbf{'fireball-dissipation-probability}}}] Probability of the flame to dissipate each turn after the apropriate time. -\item [{\textsf{\textbf{{*}fireball-reflection-probability{*}}}}] Probability +\item [{\textsf{\textbf{'fireball-reflection-probability}}}] Probability of the flame to reflect when encountering a wall. -\item [{\textsf{\textbf{{*}flame-no-recovery-time{*}}}}] Number of turns +\item [{\textsf{\textbf{'flame-no-recovery-time}}}] Number of turns that a feeb cannot fire. -\item [{\textsf{\textbf{{*}flame-recovery-probability{*}}}}] Probability +\item [{\textsf{\textbf{'flame-recovery-probability}}}] Probability of the feeb to recover the hability to throw a flame, after the apropriate time. \end{lyxlist} @@ -199,38 +205,36 @@ These are the quantities: \begin{lyxlist}{00.00.0000} -\item [{\textsf{\textbf{{*}mushroom-energy{*}}}}] Amount of energy recovered +\item [{\textsf{\textbf{'mushroom-energy}}}] Amount of energy recovered when the feeb eats a mushroom. -\item [{\textsf{\textbf{{*}carcass-energy{*}}}}] Amount of energy recovered +\item [{\textsf{\textbf{'carcass-energy}}}] Amount of energy recovered each turn that the feeb eats a carcass. -\item [{\textsf{\textbf{{*}carcass-guaranteed-lifetime{*}}}}] Number of -turns that a carcass will surely stay there. After these turns, it +\item [{\textsf{\textbf{'carcass-guaranteed-lifetime}}}] Number of +turns that a carcass will surely not rot. After these turns, it can rot, depending on probabilities. -\item [{\textsf{\textbf{{*}carcass-rot-probability{*}}}}] Probability of +\item [{\textsf{\textbf{'carcass-rot-probability}}}] Probability of the carcass to rot, after the apropriate time. -\item [{\textsf{\textbf{{*}maximum-energy{*}}}}] Maximum amount of energy +\item [{\textsf{\textbf{'maximum-energy}}}] Maximum amount of energy that a feeb can have eating. -\item [{\textsf{\textbf{{*}starting-energy{*}}}}] Amount of energy a feeb +\item [{\textsf{\textbf{'starting-energy}}}] Amount of energy a feeb has when it reincarnates. -\item [{\textsf{\textbf{{*}number-of-mushrooms{*}}}}] Quantity of mushrooms +\item [{\textsf{\textbf{'number-of-mushrooms}}}] Quantity of mushrooms that exist in the maze. \end{lyxlist} \section{The Feeb} -A feeb needs four things: a name, a brain, an initialize function -(optional) and a set of graphics (optional). +A feeb needs four things: a name, a brain and a set of graphics (optional). \begin{itemize} \item The name, a string. \item The brain is a function that decides what the feeb will do next, based -on what it is seeing and feeling. -\item The initializer is invoked when the game is about to start, so it -can analyze the map, global parameters, and so on. +on what it is seeing and feeling. \item The set of graphics is an image file (of format BMP, JPEG, PNG, and any others that supported by SDL\_image). \end{itemize} -One can create a feeb calling \textsf{\textbf{(define-feeb~}}\textsf{name~brain~}\textsf{\textbf{:initializer}}\textsf{~prepare~}\textsf{\textbf{:graphics}}\textsf{~graphics}\textsf{\textbf{)}}. +One can create a feeb calling +\textsf{\textbf{(define-feeb}~name~brain~\textbf{:graphics}~graphics\textbf{)}}. If name is already used, a warning will be signaled, and the old feeb will be substituted. Calling \textsf{\textbf{(list-of-feebs)}} will return the list of the feebs (names only) that will be defined when @@ -261,21 +265,22 @@ \item [{\textsf{\textbf{:peek-left}}}] Peek to the left around a corner. The creature does note actually move, but, in the next turn, the creature will have the same vision that it would have if he had moved one step -foward and turned left. This is used so a feeb can analize a corridor +foward and turned left (and one step back because the feeb needs to see +what is actually in front of it). Peeking used so a feeb can analize a corridor before trespassing it. \item [{\textsf{\textbf{:peek-right}}}] Peek to the right around a corner, -analogous of \textsf{\textbf{:peek-left}}. +analogous to \textsf{\textbf{:peek-left}}. \item [{\textsf{\textbf{:eat-carcass}}}] Eat a carcass if there is any -available in the feeb's square. The amount of \textsf{\textbf{{*}carcass-energy{*}}} -is restored to the feeb's energy. +available in the feeb's square. The amount of the parameter +\textsf{\textbf{'carcass-energy}} is restored to the feeb's energy. \item [{\textsf{\textbf{:eat-mushroom}}}] Eat a mushroom if there is any -available in the feeb's square. The amount of \textsf{\textbf{{*}mushroom-energy{*}}} -is restored to the feeb's energy. +available in the feeb's square. The amount of the parameter +\textsf{\textbf{'mushroom-energy}} is restored to the feeb's energy. \end{lyxlist} \subsection{Information available} -The brain of a feeb mus take five arguments; I'll call them \textsf{\emph{status}}, +The brain of a feeb must take five arguments; I'll call them \textsf{\emph{status}}, \textsf{\emph{proximity}}, \textsf{\emph{vision}}, \textsf{\emph{vision-left}} and \textsf{\emph{vision-right}}. @@ -291,51 +296,43 @@ \begin{lyxlist}{00.00.0000} \item [{\textsf{\textbf{(name}}\textsf{\emph{~status}}\textsf{\textbf{)}}}] \begin{flushleft} -The -name of the feeb. +The name of the feeb. \par\end{flushleft} -\item [{\textsf{\textbf{(facing~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} -Where -the feeb is facing, one of the constants provided: \textsf{\textbf{north}}, -\textsf{\textbf{south}}, \textsf{\textbf{east}} or \textsf{\textbf{west}}, +\item [{\textsf{\textbf{(facing}}\textsf{\emph{~status}}\textsf{\textbf{)}}}] \begin{flushleft} +Where the feeb is facing to, one of the constants provided: \textsf{\textbf{north}}, +\textsf{\textbf{east}}, \textsf{\textbf{south}} or \textsf{\textbf{west}}, wich are 0, 1, 2 and 3 respectivelly. \par\end{flushleft} -\item [{\textsf{\textbf{(x-position~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} -The -horizontal position of the feeb, increasing to east. If \textsf{\textbf{{*}sense-location{*}}} -is nil, it returns nil instead. -\par\end{flushleft} -\item [{\textsf{\textbf{(y-position~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} -The -vertical position of the feeb, increasing to north. If \textsf{\textbf{{*}sense-location{*}}} -is nil, it returns nil instead. -\par\end{flushleft} -\item [{\textsf{\textbf{(peeking~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} -If -it is \textsf{\textbf{:left}} or \textsf{\textbf{:right}}, it means +\item [{\textsf{\textbf{(x-position}\emph{~status}\textbf{)}}}] \begin{flushleft} +The horizontal position of the feeb, increasing to east. +If \textsf{\textbf{'sense-location-p}} is nil, it returns nil instead. +\par\end{flushleft} +\item [{\textsf{\textbf{(y-position}\emph{~status}\textbf{)}}}] \begin{flushleft} +The vertical position of the feeb, increasing to north. +If \textsf{\textbf{'sense-location-p}} is nil, it returns nil instead. +\par\end{flushleft} +\item [{\textsf{\textbf{(peeking}\emph{~status}\textbf{)}}}] \begin{flushleft} +If it is \textsf{\textbf{:peek-left}} or \textsf{\textbf{:peek-right}}, it means that the current \textsf{\emph{vision}} provided is result of a previous \textsf{\textbf{:peek-left}} or \textsf{\textbf{:peek-right}} command -of the same feeb. Otherwise, it is \textsf{\textbf{nil}}. +of the same feeb. Otherwise, it is \textsf{\textbf{nil}}. Note that +\textsf{\emph{proximity}} is \emph{not} affected. \par\end{flushleft} -\item [{\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} -Indicates -the amount of valid entries in \textsf{\emph{vision}}. It actually -means that \textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{))}} +\item [{\textsf{\textbf{(line-of-sight}\emph{~status}\textbf{)}}}] \begin{flushleft} +Indicates the amount of valid entries in \textsf{\emph{vision}}. It actually +means that \textsf{\textbf{(aref}\emph{~vision~}\textbf{(line-of-sight}\emph{~status}\textbf{))}} will return \textsf{\textbf{:rock}}. \par\end{flushleft} -\item [{\textsf{\textbf{(ready-to-fire~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} -\textsf{\textbf{T}} -indicates that the feeb is ready to fire. \textsf{\textbf{Nil}} indicates -it is not. -\par\end{flushleft} -\item [{\textsf{\textbf{(aborted}}\textsf{\emph{~status}}\textsf{\textbf{)}}}] \begin{flushleft} -Related -with timing. Returns \textsf{\textbf{T}} if the last move of feeb -was aborted because of speed. -\par\end{flushleft} -\item [{\textsf{\textbf{(last-move~}}\textsf{\emph{status}}\textsf{\textbf{)}}}] \begin{flushleft} -The -feeb's previous move, or \textsf{\textbf{:dead}} if it has just reincarnated. +\item [{\textsf{\textbf{(ready-to-fire}\emph{~status}\textbf{)}}}] \begin{flushleft} +If \textsf{\textbf{T}} indicates that the feeb is ready to fire. +If \textsf{\textbf{Nil}} indicates it is not. +\par\end{flushleft} +\item [{\textsf{\textbf{(aborted}\emph{~status}\textbf{)}}}] \begin{flushleft} +Related with timing. Returns \textsf{\textbf{T}} if the last move of feeb +was aborted because of timing issues. +\par\end{flushleft} +\item [{\textsf{\textbf{(last-move}\emph{~status}\textbf{)}}}] \begin{flushleft} +The feeb's previous move, or \textsf{\textbf{:dead}} if it has just reincarnated. \par\end{flushleft} \end{lyxlist} @@ -345,45 +342,43 @@ what the feeb sees. The structure \textsf{\emph{proximity}} has the contents of the squares -near the feeb, 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} -Contents -of the feeb's current square. +\item [{\textsf{\textbf{(my-square}}\textsf{\emph{~proximity}}\textsf{\textbf{)}}}] \begin{flushleft} +Contents of the feeb's current square. \par\end{flushleft} -\item [{\textsf{\textbf{(left-square~}}\textsf{\emph{proximity}}\textsf{\textbf{)}}}] \begin{flushleft} -Contents -of the right square of the feeb. +\item [{\textsf{\textbf{(left-square}}\textsf{\emph{~proximity}}\textsf{\textbf{)}}}] \begin{flushleft} +Contents of the right square of the feeb. \par\end{flushleft} -\item [{\textsf{\textbf{(right-square~}}\textsf{\emph{proximity}}\textsf{\textbf{)}}}] \begin{flushleft} -Contents -of the left square of the feeb. +\item [{\textsf{\textbf{(right-square}}\textsf{\emph{~proximity}}\textsf{\textbf{)}}}] \begin{flushleft} +Contents of the left square of the feeb. \par\end{flushleft} \item [{\textsf{\textbf{(rear-square}}\textsf{\emph{~proximity}}\textsf{\textbf{)}}}] \begin{flushleft} -Contents -of the square behind the feeb. +Contents of the square behind the feeb. \par\end{flushleft} \item [{The}] vector \textsf{\emph{vision}} has the contents of the squares -that are in front of the feeb. For example, \textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{0}\textsf{\textbf{)}} -will return the contents of the square in front of the feeb, \textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{1}\textsf{\textbf{)}} +that are in front of the feeb. For example, +\textsf{\textbf{(aref}\emph{~vision~}0\textbf{)}} +will return the contents of the square in front of the feeb, +\textsf{\textbf{(aref}\emph{~vision~}1\textbf{)}} will return the contents of the next square, and so on. As said before, -\textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{))}} +\textsf{\textbf{(aref}\emph{~vision~}\textbf{(line-of-sight}\emph{~status}\textbf{))}} will be the first :rock encountered. All subsequents square, like -\textsf{\textbf{(aref~}}\textsf{\emph{vision~}}\textsf{\textbf{(+~}}\textsf{1~}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{)))}}, +\textsf{\textbf{(aref}\emph{~vision~}\textbf{(+}~1~\textbf{(line-of-sight}\emph{~status}\textbf{)))}}, will be garbage and should not be used. \end{lyxlist} The contents of one square returned by any of these calls is either -:rock or a list of elements, or maybe \textsf{\textbf{nil}} if the +:rock or a list of elements, or \textsf{\textbf{()}} if the square is empty. Each element of the square is one of these: \begin{itemize} -\item \textbf{Feeb image.} One can call \textsf{\textbf{(feeb-image-p~}}\textsf{element}\textsf{\textbf{)}} +\item \textbf{Feeb image.} One can call \textsf{\textbf{(feeb-image-p}~element\textbf{)}} to see if element is a feeb image. -\item \textbf{Fireball image.} One can call \textsf{\textbf{(fireball-image-p~}}\textsf{element}\textsf{\textbf{)}} +\item \textbf{Fireball image.} One can call \textsf{\textbf{(fireball-image-p}~element\textbf{)}} to check if element is a fireball image. \item \textsf{\textbf{:carcass}}. If there is a \textsf{\textbf{:carcass}} -in the square of the feeb (i.e. in \textsf{\textbf{(my-square~}}\textsf{\emph{proximity}}\textsf{\textbf{)}}), +in the square of the feeb (i.e. in \textsf{\textbf{(my-square}}\textsf{\emph{~proximity}}\textsf{\textbf{)}}), the call \textsf{\textbf{:eat-carcass}} will make the feeb eat it. \item \textsf{\textbf{:mushroom}}. Analogous to \textsf{\textbf{:carcass}}. A mushroom appears randomly in places (mushroom patchs) previouly @@ -399,24 +394,20 @@ These are the fields available: \begin{lyxlist}{00.00.0000} -\item [{\textsf{\textbf{(feeb-image-name}}\textsf{~feeb-image}\textsf{\textbf{)}}}] \begin{flushleft} -The -name of the feeb. Maybe you can know it's weakpoints. -\par\end{flushleft} -\item [{\textsf{\textbf{(feeb-image-facing~}}\textsf{feeb-image}\textsf{\textbf{)}}}] \begin{flushleft} -The -facing of the feeb. This way the brain function can see if the feeb-image -either sees it or not. -\par\end{flushleft} -\item [{\textsf{\textbf{(feeb-image-peeking~}}\textsf{feeb-image}\textsf{\textbf{)}}}] \begin{flushleft} -Returns -\textsf{\textbf{:peek-left}} or \textsf{\textbf{:peek-right}} if the +\item [{\textsf{\textbf{(feeb-image-name}~feeb-image\textbf{)}}}] \begin{flushleft} +The name of the feeb. (Maybe you know it's weakpoints?) +\par\end{flushleft} +\item [{\textsf{\textbf{(feeb-image-facing}~feeb-image\textbf{)}}}] \begin{flushleft} +The facing of the feeb. This way the brain function can +see if the feeb-image either sees the feeb which is playing or not. +\par\end{flushleft} +\item [{\textsf{\textbf{(feeb-image-peeking}~feeb-image\textbf{)}}}] \begin{flushleft} +Returns \textsf{\textbf{:peek-left}} or \textsf{\textbf{:peek-right}} if the feeb is peeking to (its) left or right, or \textsf{\textbf{nil}} if not. \par\end{flushleft} -\item [{\textsf{\textbf{(fireball-image-direction~}}\textsf{fireball-image}\textsf{\textbf{)}}}] \begin{flushleft} -The -direction that the fireball image is going to. +\item [{\textsf{\textbf{(fireball-image-direction}~fireball-image\textbf{)}}}] \begin{flushleft} +The direction that the fireball image is going to. \par\end{flushleft} \end{lyxlist} @@ -424,8 +415,8 @@ \textsf{\emph{vision-left}} and \textsf{\emph{vision-right}} are vectors similar to vision, but they are less precise in the contents. Also -their valid contents are limited by \textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{)}}, -so \textsf{\textbf{(aref~}}\textsf{\emph{vision-left~}}\textsf{\textbf{(line-of-sight~}}\textsf{\emph{status}}\textsf{\textbf{))}}, +their valid contents are limited by \textsf{\textbf{(line-of-sight}~\emph{status}\textbf{)}}, +so \textsf{\textbf{(aref}~\emph{vision-left}~\textbf{(line-of-sight}~\emph{status}\textbf{))}}, for example, will return \textsf{\textbf{:unknown}}. Note that feebs that are not peeking, mushrooms and carcasses are @@ -451,6 +442,20 @@ code and know what they do. +\subsection{Changing the map layout} + +It is possible to change the layout of the map by calling +\textsf{\textbf{(change-layout}~new-layout\textbf{)}}. +There are a few predefined mazes that are in variables \textsf{\textbf{{*}maze-0{*}}} +throw \textsf{\textbf{{*}maze-5{*}}}. If you want to create a new +map, you can start by an empty template of any size provided by +\textsf{\textbf{(make-template}~x-size~y-size~\textbf{:density}~density\textbf{)}}. +The density is a number, recomended to be between 0.25 and 0.45, +which tells the portion of the maze should be blank spaces. +The function quits after a while if it doesn't meet this portion. See +its documentation for more details and options. + + \subsection{Graphics} With this version of the game, it's possible to choose the graphics @@ -466,7 +471,7 @@ After creating the image file, you must call \textsf{\textbf{(create-graphics}}\textsf{~path-to-image-file}\textsf{\textbf{)}}. If you now how to work with sdl surfaces in lispbuilder, you may use the function with a surface instead of a image file; or you can call -\textsf{\textbf{(create-graphics~}}\textsf{path-to-image-file~nil}\textsf{\textbf{)}} +\textsf{\textbf{(create-graphics}~path-to-image-file~nil\textbf{)}} if the surface should not be freed after the call. The result must be the third argument given to define-feeb. @@ -476,11 +481,12 @@ The game loop is started by calling (feebs). + \section{Contests} I sugest that you see this chapter only after you have created at -least a basic brain feeb, wich is better than the (simple) provided -brain, and when you want to participate of a contest or a game with +least a basic brain feeb, which is better than the (simple) provided +brain, or if you want to participate of a contest or a game with your friends. @@ -495,18 +501,18 @@ what is really in the maze, but only the possible ways. To get the map, one can call \textsf{\textbf{(get-maze-map)}}. This -function will return \textsf{\textbf{nil}} if \textsf{\textbf{{*}may-get-maze-p{*}}} +function will return \textsf{\textbf{nil}} if parameter \textsf{\textbf{'may-get-maze-map-p}} is also \textsf{\textbf{nil}}. Otherwise, the map returned is an array, -so that calling \textsf{\textbf{(aref}}\textsf{~map~x~y}\textsf{\textbf{)}} +so that calling \textsf{\textbf{(aref}~map~x~y\textbf{)}} will get the contents in the euclidean position (x,y) . The contents of a cell could be one of these: \begin{lyxlist}{00.00.0000} \item [{\textsf{\textbf{:mushroom-place}}}] A mushroom patch, i.e. when -a mushroom is eaten it can come out here. +a mushroom is reincarnate, it could reincarnate here. \item [{\textsf{\textbf{:feeb-entry-place}}}] A feeb entry, i.e. if a carcass rots a feeb can appear here. -\item [{\textsf{\textbf{:rock}}}] A wall. Feebs cannot come in this place. +\item [{\textsf{\textbf{:rock}}}] A wall. Feebs cannot come to this place. \item [{\textsf{\textbf{nil}}}] An {}``empty'' place, i.e. neither of the previous. \end{lyxlist} @@ -514,19 +520,23 @@ \subsection{Timing} There are also some timing atributes that can be given to the game. -If the feeb takes too long to make a decision, there is more probability +The more time the feeb takes make a decision, greater is the probability of its command to be aborted. -To make this available, someone must set these: +To make this available, someone must set these parameters: \begin{lyxlist}{00.00.0000} -\item [{\textsf{\textbf{{*}slow-feeb-noop-switch{*}}}}] If is non-nil, -there is a possibility that the move of a feeb is aborted according -to its function time. Not applied to the human controlled feeb. -\item [{\textsf{\textbf{{*}slow-feeb-noop-factor{*}}}}] The probability -of the feeb to abort will be this factor times the amount of time -the feeb takes to have a decision, divided for the total time taken -by all the feebs in the current turn. +\item [{\textsf{\textbf{'slow-feeb-noop-switch}}}] If is non-nil, +there is a possibility that the move of a feeb is aborted according +to its function time. +\item [{\textsf{\textbf{'slow-feeb-noop-factor}}}] 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. +\item [{\textsf{\textbf{'reference-time}}}] Time taken by reference +if non-nil. +\item [{\textsf{\textbf{'points-for-slow-down}}}] Points earned when +a feeb's move is aborted due to slowness. \end{lyxlist} \subsection{Sense of location} @@ -537,30 +547,25 @@ These are the parameters: \begin{lyxlist}{00.00.0000} -\item [{\textsf{\textbf{{*}sense-location-p{*}}}}] Tells if the actual -position of the feeb can be determinated accessing \textsf{\textbf{x-position}} -and \textsf{\textbf{y-position}}. +\item [{\textsf{\textbf{'sense-location-p}}}] If nil, +\textsf{\textbf{x-position}} and \textsf{\textbf{y-position}} +will return nil when someone tries to invoke it. +Otherwise return the position. \end{lyxlist} \subsection{Changing the rules} To change the rules of the contest, they must be changed before the feebs are defined, because in a feeb definition it could use the values -of the variables to make a global strategy, and change the strategies -after this could not be fair. +of the variables to make a global strategy. -All the parameters that can be listed using \textsf{\textbf{(list-parameter-settings)}} -can be changed using setf. Also, they all have documentation about -themselves, so feel free to use \textsf{\textbf{(documentation~}}\textsf{parameter~'variable}\textsf{\textbf{)}} +All the parameters, values and documentation that can be listed using +\textsf{\textbf{(list-parameter-settings)}} can be changed using +\textsf{\textbf{(change-feeb-parm name value)}}, which is deactivated +during the game. Also, they all have documentation about themselves, so feel free to use +\textsf{\textbf{(documentation~}}\textsf{'parameter~'feeb-parm}\textsf{\textbf{)}} and see what each parameter does. Documentation is available to external -functions too. - -It is possible to change the layout of the map by calling \textsf{\textbf{(change-layout}}\textsf{~new-layout}\textsf{\textbf{)}}. -There are a few predefined mazes that are \textsf{\textbf{{*}maze-0{*}}} -throw \textsf{\textbf{{*}maze-5{*}}}. If you want to create a new -map, take the template (commented) inside the same file, or create -maybe a bigger template (of any size, because the values of \textsf{\textbf{{*}maze-x-size{*}}} -and \textsf{\textbf{{*}maze-y-size{*}}} will be changed accordingly). +functions as well. \section{Reference} Added: images.lisp ============================================================================== --- (empty file) +++ images.lisp Mon Dec 31 16:35:35 2007 @@ -0,0 +1,121 @@ +;;; -*- Common Lisp -*- + +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 The Feebs War. If not, see . +|# + + +(in-package :feebs) + +;;; This file is an extension of system.lisp which handles vision + + + +;;; -*- Vision Calculation -*- + +;;; Computes what the feeb is seeing + +(defun compute-vision (feeb) + (let ((proximity (feeb-proximity feeb)) + (vision (feeb-vision feeb)) + (vision-left (feeb-vision-left feeb)) + (vision-right (feeb-vision-right feeb)) + (facing (feeb-facing feeb)) + vision-dx + vision-dy + (x (feeb-x-position feeb)) + (y (feeb-y-position feeb))) + ;; First fill in proximity info. + (setf (my-square proximity) + (imagify feeb (aref *maze* x y) 'proximity) + (left-square proximity) + (imagify feeb + (aref *maze* (+ x (left-dx facing)) (+ y (left-dy facing))) + :proximity) + (right-square proximity) + (imagify feeb + (aref *maze* (+ x (right-dx facing)) (+ y (right-dy facing))) + :proximity) + (rear-square proximity) + (imagify feeb + (aref *maze* (+ x (behind-dx facing)) (+ y (behind-dy facing))) + :proximity)) + ;; The vision vector starts in the square the feeb is facing. + (setf x (+ x (forward-dx facing)) + y (+ y (forward-dy facing))) + ;; Figure out which direction to scan in. + (case (feeb-peeking feeb) + (:peek-left (setf facing (left-of facing))) + (:peek-right (setf facing (right-of facing)))) + (setf vision-dx (forward-dx facing) + vision-dy (forward-dy facing)) + ;; compute vision, vision-left and vision-right + (do* ((x x (+ x vision-dx)) + (y y (+ y vision-dy)) + (left-wall-x (+ x (left-dx facing)) (+ left-wall-x vision-dx)) + (left-wall-y (+ y (left-dy facing)) (+ left-wall-y vision-dy)) + (right-wall-x (+ x (right-dx facing)) (+ right-wall-x vision-dx)) + (right-wall-y (+ y (right-dy facing)) (+ right-wall-y vision-dy)) + (index 0 (1+ index))) + ((wallp (aref *maze* x y)) + (setf (aref vision index) :rock + (aref vision-left index) :unknown + (aref vision-right index) :unknown + (line-of-sight status) index)) + (setf (aref vision index) (imagify feeb (aref *maze* x y) :vision) + (aref vision-left index) + (imagify feeb + (aref *maze* left-wall-x left-wall-y) + :left-vision) + (aref vision-right index) + (imagify feeb + (aref *maze* right-wall-x right-wall-y) + :right-vision))))) + +(defstruct feeb-image + name facing peeking) + +(defstruct fireball-image + direction) + +;;; This transforms what the feeb is seeing; + +(defgeneric imagify (feeb thing type) + (:documentation "Defines how FEEB sees or feels THING. +TYPE could be :vision, :left-vision :right-vision or :proximity") + (:method (feeb thing type) + thing) + + (:method (feeb (thing feeb) + (type (or (eql :vision) (eql :proximity)))) + (make-feeb-image :name (feeb-name thing) + :facing (feeb-facing feeb) + :peeking (feeb-peeking feeb))) + + (:method (feeb (thing fireball) + (type (or (eql :vision) (eql :proximity)))) + (make-fireball-image :direction (fireball-direction thing))) + + (:method (feeb thing + (or (eql :left-vision) (eql :right-vision))) + nil) + + (:method (feeb (thing feeb) + (or (eql :left-vision) (eql :right-vision))) + (and (feeb-image-p thing) + (= facing (feeb-image-facing thing)) + (feeb-image-peeking thing)))) Modified: main.lisp ============================================================================== --- main.lisp (original) +++ main.lisp Mon Dec 31 16:35:35 2007 @@ -21,38 +21,67 @@ (in-package :feebs) -;;; Some functions +;; These are defined provisorily here +;; the definitive version is in rules.lisp -(defmacro define-parameter (name &optional value doc) - `(progn - (defvar ,name ,value - ,@(if doc '(doc))) - (export ,name) - (pushnew ',name *feeb-parameters*))) - -(defun list-parameter-settings () - (let ((settings nil)) - (dolist (parm *feeb-parameters*) - (push (cons parm (symbol-value parm)) settings)) - settings)) +(defun rot-carcass-p (time) + t) + +(defun reincarnate-feeb-p (feeb) + t) + +(defun finish-game-p () + ;; This is a little dangerous... + nil) + + + +;;; Parameters + +(let ((parameters (make-hash-table :test 'eq))) + + (defun def-feeb-parm (name value &optional doc) + (aif (gethash name parameters) + (progn + (warn "Change parameter ~a to ~a: ~ +parameter already existed with value ~a." name value (car it)) + (setf (gethash name parameters) (cons value (or doc (cdr it))))) + (setf (gethash name parameters) (cons value doc))) + name) + + (defun get-feeb-parm (name) + (gethash name parameters)) + + (defun change-parameter (name value) + (setf (car (gethash name parameters)) value)) + + (defmethod documentation (name (type (eql 'feeb-parameter))) + (cdr (gethash name parameters))) + + (defun list-parameter-settings () + (let (params) + (maphash #'(lambda (key value) + (push (list key (car value) (cdr value)) params)) + parameters) + params))) ;;; Characteristics of the maze: -(define-parameter *may-get-maze-map-p* t - "Tells if the function (get-maze-map) returns the map layout of nil - during the game.") +(def-feeb-parm 'may-get-maze-map-p t + "Tells if the function (get-maze-map) returns the map layout +instead of nil during the game.") ;;; Tests that behavior functions might use -(declare (inline feeb-image-p fireball-image-p)) +;; (declare (inline feeb-image-p fireball-image-p)) -(defun feeb-image-p (thing) - (typep thing 'feeb)) +;; (defun feeb-image-p (thing) +;; (typep thing 'feeb)) -(defun fireball-image-p (thing) - (typep thing 'fireball)) +;; (defun fireball-image-p (thing) +;; (typep thing 'fireball)) @@ -72,8 +101,8 @@ (if (/= (length string) y) (error "Not all the strings in ~a have the same size." layout))) (setf *layout* layout - *maze-y-size* y - *maze-x-size* x)) + *maze-y-size* (change-feeb-parm 'maze-y-size y) + *maze-x-size*(change-feeb-parm 'maze-x-size x))) (init-maze)) (defun get-maze-map () @@ -85,12 +114,13 @@ :feeb-entry-place -place where a feeb can reincarnate nil - nothing special Just remember that if *may-get-maze-map-p* is nil, -this function return an array of nils" - (let ((new-maze (make-array (list *maze-x-size* *maze-y-size*)))) - (dotimes (x *maze-x-size*) - (dotimes (y *maze-y-size*) - (setf (aref new-maze x y) (aref *fake-maze* x y)))) - new-maze))) +this function return nil." + (and (get-feeb-parm 'may-get-maze-map-p) + (let ((new-maze (make-array (list *maze-x-size* *maze-y-size*)))) + (dotimes (x *maze-x-size*) + (dotimes (y *maze-y-size*) + (setf (aref new-maze x y) (aref *fake-maze* x y)))) + new-maze))) (defun init-maze () (setf *maze* (make-array (list *maze-x-size* *maze-y-size*)) @@ -108,18 +138,15 @@ (aref *fake-maze* j i) nil) (case (schar str j) (#\X - (setf (aref *fake-maze* j i) - (and *may-get-maze-map-p* :rock) + (setf (aref *fake-maze* j i) :rock (aref *maze* j i) :rock)) (#\* - (setf (aref *fake-maze* j i) - (and *may-get-maze-map-p* :mushroom-place)) + (setf (aref *fake-maze* j i) :mushroom-place) (incf *number-of-mushroom-sites*) (push (make-pos j i) *mushroom-sites*)) (#\e (setf (aref *fake-maze* j i) - (and *may-get-maze-map-p* - :feeb-entry-place)) + :feeb-entry-place) (incf *number-of-entry-points*) (push (make-pos j i) *entry-points*)) (#\space nil) @@ -181,7 +208,6 @@ (let ((feeb (make-instance class :name name :brain brain - :direction (random 4) :graphics graphs :x-position x-pos :y-position y-pos))) @@ -202,15 +228,14 @@ ;;; The Game -(let ((mushrooms 0)) +(let ((mushrooms 1)) (defun number-of-mushrooms (n) - (setf *mushrooms-to-grow* n)) + (setf mushrooms n)) (defun play-one-turn () - (setf mushrooms 0) ; restart the count ;; This is defined by rules: - (start-turn) + (start-turn) ; possible call to number-of-mushrooms ;; Maybe grow up mushrooms: (let ((m-sites (sort *mushroom-sites* #'(lambda (x y) @@ -218,32 +243,35 @@ (zerop (random 2)))))) (dotimes (i mushrooms) (let ((site (pop m-sites))) - (create-mushroom (car site) (cdr site))))) + (unless (member #'fireball-p) + (create-mushroom (car site) (cdr site))))) ;; Maybe rot some carcasses - ;; FIXME: Ugly code code, and - (loop for carc in *carcasses* - with ncarcasses do - (if (rot-carcass-p (first carc)) - (progn - (delete-object :carcass (second carc) (third carc)) - (reincarnate-feeb (pop *dead-feebs*))) - (progn - (push carc ncarcasses) - (incf (first carc))))) + (dolist (carc (prog1 *carcasses* + (setf *carcasses* nil))) + (unless (rot-carcass (first carc) (second carc) (third carc)) + (progn + (incf (first carc)) + (push carc *carcasses*)))) ;; Move some fireballs: (dolist (fireball *fireballs-flying*) (move-object fireball (make-move-choice fireball))) (dolist (feeb *feebs*) - (unless (feeb-dead-p feeb) - ;; Starve the feeb: - (when (<= (decf (feeb-energy-reserve feeb)) 0) - (destroy-object feeb :starve)) - ;; Compute vision for the feeb: - (compute-vision feeb))) - (dolist (feeb *feebs*) - (unless (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)))) + (dolist (*playing-feeb* *feebs*) + (unless (feeb-dead-p *playing-feeb*) ;; Collect the feeb's move - (setf (feeb-peeking feeb) nil) - (move-object feeb (setf (feeb-last-move feeb) - (make-move-choice feeb)))))) -) \ No newline at end of file + (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)) Modified: mazes.lisp ============================================================================== --- mazes.lisp (original) +++ mazes.lisp Mon Dec 31 16:35:35 2007 @@ -316,7 +316,7 @@ #\X #\Space)))))) -;;; This one generates a almost ready-to-use map +;;; This one generates an almost ready-to-use map (defun generate-maze (x-size y-size &key (density 0.4) @@ -333,7 +333,8 @@ recomended to be between 0.25 and 0.45. The horizontal corridors will be between CORRIDOR-X-MIN and CORRIDOR-X-MAX around CORRIDOR-X-AVG, when -possible; similarly for vertical corridors." +possible; similarly for vertical corridors. +It returns two values, a layout like *maze-0* and its density." (if (or (< x-size 10) (< y-size 10)) (error "Too small - should be at least 10x10.")) ;; Certifying the values to be acceptable @@ -371,10 +372,11 @@ (y2 (if y1 (bound-random y1 corridor-y-min corridor-y-avg corridor-y-max)) (if y1 (bound-random y1 corridor-y-min - corridor-y-avg corridor-y-max)))) - ((or (>= (density map x-size y-size) density) + corridor-y-avg corridor-y-max))) + (real-dens )) + ((or (>= real density) (> i (* density x-size y-size))) ; quits after trying TOO MUCH - (translate map x-size y-size)) + (values (translate map x-size y-size) real-dens)) (if x1 (setf map (horiz-corridor map y x1 (bound x2 1 (- x-size 2))))) Modified: package.lisp ============================================================================== --- package.lisp (original) +++ package.lisp Mon Dec 31 16:35:35 2007 @@ -33,8 +33,7 @@ (defpackage :feebs (:use :common-lisp) ;; Export everything we want the players to get their hands on. - (:export *number-of-feebs* *game-length* - *number-of-auto-feebs* + (:export *game-length* ;; Strategic quantities *points-for-killing* *points-for-dying* @@ -48,8 +47,6 @@ *number-of-mushrooms* ;; Probabilities - *carcass-guaranteed-lifetime* - *carcass-rot-probability* *fireball-guaranteed-lifetime* *fireball-dissipation-probability* *fireball-reflection-probability* @@ -80,9 +77,12 @@ feeb-image-p feeb-image-name feeb-image-facing feeb-image-peeking fireball-image-p fireball-image-direction - - ;; Functions + + ;; Parameters + get-feeb-parm change-feeb-parm list-parameter-settings + + ;; Settings define-feeb delete-feeb feebs change-layout @@ -93,7 +93,7 @@ ;; Some layouts (can be find in mazes.lisp) *maze-1* *maze-2* *maze-3* *maze-4* *maze-5* - *maze-template* + make-template generate-maze ;; Graphics create-graphics @@ -119,6 +119,9 @@ ;;; Directions +(deftype direction () + `(integer 0 3)) + (defconstant north 0) (defconstant east 1) (defconstant south 2) @@ -178,10 +181,18 @@ "XXXXX XXXXXXXXXXXXX X" "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")) -(defparameter *maze-x-size* 32 - "Horizontal size of the maze") -(defparameter *maze-y-size* 32 - "Vertical size of the maze") + + +;;; Map size + +(def-feeb-parm 'maze-x-size 32 + "Horizontal size of the maze.") + +(def-feeb-parm 'maze-y-size 32 + "Vertical size of the maze.") + +(defvar *maze-x-size* 32) +(defvar *maze-y-size* 32) ;;; Quantities during the game @@ -197,5 +208,13 @@ (defvar *dead-feebs*) (defvar *carcasses*) -(defvar *continue*) +;;; Current feeb playing +(defvar *playing-feeb*) +(defmacro aif (test then &optional else) + `(let ((it ,test)) + (if it ,then ,else))) + +(defmacro awhen (test &rest body) + `(let ((it ,test)) + (when it , at body))) Added: rules.lisp ============================================================================== --- (empty file) +++ rules.lisp Mon Dec 31 16:35:35 2007 @@ -0,0 +1,119 @@ +;;; -*- Common Lisp -*- + +#| Copyright (c) 2007 Gustavo Henrique Milar? + + This file is part of The Feebs War. + + The Feebs War 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 of the License, or + (at your option) any later version. + + The Feebs War 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 The Feebs War. If not, see . +|# + + +(in-package :feebs) + + + +(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) + (defun start-round () + (setf turn-number 0) + (number-of-mushrooms + (random (1+ (get-feeb-parm 'number-of-mushrooms))))) + + (defun start-turn () + (incf turn-number)) + + (defun finish-game-p () + (>= (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.") + +(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.") + +(def-feeb-parm 'reference-time nil + "Time taken by reference if non-nil. See slow-feeb-noop-factor.") + +(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: + +(def-feeb-parm 'points-for-killing 5 + "How many points some feeb earn for killing someone.") + +(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.") + + +;;; Energies: + +(def-feeb-parm 'flame-energy 10 + "Amount of energy lost after throwing a flame.") + +(def-feeb-parm 'mushroom-energy 50 + "Amount of energy recovered when the feeb eats a mushroom.") + +(def-feeb-parm 'carcass-energy 30 + "Amount of energy recovered each turn that the feeb +eats a carcass.") + +(def-feeb-parm 'maximum-energy 100 + "The most energy a feeb can accumulate.") + +(def-feeb-parm 'starting-energy 50 + "Smallest amount of energy a feeb will start with.") + +;;; Carcasses: + +(def-feeb-parm 'carcass-guaranteed-lifetime 5 + "Number of +turns that a carcass will surely not rot. After these turns, it +can rot, depending on probabilities.") + +(def-feeb-parm 'carcass-rot-probability 1/3 + "Probability of the carcass to rot, after the apropriate time.") + + +;;; Fireballs: + +(def-feeb-parm 'fireball-dissipation-probability 1/5 + "Probability of the flame to dissipate each turn after the +apropriate time.") + +(def-feeb-parm 'fireball-reflection-probability 2/3 + "Probability of the flame to reflect when encountering a wall.") + +(deef-feeb-parm 'flame-no-recovery-time 2 + "Probability +of the feeb to recover the hability to throw a flame, after the apropriate +time.") + +(def-feeb-parm 'flame-recovery-probability 1/3 + "Probability of the feeb to recover the hability to throw a flame, +after the apropriate time.") Modified: system.lisp ============================================================================== --- system.lisp (original) +++ system.lisp Mon Dec 31 16:35:35 2007 @@ -27,24 +27,21 @@ ;;; This class is used by the system (defclass object () - ((direction :accessor object-direction) - (x-position :accessor object-x-position) - (y-position :accessor object-y-position))) + ((direction :accessor object-direction :initarg :direction) + (x-position :accessor object-x-position :initarg :x-position) + (y-position :accessor object-y-position :initarg :y-position))) (defclass feeb (object) (;; These are structures accessible from behavior functions. ;; These (whose :reader start with feeb-image) ;; are intended to be accessed by other feebs - (name :accessor feeb-name :reader name :initarg :name - :reader feeb-image-name) - (direction :reader facing :reader feeb-image-facing - :initform (random 4)) - (peeking :accessor feeb-peeking :reader peeking - :reader feeb-image-peeking) + (name :accessor feeb-name :reader name :initarg :name) + (direction :reader facing :initform (random 4)) + (peeking :accessor feeb-peeking :reader peeking) ;; These are intended to be accessed only by the feeb itself - (x-position :reader x-position :initform 0 :initarg :x-position) - (y-position :reader y-position :initform 0 :initarg :y-position) + (x-position :reader x-position :accessor feeb-x-position) + (y-position :reader y-position :accessor feeb-y-position) (line-of-sight :accessor feeb-line-of-sight :reader line-of-sight :initform 0) (energy-reserve :accessor feeb-energy-reserve :reader energy-reserve @@ -55,7 +52,7 @@ (last-move :accessor feeb-last-move :reader last-move :initform :dead) - ;; These are available for the system only + ;; These are available for the system (brain :accessor feeb-brain :initarg :brain) (graphics :accessor feeb-graphics :initarg :graphics) (time :accessor feeb-time :initform 0) @@ -64,7 +61,6 @@ (score :accessor feeb-score :initform 0) (kills :accessor feeb-kills :initform 0) (dead-p :accessor feeb-dead-p) - (playing-p :accessor feeb-playing-p) (turns-since-flamed :accessor feeb-turns-since-flamed :initform 0) (proximity :accessor feeb-proximity :initform (make-proximity)) (vision :accessor feeb-vision @@ -74,6 +70,21 @@ (vision-right :accessor feeb-vision-right :initform (make-array (list (max *maze-y-size* *maze-x-size*)))))) +(defclass fireball (object) + ((owner :accessor fireball-owner :initarg :owner) + (x-position :accessor fireball-x-position) + (y-position :accessor fireball-y-position) + (direction :accessor fireball-direction))) + +(declaim + (inline fireball-p feeb-p)) + +(defun fireball-p (x) + (typep x 'fireball)) + +(defun feeb-p (x) + (typep x 'feeb)) + ;;; These make sure that these accessors are just available ;;; for the feeb itself @@ -161,8 +172,13 @@ ;;; -*- General Rules -*- -(defgeneric start-turn (&key &allow-other-keys) - (:method () t)) +;; These will be redefined by rules + +(defun start-turn () + t) + +(defun start-round () + t) @@ -202,79 +218,13 @@ -;;; -*- Vision Calculation -*- - -;;; Computes what the feeb is seeing - -(defun compute-vision (feeb) - (let ((proximity (feeb-proximity feeb)) - (vision (feeb-vision feeb)) - (vision-left (feeb-vision-left feeb)) - (vision-right (feeb-vision-right feeb)) - (facing (feeb-facing feeb)) - vision-dx - vision-dy - (x (feeb-x-position feeb)) - (y (feeb-y-position feeb))) - ;; First fill in proximity info. - (setf (my-square proximity) - (aref *maze* x y) - (left-square proximity) - (aref *maze* (+ x (left-dx facing)) (+ y (left-dy facing))) - (right-square proximity) - (aref *maze* (+ x (right-dx facing)) (+ y (right-dy facing))) - (rear-square proximity) - (aref *maze* (+ x (behind-dx facing)) (+ y (behind-dy facing)))) - ;; The vision vector starts in the square the feeb is facing. - (setf x (+ x (forward-dx facing)) - y (+ y (forward-dy facing))) - ;; Figure out which direction to scan in. - (case (feeb-peeking feeb) - (:left (setf facing (left-of facing))) - (:right (setf facing (right-of facing)))) - (setf vision-dx (forward-dx facing) - vision-dy (forward-dy facing)) - ;; compute vision, vision-left and vision-right - (do* ((x x (+ x vision-dx)) - (y y (+ y vision-dy)) - (left-wall-x (+ x (left-dx facing)) (+ left-wall-x vision-dx)) - (left-wall-y (+ y (left-dy facing)) (+ left-wall-y vision-dy)) - (right-wall-x (+ x (right-dx facing)) (+ right-wall-x vision-dx)) - (right-wall-y (+ y (right-dy facing)) (+ right-wall-y vision-dy)) - (index 0 (1+ index))) - ((wallp (aref *maze* x y)) - (setf (aref vision index) (aref *maze* x y) - (aref vision-left index) :unknown - (aref vision-right index) :unknown - (line-of-sight status) index)) - (setf (aref vision index) (aref *maze* x y) - (aref vision-left index) - (side-imagify (aref *maze* left-wall-x left-wall-y) - (right-of facing)) - (aref vision-right index) - (side-imagify (aref *maze* right-wall-x right-wall-y) - (left-of facing)))))) - -;;; Compute the info to be put into the vision-left and vision-right vectors. -;;; A peeking feeb must be facing in the specified direction in order to count. - -(defun side-imagify (stuff facing) - (if (wallp stuff) - stuff - (loop for thing in stuff - and elt = (and (feeb-image-p thing) - (= facing (feeb-image-facing thing)) - (feeb-image-peeking thing)) - if elt - return it))) - - - ;;; -*- Movement -*- ;;; Lets the feeb make a choice -(defgeneric make-move-choice (object &key &allow-other-keys) +(defgeneric make-move-choice (object) + (:documentation "Lets object make its move choice.") + (:method ((feeb feeb)) (funcall (feeb-brain feeb) (feeb-status feeb) @@ -286,6 +236,9 @@ ;;; 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 (eql :turn-right))) (setf (object-direction object) (right-of (object-direction object))) @@ -316,7 +269,7 @@ ;;; Feeb moves (:method ((feeb feeb) (move (eql :move-forward))) - (let ((thing (find-if #'fireball-image-p stuff))) + (let ((thing (find-if #'fireball-p stuff))) (when thing (destroy-object feeb thing) (return-from make-move t))) (call-next-method)) @@ -325,9 +278,9 @@ (let ((x (feeb-x-position feeb)) (y (feeb-y-position feeb)) (fireball - (make-fireball-image (feeb-facing feeb) - feeb x y (forward-dx facing) - (forward-dy facing)))) + (make-instace 'fireball (feeb-facing feeb) + feeb x y (forward-dx facing) + (forward-dy facing)))) (push fireball *fireballs-flying*) t)) @@ -344,17 +297,10 @@ (when (member :carcass (aref *maze* x y)) t))) - (:method ((feeb feeb) (move (eql :peek-left))) + (: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 (peeking feeb) move))) - t) + (setf (feeb-peeking feeb) move))) - (:method make-move ((feeb feeb) (move (eql :peek-right))) - (multiple-value-bind (x y stuff) - (get-forward-pos feeb) - (unless (wallp stuff) - (setf (peeking feeb) move))) - t) ) ; end of make-move generic function