-
Notifications
You must be signed in to change notification settings - Fork 0
/
evolution.el
149 lines (126 loc) · 4.83 KB
/
evolution.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
;; (defclass record () ; No superclasses
;; ((name :initarg :name
;; :initform ""
;; :type string
;; :custom string
;; :documentation "The name of a person.")
;; (birthday :initarg :birthday
;; :initform "Jan 1, 1970"
;; :custom string
;; :type string
;; :documentation "The person's birthday.")
;; (phone :initarg :phone
;; :initform ""
;; :documentation "Phone number."))
;; "A single record for tracking people I know.")
;; (setq rec (record "rand" :name "Random Sample" :birthday "01/01/2000" :phone "555-5555"))
;; (record-name rec)
;; (oref rec :birthday)
;; (record-p rec)
(defun fresh-line ()
(princ "\n"))
;; (fresh-line)
(defvar *width* 100)
(defvar *height* 30)
(defvar *jungle* '(45 10 10 10))
(defvar *plant-energy* 80)
(defvar *plants* (make-hash-table :test #'equal))
(defun random-plant (left top width height)
(let ((pos (cons (+ left (random width)) (+ top (random height)))))
(setf (gethash pos *plants*) t)))
(defun add-plants ()
(apply #'random-plant *jungle*)
(random-plant 0 0 *width* *height*))
(defstruct animal x y energy dir genes)
(defvar *animals*
(list (make-animal :x (ash *width* -1)
:y (ash *height* -1)
:energy 1000
:dir 0
:genes (loop repeat 8
collecting (1+ (random 10))))))
(defun move (animal)
(let ((dir (animal-dir animal))
(x (animal-x animal))
(y (animal-y animal)))
(setf (animal-x animal) (mod (+ x
(cond ((and (>= dir 2) (< dir 5)) 1)
((or (= dir 1) (= dir 5)) 0)
(t -1))
*width*)
*width*))
(setf (animal-y animal) (mod (+ y
(cond ((and (>= dir 0) (< dir 3)) -1)
((and (>= dir 4) (< dir 7)) 1)
(t 0))
*height*)
*height*))
(decf (animal-energy animal))))
(defun turn (animal)
(let ((x (random (apply #'+ (animal-genes animal)))))
(labels ((angle (genes x)
(let ((xnu (- x (car genes))))
(if (< xnu 0)
0
(1+ (angle (cdr genes) xnu))))))
(setf (animal-dir animal)
(mod (+ (animal-dir animal) (angle (animal-genes animal) x)) 8)))))
(defun eat (animal)
(let ((pos (cons (animal-x animal) (animal-y animal))))
(when (gethash pos *plants*)
(incf (animal-energy animal) *plant-energy*)
(remhash pos *plants*))))
(defvar *reproduction-energy* 200)
(defun reproduce (animal)
(let ((e (animal-energy animal)))
(when (>= e *reproduction-energy*)
(setf (animal-energy animal) (ash e -1))
(let ((animal-nu animal)
(genes (copy-list (animal-genes animal)))
(mutation (random 8)))
(setf (nth mutation genes) (max 1 (+ (nth mutation genes) (random 3) -1)))
(setf (animal-genes animal-nu) genes)
(push animal-nu *animals*)))))
(defun update-world ()
(setf *animals* (remove-if (lambda (animal)
(<= (animal-energy animal) 0))
*animals*))
(mapc (lambda (animal)
(turn animal)
(move animal)
(eat animal)
(reproduce animal))
*animals*)
(add-plants))
(defun draw-world ()
(loop for y
below *height*
do (progn (fresh-line)
(princ "|")
(loop for x
below *width*
do (princ (cond ((some (lambda (animal)
(and (= (animal-x animal) x)
(= (animal-y animal) y)))
*animals*)
(char-to-string ?M)) ;; ?\M
((gethash (cons x y) *plants*) (char-to-string ?\*))
(t (char-to-string ?\ )))))
(princ "|"))))
(defun evolution ()
(draw-world)
(fresh-line)
(let ((str (read-from-minibuffer "days: ")))
(cond ((equal str "quit") ())
(t (let ((x (string-to-int str)))
(if x
(loop for i
below x
do (update-world)
if (zerop (mod i 1000))
do (princ ?\.))
(update-world))
(evolution))))))
;; (string-to-int "2a")
;; (princ (char-to-string ?M))
(evolution)