diff options
author | Grant Shangreaux <grant@unabridgedsoftware.com> | 2022-01-22 19:45:44 -0600 |
---|---|---|
committer | Grant Shangreaux <grant@unabridgedsoftware.com> | 2022-01-22 19:45:44 -0600 |
commit | de237aee0efcf74a91f5faa4da44565a0b5e7f92 (patch) | |
tree | 5d1f3b01ffe507f6bf02761404b180430c4f2a89 | |
parent | 516d89a2a6d05a0ee1e2787c037c53f26f93f216 (diff) |
Clean: whitespace and lines between tangled output
-rw-r--r-- | mafia.org | 95 |
1 files changed, 57 insertions, 38 deletions
@@ -14,12 +14,19 @@ the following source block represents the whole program from a high level: #+name: mafia #+begin_src emacs-lisp :noweb yes :tangle yes :results silent ;;; mafia.el --- Emacs Mafia game simulation -*- lexical-binding:t -*- - + <<dependencies>> + <<mafia-class>> + <<actor-classes>> + <<initialization-helpers>> + <<top-level-mafia-methods>> + + <<actor-behavior-methods>> + <<game-loop>> #+end_src @@ -43,10 +50,9 @@ CLOS, the powerful object oriented system from CL. #+begin_src emacs-lisp :results silent (require 'cl-lib) (require 'eieio) - #+end_src -*** game state +** Game State a game consists of N >= 4 *actors*, one of which is the *killer*. each game will have a number of *rounds*, at the end of each an actor will /die/. each round @@ -62,7 +68,7 @@ win. If there's only 2 players left, the killer wins. using EIEIO, lets define a class ~mafia~ to represent the whole game state. #+name: mafia-class -#+begin_src emacs-lisp +#+begin_src emacs-lisp :results silent (defclass mafia () ; No superclasses ((actors :initarg :actors :initform (mafia-initialize-actors 4) @@ -75,7 +81,6 @@ using EIEIO, lets define a class ~mafia~ to represent the whole game state. :type number :documentation "The current 'slice-of-time' the game is in.")) "A class representing the game state of Mafia, defaults to 4 players.") - #+end_src Notice the ~:initform~ slot options (instance variables are called slots in @@ -94,17 +99,16 @@ use inheritance here to set apart the killer with its own ~:initform~. ((id :initarg :id :type number)) "Base class for mafia actors.") - + (defclass mafia-killer (mafia-actor) () "Actor subclass to represent the killer.") - + (defclass mafia-innocent (mafia-actor) - ((alive :initform t - :documentation "Either t or nil (for dead).") + ((status :initform 'alive + :documentation "'alive, 'dying, or 'dead") (death-countdown :initform (1+ (random 10)) - :documentation "The number of ticks until death."))) - + :documentation "The number of ticks to go from dying to dead"))) #+end_src Then the function ~mafia-initial-actors~ will handle initializing N actors @@ -118,7 +122,6 @@ into a list which is the ~:initform~ of the ~mafia~ game instance. (let ((killer (1+ (random players)))) (cl-loop for i from 1 to players collect (if (eql i killer) (mafia-killer :id i) (mafia-innocent :id i))))) - #+end_src *** visualizing initial game state @@ -128,62 +131,78 @@ Lets initialize a game with 6 actors and inspect it to see what to expect. #+begin_src emacs-lisp (let* ((mafia-game (mafia :actors (mafia-initialize-actors 6))) (actors (slot-value mafia-game 'actors))) - (cons '(class id alive?) ;; add the header row + (cons '(class id status) ;; add the header row (mapcar (lambda (a) (let ((class (eieio-object-class a))) - (with-slots (id alive) a - (list class id (when (eql class 'mafia-innocent) alive))))) + (with-slots (id status) a + (list class id (when (eql class 'mafia-innocent) status))))) actors))) #+end_src #+RESULTS: -| class | id | alive? | -| mafia-innocent | 1 | t | -| mafia-killer | 2 | nil | -| mafia-innocent | 3 | t | -| mafia-innocent | 4 | t | -| mafia-innocent | 5 | t | -| mafia-innocent | 6 | t | +| class | id | status | +| mafia-innocent | 1 | alive | +| mafia-innocent | 2 | alive | +| mafia-innocent | 3 | alive | +| mafia-killer | 4 | nil | +| mafia-innocent | 5 | alive | +| mafia-innocent | 6 | alive | -** Game loop +** Game Loop The game loop will advance by a single tick where each actor /observes/ the others. -So... we need to define a game loop function, and a method for the actors to +So... we need to define a game loop function, and a method for the actors to #+name: game-loop #+begin_src emacs-lisp :results silent (defun mafia-play (players) "Entry point to start a game of Mafia." (interactive "nnumber of players: ") (let* ((game (mafia :actors (mafia-initialize-actors players)))) - (while (> (length (mafia-innocents-alive game)) 1) + (while (> (length (mafia-living-innocents game)) 1) (mafia-update game)) (message "Game over!"))) - #+end_src #+name: top-level-mafia-methods #+begin_src emacs-lisp :results silent - (cl-defmethod mafia-innocents-alive ((obj mafia)) + (cl-defmethod mafia-living-innocents ((obj mafia)) "Returns the living innocents from a mafia game." - (cl-remove-if-not #'mafia-innocent-alive-p (mafia-innocents obj))) - + (cl-remove-if-not #'mafia-alive-p (mafia-innocents obj))) + + (cl-defmethod mafia-update ((obj mafia)) + "Performs the update logic for the mafia game instane." + (mafia-innocent-die (cl-first (mafia-innocents-alive obj)))) + (cl-defmethod mafia-innocents ((obj mafia)) "Returns the list of innocents from a mafia game." (cl-remove-if #'mafia-killer-p (slot-value obj 'actors))) - - (cl-defmethod mafia-innocent-alive-p ((obj mafia-innocent)) +#+end_src + +** Actor Behavior +:PROPERTIES: +:header-args: :noweb-ref actor-behavior-methods :noweb-sep "\n\n" +:END: + +This may be somewhat redundant, because the slot is meant to hold a boolean +value anyway. However, if we added other "types" of actors, perhaps we'd +specialize this method for them. + +#+begin_src emacs-lisp + (cl-defmethod mafia-alive-p ((obj mafia-innocent)) "Returns `t' if the actor is alive, otherwise `nil'" - (slot-value obj 'alive)) - + (eql (slot-value obj 'status) 'alive)) +#+end_src + +Then we want a method to make an actor die. For now, we'll just print some +message and update its state so that the ~alive~ slot is ~nil~. According +to the game rules, we should start some "timer" so that it will count down +its ~death-countown~, but I'm not quite prepared for that at this moment. + +#+begin_src emacs-lisp (cl-defmethod mafia-innocent-die ((obj mafia-innocent)) (with-slots (id alive) obj (print (format "Innocent %s has been killed!" id)) (setf alive nil))) - - (cl-defmethod mafia-update ((obj mafia)) - "Performs the update logic for the mafia game instane." - (mafia-innocent-die (cl-first (mafia-innocents-alive obj)))) - #+end_src * english villiage simulator |