Skip to content

Commit

Permalink
Land of Lisp progress: Finished the Chapter 9! Orc Game finished!
Browse files Browse the repository at this point in the history
Summary:
* arrays are similar to lists, but allow you to access an item at a specific
offset more efficiently
* hash tables are similar to alists, but let you look up the value associated
with a key more efficiently
* using arrays and hash tables in the appropriate places will usually make
your code much faster
* the only true way to tell if changing a data structure or algorithm makes
your program faster it to time your code with the time command (on CL)
* Common Lisp has generic functions that can be used against multiple
datatypes. The most useful of these are sequence functions that can
transparently handle lists, arrays and strings.
* You can create objects with properties in list using the defstruct command

The most valuable insight here was about the DEFMETHOD to define generic
procedures tagging the datatype on argument. So we can define a function
multiple times for each datatype doing a special procedure. This is really
great. We can use as well for structs and classes (I think the book covers
that later, but I got something from the google lisp koans too).

https://www.github.com/DestructHub/lisp-koans-answers
  • Loading branch information
ryukinix committed Feb 27, 2017
1 parent a187283 commit 55971d4
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 38 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
A personal repository for annotation about learning lisp patterns.
The actual content are answers and code covering the book [Land of Lisp](http://www.landoflisp.com) and the insights at the MIT 6.001 Course about Structures and Interpretations of Computer Programs.

# Land of Lisp book (reading) [178/482]
![progress](http://progressed.io/bar/37)
# Land of Lisp book (reading) [189/482]
![progress](http://progressed.io/bar/39)

- [x] Chapter 1 (intro)
- [x] Chapter 2 (guess my numbers)
Expand All @@ -14,7 +14,7 @@ The actual content are answers and code covering the book [Land of Lisp](http://
- [x] Chapter 6.5 (lambda chapter)
- [x] Chapter 7 (go beyond basic lists)
- [x] Chapter 8 (grand theft wumpus)
- [ ] Chapter 9 (advanced datatypes and generic programming)
- [x] Chapter 9 (advanced datatypes and generic programming)
- [ ] Chapter 10
- [ ] Chapter 11
- [ ] Chapter 12
Expand Down
193 changes: 158 additions & 35 deletions land-of-lisp/cap9-orc-battle-game.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ in a fight to the death. With your superior wits and your repertoire
of sword-fighting maneuvers, you must carefully make strategies in your battle with orcs,
hydras, and other nasty enemies.
Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
c
Using DEFMETHOD and DEFSTRUCT, let's dispatch some whoop ass on these vermin!
|#



;; global variables for player status

(defparameter *player-health* nil)
Expand All @@ -29,45 +28,126 @@ Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
;; we'll also define a list of functions for building monsters that
;; we'll store in the variable *monster-builders* (AQUI É MONSTRO, PORRA)


(defparameter *monsters* nil)
(defparameter *monster-builders* nil)
(defparameter *monster-num* 12) ;; high => more difficult
(defparameter *monster-num* 6) ;; high => more difficult

;; undefined functions yet:
;; +MONSTER-HIT
;; +MONSTERS-DEAD
;; +PICK-MONSTER
;; +RANDVAL
;; I need define the structure of MONSTER as well yet.
(defun randval (n)
(1+ (random (max 1 n))))

(defun init-player()
"Set the initial tributes of our knight"
(setf *player-health* 30)
(setf *player-agility* 30)
(setf *player-strength* 30))
;; STRUCTS

;; THE MONSTERS

;; generic monster strict
(defstruct monster (health (randval 10)))

;; THE WICKED ORC
(defstruct (orc (:include monster))
(club-level (randval 8)))
(push #'make-orc *monster-builders*)

(defmethod monster-show ((m orc))
(princ "A wicked orc with a level ")
(princ (orc-club-level m))
(princ " club"))

(defmethod monster-attack ((m orc))
(let ((x (randval (orc-club-level m))))
(princ "An orc swings his club at you knocks off ")
(princ x)
(princ " of your health points. ")
(decf *player-health* x)))


;; THE MALICIOUS HYDRA
(defstruct (hydra (:include monster)))
(push #'make-hydra *monster-builders*)

(defmethod monster-show ((m hydra))
(princ "A malicious hydra with ")
(princ (monster-health m))
(princ " heads. "))

(defmethod monster-hit ((m hydra) x)
(decf (monster-health m) x)
(if (monster-dead m)
(princ "The corpse of the fully decapitated hydra falls to the floor! ")
(progn (princ "You lop off ")
(princ x)
(princ " of hydra's heads! "))))

(defmethod monster-attack ((m hydra))
(let ((x (randval (ash (monster-health m) -1))))
(princ "A hydra attacks you with ")
(princ x)
(princ " of its heads! It also grows back one more head! ")
(incf (monster-health m))
(decf *player-health* x)))

(defstruct (slime-mold (:include monster))
(slimeness (randval 5)))
(push #'make-slime-mold *monster-builders*)


(defmethod monster-attack ((m slime-mold))
(princ "A slime mold of slimness of ")
(princ (slime-mold-slimeness m))
(princ " attacks "))

(defmethod monster-show ((m slime-mold))
(let ((x (randval (slime-mold-slimeness m))))
(princ "A slime mold wraps around your legs and decreases your agility by ")
(princ x)
(princ "! ")
(decf *player-agility* x)
(when (zerop (random 2))
(princ "It also squirts in your face, taking away a health point! ")
(decf *player-health*))))

(defstruct (brigand (:include monster)))
(push #'make-brigand *monster-builders*)

(defmethod monster-attack ((m brigand))
(let ((x (max *player-health*
*player-agility*
*player-strength*)))
(cond ((= x *player-health*)
(princ "A brigand hits you with his slingshot taking off 2 health points! ")
(decf *player-health* 2))
((= x *player-agility*)
(princ "A brigand catches your leg with his whip taking off 2 agility points! ")
(decf *player-agility* 2))
((= x *player-strength*)
(princ "A brigand cuts your arm with his whip, taking off 2 strength points! ")
(decf *player-strength* 2)))))

(defun player-dead ()
"Check if the player is alive"
(<= *player-health* 0))

(defun monster-dead (m)
(<= (monster-health m) 0))

(defun monsters-dead ()
(every #'monster-dead *monsters*))

(defun show-player ()
"If the player is alive, show in REPL your info at each action"
(fresh-line)
(format t "You are a valiant knight with a health of ~a,
an agility of ~a and a strength of ~a"
*player-health*
*player-agility*
*player-health*))
(defmethod monster-hit (m x)
(decf (monster-health m) x)
(if (monster-dead m)
(progn (princ "You killed the ")
(princ (type-of m))
(princ "! "))
(progn (princ "You hit the ")
(princ (type-of m))
(princ ", knocking off")
(princ x)
(princ " health points! "))))


(defun randval (n)
(1+ (random (max 1 n))))

(defmethod monster-show (m)
(princ "A fierce ")
(princ (type-of m)))

(defmethod monster-attack (m))

;; helper functions for player attack
(defun random-monster ()
Expand All @@ -79,7 +159,8 @@ Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
(defun pick-monster ()
(fresh-line)
(princ "Monster #:")
(let ((x read))
(fresh-line)
(let ((x (read)))
(if (not (and (integerp x)
(>= x 1)
(<= x *monster-num*)))
Expand All @@ -91,19 +172,56 @@ Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
(pick-monster))
m)))))

;; monster management functions
(defun init-monsters ()
(setf *monsters*
(map 'vector
(lambda (x)
(funcall (nth (random (length *monsters-builders*)))
*monster-builders*))
(declare (ignore x))
(funcall (nth (random (length *monster-builders*))
*monster-builders*)))
(make-array *monster-num*))))

(defun show-monsters ()
(fresh-line)
(princ "Your foes:")
(let ((x 0))
(map 'list
(lambda (m)
(fresh-line)
(princ " ")
(princ (incf x))
(princ ". ")
(if (monster-dead m)
(princ "**dead**")
(progn (princ "(Health=")
(princ (monster-health m))
(princ ") ")
(monster-show m))))
*monsters*)))

(defun init-player()
"Set the initial tributes of our knight"
(setf *player-health* 30)
(setf *player-agility* 30)
(setf *player-strength* 30))

(defun player-dead ()
"Check if the player is alive"
(<= *player-health* 0))

(defun show-player ()
"If the player is alive, show in REPL your info at each action"
(fresh-line)
(format t "You are a valiant knight with a health of ~a, an agility of ~a and a strength of ~a"
*player-health*
*player-agility*
*player-health*))

(defun player-attack ()
"The player-attack function lets us manage a player's attack"
(fresh-line)
(princ "Attack style: [s]tab [d]ouble swing [r]oundhouse: ")
(fresh-line)
(case (read)
(s (monster-hit (pick-monster)
(+ 2 (randval (ash *player-strength* -1)))))
Expand All @@ -115,7 +233,7 @@ Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
(monster-hit (pick-monster) x))))
(otherwise (dotimes (x (1+ (randval (truncate (/ *player-strength* 3)))))
(unless (monsters-dead)
(monster-hit (random-monster 1)))))))
(monster-hit (random-monster) 1))))))



Expand All @@ -124,6 +242,7 @@ Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
and player attacks."
(unless (or (player-dead)
(monsters-dead))
(fresh-line)
(show-player)
(dotimes (k (1+ (truncate (/ (max 0 *player-agility*) 15))))
(unless (monsters-dead)
Expand All @@ -133,7 +252,7 @@ Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
(map 'list
(lambda (m)
(or (monster-dead m)
(moster-attack m)))
(monster-attack m)))
*monsters*)
(game-loop)))

Expand All @@ -148,3 +267,7 @@ Using DEFMETHOD and DEFDESTRUCT, let's dispatch some whoop ass on these vermin!
(when (monsters-dead)
(princ "Congratulations! You have vanquished all of your foes.")))



(orc-battle)
;; just execute this game via terminal as: sbcl --script this-file-name.lisp

0 comments on commit 55971d4

Please sign in to comment.