list - 如何操作由列表组成的复杂数据结构?

标签 list lisp common-lisp connect

我正在尝试代表 3D Connect 4 棋盘游戏:

BoardGameConnect4-3D

例如,我有以下列表结构:

(
(
(NIL NIL NIL NIL)
(NIL NIL NIL NIL)
(NIL NIL NIL NIL)
(NIL NIL NIL NIL)
)
(1 1 1 1 1 1 1 1 1 1 1 1 10 10 10 10 10 10 10 10 10 10 10 10)
)

每个 NIL 代表其中的一个位置。例如,如果我将两 block (一 block 黑色和一 block 白色)放在第一个位置,它看起来像这样:

(
(
((B W) NIL NIL NIL)
(NIL NIL NIL NIL)
(NIL NIL NIL NIL)
(NIL NIL NIL NIL)
)
(1 1 1 1 1 1 1 1 1 1 1 1 10 10 10 10 10 10 10 10 10 10 10 10)
)

这意味着 W 将是底部的那个。我还需要将它们相互比较,以便程序能够说出何时找到获胜者。

如何在每个位置添加棋子?既然它们是具有 NIL 值的列表,我该如何比较它们?

最佳答案

无论您选择使用什么实现,最好定义一个接口(interface)来操作您的对象。下面,我定义了 make-board、push-token 和 pop-token 函数。您还可以定义其他访问器函数,例如获取坐标 (x y z) 处的值。

然后,您只需通过此接口(interface)操作您的数据,以便您的代码可读且易于维护。我使用的是向量的 2D 矩阵,其中内部向量由于其填充指针而被用作堆栈(有关详细信息,请参阅 MAKE-ARRAY)。

板类别和 token 类型

(defclass board ()
  ((matrix :reader board-matrix :initarg :matrix)
   (size :reader board-size :initarg :size)))

(deftype token-type () '(member white black))

构造函数

(defun make-board (size)
  (let ((board
         (make-array (list size size))))
    (dotimes (i (array-total-size board))
      (setf (row-major-aref board i)
            (make-array size
                        :element-type 'symbol
                        :fill-pointer 0)))
    (make-instance 'board :matrix board :size size)))

自定义打印机

(defmethod print-object ((b board) stream)
  (print-unreadable-object (b stream :type t)
    (let ((matrix (board-matrix b))
          (size (board-size b)))
      (dotimes (row size)
        (fresh-line)
        (dotimes (col size)
          (let* ((stack (aref matrix row col)))
            (dotimes (z size)
              (princ (case (aref stack z)
                       (white #\w)
                       (black #\b)
                       (t #\.))
                     stream)))
          (princ #\space stream))))))

推向 (x,y)

(defun push-token (board x y token)
  (check-type token token-type)
  (vector-push token (aref (board-matrix board) y x)))

从 (x,y) 弹出

(defun pop-token (board x y)
  (ignore-errors
    (let ((stack (aref (board-matrix board) y x)))
      (prog1 (vector-pop stack)
        ;; we reset the previous top-most place to NIL because we
        ;; want to allow the access of any cell in the 3D
        ;; board. The fill-pointer is just here to track the
        ;; position of the highest token.
        (setf (aref stack (fill-pointer stack)) nil)))))

测试

(let ((board (make-board 4)))
  (flet ((@ (&rest args) (print board)))
    (print board)
    (@ (push-token board 1 2 'white))
    (@ (push-token board 1 2 'black))
    (@ (push-token board 1 2 'white))
    (@ (push-token board 1 2 'black))
    (@ (push-token board 1 2 'black))
    (@ (push-token board 0 3 'white))
    (@ (pop-token board 1 2))
    (@ (pop-token board 1 2))))

输出

#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... .... .... .... 
.... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... w... .... .... 
.... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... wb.. .... .... 
.... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... wbw. .... .... 
.... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... wbwb .... .... 
.... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... wbwb .... .... 
.... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... wbwb .... .... 
w... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... wbw. .... .... 
w... .... .... .... > 
#<BOARD 
.... .... .... .... 
.... .... .... .... 
.... wb.. .... .... 
w... .... .... .... >

关于list - 如何操作由列表组成的复杂数据结构?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38641323/

相关文章:

lisp - 返回与符号关联的所有值的函数

algorithm - Lisp gethash 复杂性

list - 使用 zipWith 计算列表元素的差异

java - 按元素类型拆分列表

list - 如何在 Flutter 中反转 ListView

common-lisp - 在 apply mapcar 中使用 `cons`

macos - Common Lisp 程序的 OS X 包

python - 对元组列表进行排序时的多个要求

LISP MAKE-PATHNAME : Illegal :DIRECTORY argument

database - 函数式编程和数据库交互的最佳实践是什么?