В игре 11th hour попалась головоломка-игрушка, цель которой: выстроить в ряд 4 фишки. Причём нельзя выбрать горизонталь для новой фишки, можно выбрать только вертикаль. Я не могу победить компьютер в этой мини-игре, так что попробую устроить битву двух 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)
Каждая клетка доски может находиться в одном из трёх состояний:
;; 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)