用 clips 模拟生态第0.3步:添加位置
续 前文,添加食物和个体的位置,并需要个体移动到食物附近进食。为简化起见,暂用一维位置即x在【0到1440】。
世界
和时间流逝
未修改,其他部分如下:
(deftemplate 某种
(slot 长辈)
(slot 编号)
(slot 能量)
(slot 经历时间)
(slot x))
(deftemplate 食物
(slot 编号)
(slot x))
(defrule 开始
=>
(println "开天辟地")
; 纪录编号,确保不重复;否则新个体会取代老个体
(assert (世界 (数量 1) (时间 0)))
(bind ?宽 1440)
(loop-for-count (?序号 1 10)
(assert (食物 (编号 ?序号) (x (random 0 ?宽)))))
(assert (某种 (长辈 0) (编号 0) (能量 0) (经历时间 0) (x (random 0 ?宽)))))
(defrule 觅食
(declare (salience 5))
(世界 (时间 ?时间))
?个体 <- (某种 (编号 ?个体编号) (能量 ?能量) (x ?个体位置) (经历时间 ?经历时间&:(< ?经历时间 ?时间)))
?食物 <- (食物 (编号 ?食物编号) (x ?食物位置))
=>
(modify ?个体 (经历时间 (+ 1 ?经历时间)))
(bind ?速度 1)
(bind ?距离 (- ?个体位置 ?食物位置))
(if (< (abs ?距离) 2)
then
(retract ?食物)
(println ?个体编号 "在" ?食物位置 "吃了" ?食物编号)
(modify ?个体 (能量 (+ ?能量 1)) )
else
; 靠近食物
(if (> ?距离 0)
then
(modify ?个体 (x (- ?个体位置 ?速度)))
else
(modify ?个体 (x (+ ?个体位置 ?速度)))
)
)
)
(defrule 繁衍
(declare (salience 10))
?世界 <- (世界 (数量 ?个体量) (时间 ?时间))
?长辈 <- (某种 (编号 ?编号) (能量 ?能量&:(> ?能量 0)) (x ?长辈位置))
=>
(assert (某种 (长辈 ?编号) (编号 ?个体量) (能量 0) (经历时间 ?时间) (x (+ ?长辈位置 1))))
(modify ?世界 (数量 (+ 1 ?个体量)))
(modify ?长辈 (能量 0))
)
为追踪繁衍和觅食,加了些辅助属性如长辈
。输出像这样:
开天辟地
0在1273吃了10
0在1025吃了9
1在279吃了8
2在572吃了7
4在887吃了6
1在362吃了5
5在826吃了4
7在1317吃了3
1在250吃了2
8在998吃了1
之前的fact消失的确是因为编号重复,但具体是因为改了老个体撞了新个体,还是创建新个体撞了老个体,未深究。
代码嵌套if-else后,仍会难读。感觉按规则组织代码可能减少了循环的使用,但业务逻辑部分稍冗长些,尤其还有lisp风格的括号语法,以及每次重复声明的属性(slot)名。
之后试试 deffunction 清晰化一下代码。