Yellow Rabbit

Трилобит: игра на Lisp

Игра Трилобит на Lisp:  постановка задачи

Постановка задачи

В игре 11th hour попалась головоломка-игрушка, цель которой: выстроить в ряд 4 фишки. Причём нельзя выбрать горизонталь для новой фишки, можно выбрать только вертикаль. Trilobite original game screen Я не могу победить компьютер в этой мини-игре, так что попробую устроить битву двух AI. Было бы забавно написать соперника для компьютера на Lisp, так как я практически не знаком с этим языком.

Для начала я прочёл Land of Lisp: Learn to Program in Lisp, One Game at a Time! чтобы понять как вообще можно писать игры на этом языке. В качестве компилятора/интерпретатора использую SBCL, ну как один из доступных (/usr/dports/lang/sbcl) для DragonFly BSD.

Игровое поле (доска)

Из книги стало ясно, что доску нужного мне размера (8х7) мне скорее всего не получится реализовать без опыта оптимизации программ на Lisp. Так что начнём с крошечной доски 3x3, на которой, тем не менее, можно будет отработать логику искусственного интеллекта.


;; *** Consts
;; board
(defparameter *board-width*  3)
(defparameter *board-height* 3)
(defparameter *board-size*   (* *board-width* *board-height*))

Условием для победы также будет считаться более короткая линия из фишек:


;; row length for win
(defparameter *win-len* 3)

Каждая клетка доски может находиться в одном из трёх состояний:

  1. быть пустой;
  2. с фишкой противника;
  3. с нашей фишкой.

;; cell types
(defparameter *empty-cell* 0)
(defparameter *ai-cell*    1)
(defparameter *human-cell* 2)

defparameter не совсем то, что мне нужно, тут скорее подошёл бы старый добрый #define, но я пока не обнаружил в Lisp какого-либо подобия настоящих констант.

Доска это массив из ячеек. Её можно создать или полностью из пустых клеток, или копированием из списка клеток, а копировать я буду часто поскольку нужно будет очень много досок с различными комбинациями фишек.


;; *** Board
;; two dimentional array of cells
;; . X ->
;; Y
;; |
;; v
;; initial board
(defun new-board ()
  (make-array *board-size* :initial-element *empty-cell*))

;; make board from list
(defun board-from-list (lst)
  (make-array *board-size* :initial-contents lst))

Нужно ввести понятия игроков чтобы как-то различать чей сейчас ход и т.д.


;; players
(defparameter *ai-player*    1)
(defparameter *human-player* 2)

(defun change-player (player)
  (if (eql player *ai-player*)
    *human-player*
    *ai-player*))

(defun get-player-color (player)
  (if (eql player *ai-player*)
    *ai-cell*
    *human-cell*))

(defun get-player-str (player)
  (if (eql player *ai-player*)
    "The Evil AI"
    "Human"))

И, возвращаясь к нашей доске, опишем пару вспомогательных функция для доступа и проверки ячеек.


;; get board cell
(defun get-cell (board cell)
  (aref board cell))

;; cell type predicates
(defun cell-emptyp (board cell)
  (eql (get-cell board cell) *empty-cell*))

(defun cell-playerp (board cell player)
  (eql (get-cell board cell) player))

На данный момент можно немного посмотреть на работу доски:


% rlwrap sbcl --load trilobite.lisp
This is SBCL 1.2.9, an implementation of ANSI Common Lisp.
More information about SBCL is available at <http://www.sbcl.org/>.

SBCL is free software, provided as is, with absolutely no warranty.
It is mostly in the public domain; some portions are provided under
BSD-style licenses.  See the CREDITS and COPYING files in the
distribution for more information.
* (board-from-list '(1 2 3 4 5 6 7 8 9))

#(1 2 3 4 5 6 7 8 9)
* (new-board)

#(0 0 0 0 0 0 0 0 0)
* (cell-emptyp (new-board) 4)

T
* (get-cell (new-board) 4)

0
* (cell-playerp (new-board) 4 *ai-player*)

NIL
* (exit)