将数字插入已具有数字的位置以创建列表

时间:2016-08-11 17:02:53

标签: list insert numbers lisp common-lisp

我有这个用于4-in-a-row游戏的lisp代码

(defun board ()
'((
 (NIL NIL NIL NIL)
 (NIL NIL NIL NIL)
 (NIL NIL NIL NIL)
 (NIL NIL NIL NIL)
)
(NIL NIL)))

每个NIL代表一列(忘记最后两个NIL)。在每一列中,我可以放置游戏棋子,可以是1(代表白色)或10(代表黑色)。以下代码用于将游戏块放在玩家想要的位置。

(defun get-level (level board)
 (cond ((= level 1) (first board))
  ((= level 2) (second board))
  ((= level 3) (third board))
  ((= level 4) (fourth board))
  ))

(defun get-column (column board)
 (cond ((= column 1) (first board))
  ((= column 2) (second board))
  ((= column 3) (third board))
  ((= column 4) (fourth board))
  ))

(defun get-line (line board)
 (cond ((= line 1) (first board))
  ((= line 2) (second board))
  ((= line 3) (third board))
  ((= line 4) (fourth board))
  ))

(defun get-elem (x y z board)
   (get-column y (get-line x (get-level z board))))

(defun value1 (x y z board)
   (insertValue x y z board '1))

(defun value10 (x y z board)
   (insertValue x y z board '10))

(defun insertValue (x y z board value)
 (cond ((= z 1)(list (act-levelValue x y (first board) value) (second board) (third board) (fourth board)))
 ((= z 2)(list (first board) (act-levelValue x y (second board) value) (third board) (fourth board)))
 ((= z 3)(list (first board) (second board) (act-nivelValor x y (third board) value) (fourth board)))
 ((= z 4)(list (first board) (second board) (third board) (act-levelValue x y (fourth board) value)))))

(defun act-levelValue (x y level value)
 (cond ((= x 1)(list (act-lineValue y (first level) valor) (second level) (third level) (fourth level)))
 ((= x 2)(list (first level) (act-lineValue y (second level) value) (third level) (fourth level)))
 ((= x 3)(list (first level) (second level) (act-lineValue y (third level) value) (fourth level)))
 ((= x 4)(list (first level) (second level) (third level) (act-linhaValor y (fourth level) value)))))

(defun act-lineValue (y line value)
  (cond ((= y 1) (list value (second line) (third line) (fourth line)))
  ((= y 2) (list (first line) value (third line) (fourth line)))
  ((= y 3) (list (first line) (second line) value (fourth line)))
  ((= y 4) (list (first line) (second line) (third line) value))))

当我尝试在空位置插入一个值时,它会起作用。

CL-USER 1 > (inserirValor 1 1 1 '(((NIL NIL NIL NIL)(NIL NIL NIL NIL)(NIL NIL NIL NIL)(NIL NIL NIL NIL))(NIL NIL)) '10)
(((10 NIL NIL NIL) (NIL NIL NIL NIL) (NIL NIL NIL NIL) (NIL NIL NIL NIL)) (NIL NIL) NIL NIL)

但是当我尝试在同一位置插入另一个值时,它不起作用。它只是取代以前的新值,当我真正想要的是这样的时候:

CL-USER 1 > (inserirValor 1 1 1 '(((10 NIL NIL NIL)(NIL NIL NIL NIL)(NIL NIL NIL NIL)(NIL NIL NIL NIL))(NIL NIL)) '1)
((((1 10) NIL NIL NIL) (NIL NIL NIL NIL) (NIL NIL NIL NIL) (NIL NIL NIL NIL)) (NIL NIL) NIL NIL)

有人能帮助我吗?我该怎么办?在insertValue函数中创建一个新条件?

1 个答案:

答案 0 :(得分:2)

代码重复

你不应该打那么多。想想RSI; - )

而不是firstsecond等,您可以使用NTH进行简单访问。 这适用于不同的尺寸,而不仅仅是4。

至于更新电路板,您似乎选择使用嵌套列表和纯功能方法(即无突变)。您需要制作一块经过修改的电路板副本。让我们定义一个辅助函数,它以纯函数的方式替换列表中的一个元素:

(defun replace-element (list n value)
  (nconc                  
   (subseq list 0 n)
   (list value)
   (subseq list (1+ n))))

(APPEND也可以替代NCONC,但为什么要分配更多内存?)

你也可以复制和改变:

(defun replace-element (list n value)
  (let ((copy
         (copy-list list)))
    (setf (nth N copy) value)
    copy))

这是一个测试:

(let ((list '(a b c d e)))
  (loop
     for i below (length list)
     collect (replace-element list i '_)))

((_ B C D E)
 (A _ C D E)
 (A B _ D E)
 (A B C _ E)
 (A B C D _))

添加值

您有效地在act-lineValue函数中添加了值。考虑如何初始化数据,而不是替换旧值。当电路板为空时,你有NIL,它代表空列表。

这意味着您可以将您的值放在现有列表的前面,而不是替换已经存在的列表。 使用上一个函数,它变为:

(replace-element line N (cons value (nth N line)))

其他评论

  • Lisp中的名称不使用CamelCase,但使用短划线符号分隔单词。这意味着level-value而不是levelValue

  • 另外,你的名字有点神秘,我真的不知道act前缀代表什么。 get-elem应为get-element。代码应该是可读的。

  • 为什么用数字编码白色和黑色?您正在使用Lisp,这是一种具有符号值的语言。只需使用'white'black,这不会导致效率损失并且更具可读性。

相关问题