我正在用 CL 编写一款地下城探索游戏,但我在处理案例表单时遇到了问题。
有两件事:
Duplicate keyform QUOTE in CASE statement
(make-instance 'cl-rogue:tile tile-type 'wall)
应打印为“#”,但无论我使用哪种图块类型,该对象都会打印为“”。代码:
(in-package :cl-user)
(defpackage :cl-rogue
(:use :common-lisp)
(:export
:*rows*
:*cols*
:*levels*
:tile
:tile-type
:tile-contents
:tile-hidden
:tile-locked
:tile-closed
:main))
(in-package :cl-rogue)
(defparameter *cols* 80)
(defparameter *rows* 24)
(defparameter *levels* 26)
班级:
(defclass tile ()
((tile-type
:initarg :tile-type
:accessor tile-type
:initform 'floor
:documentation "Type of tile")
(tile-contents
:initarg :tile-contents
:accessor tile-contents
:initform '()
:documentation "Any items the tile holds")
(tile-hidden
:initarg :tile-hidden
:accessor tile-hidden
:initform nil
:documentation "Whether the tile is hidden or shown")
(tile-locked
:initarg :tile-locked
:accessor tile-locked
:initform nil
:documentation "Whether the tile is locked")
(tile-closed
:initarg :tile-closed
:accessor tile-closed
:initform nil
:documentation "Whether the tile is open or closed")))
打印方式:
(defmethod print-object ((object tile) stream)
(with-slots (tile-type tile-contents tile-hidden tile-locked tile-closed) object
(if tile-hidden
(format stream " ")
(let ((an-item (car tile-contents)))
(if an-item
(format stream "~a" an-item)
(format stream (case tile-type
('wall "#")
('upstair "<")
('downstair ">")
('door (if tile-closed "+" "\\"))
(otherwise " "))))))))
您不需要引用
CASE
中的符号。
实际上你不应该在
CASE
子句中引用符号。
看:这是错误的
CL-USER 31 > (case 'quote
('not-quote 'oops-really-quote)
('quote 'it-is-a-quote))
OOPS-REALLY-QUOTE
上面是使用
'not-quote
而不是正确的未引用的 not-quote
的意外结果。
下列说法正确的是:
CL-USER 32 > (case 'quote
(not-quote 'oops-really-quote)
(quote 'it-is-a-quote))
IT-IS-A-QUOTE
Common Lisp 中 CASE 的语法
case keyform
{normal-clause}*
[otherwise-clause]
=> result*
normal-clause::= (keys form*)
otherwise-clause::= ({otherwise | t} form*)
clause::= normal-clause | otherwise-clause
keys ::= object | (object*)
如您所见,键要么是单个对象,要么是对象列表。不评估对象。
不评估 CASE 子句中的符号。
(case tile-type
(wall ...)
(door ...))
WALL
和 DOOR
纯粹是符号,不作为变量进行计算。
Lisp 阅读器将
'foo
读作 (quote foo)
。
你写道:
(case tile-type
('wall ...)
('door ...))
这相当于:
(case tile-type
((quote wall) ...)
((quote door) ...))
但是你不能引用
CASE
中的符号。您必须提供符号作为文字常量。
如果你写:
(let ((bar 'foo)
(baz 'foo))
(case bar
(baz :we-have-a-foo-through-baz)
(foo :we-really-have-a-foo)))
这将返回
:WE-REALLY-HAVE-A-FOO
。因为 CASE
使用常量数据,而不是变量。
CASE
接受项目列表。由于您在 more than 子句中使用 QUOTE
作为符号,因此编译器会显示警告。
正如我所说,无法报价,因为这些物品没有经过评估。
至于
CASE
接受子句中的项目列表,它看起来像这样:
(case tile-type
((door wall) ...)
((floor window painting) ...))
对于
WALL
符号,您在创建对象时需要确保它位于正确的包中。
最好使用关键字符号,例如
:wall
。这样你就不需要导出它,并且不会混淆该符号位于哪个包中。
关于代码的格式: 您有一个项目符号列表,紧随其后的是代码部分。这不会按照您的预期呈现。我在代码之前添加了文本“代码:”。然后渲染就按预期工作了。