summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrant Shangreaux <grant@unabridgedsoftware.com>2022-01-22 19:45:44 -0600
committerGrant Shangreaux <grant@unabridgedsoftware.com>2022-01-22 19:45:44 -0600
commitde237aee0efcf74a91f5faa4da44565a0b5e7f92 (patch)
tree5d1f3b01ffe507f6bf02761404b180430c4f2a89
parent516d89a2a6d05a0ee1e2787c037c53f26f93f216 (diff)
Clean: whitespace and lines between tangled output
-rw-r--r--mafia.org95
1 files changed, 57 insertions, 38 deletions
diff --git a/mafia.org b/mafia.org
index 3d68c52..510c140 100644
--- a/mafia.org
+++ b/mafia.org
@@ -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