We continue to develop the game described here, here and here.
Now the time has come to acquire a small system of interaction with player. First, let’s show the board:
;; *** UI
;; show board
(defun draw-board (board)
(flet
((get-cell-char (cell)
(cond
((eql cell *ai-cell*) #\A)
((eql cell *human-cell*) #\H)
(t #\.))))
(loop
for j below *board-height*
for row-idx from 0 by *board-width*
do (progn
(fresh-line)
(loop
for i below *board-width*
for idx from row-idx
for cell = (get-cell board idx)
do (princ (get-cell-char cell)))))
(fresh-line)
(loop
for i below *board-width*
do (princ (code-char (+ 97 i))))))
Under the board are printed letters of the columns, we need them to enter the player moves.
* (draw-board (new-board))
...
...
...
abc
A small auxiliary function for printing the winner. The winner is not the loser in the current position
;; announce winner
(defun announce-winner (tree)
(fresh-line)
(if (game-node-failp tree)
(format t "The winner is ~a"
(get-player-str (change-player (game-node-player tree))))
(princ "There are no winners.")))
Completely information about the game situation includes the board and the current active player.
;; show situation
(defun print-info (tree)
(fresh-line)
(format t "current player = ~a" (get-player-str (game-node-player tree)))
(draw-board (game-node-board tree)))
Let’s try on the initial board:
* (print-info (game-tree (new-board) *ai-player* -1))
current player = The Evil AI
...
...
...
abc
NIL
*
The processing of the player’s move is simple: it is suggested to enter a number corresponding to the letter designation of the column. Filled columns are not offered for selection. The correctness of the data is no checked, but for our purposes this is not critical.
;; handle human
(defun handle-human (tree)
(fresh-line)
(princ "choose your move:")
(let ((moves (game-node-moves tree)))
(labels ((print-moves (lst n)
(unless (null lst)
(let* ((move (car lst))
(action (code-char (+ 97 (mod (car move) *board-width*)))))
(fresh-line)
(format t "~a. ~a" n action)
(print-moves (cdr lst) (1+ n))))))
(print-moves moves 1))
(fresh-line)
(cadr (nth (1- (read)) moves))))
The most important function of the program. Allows the computer and the player to make move in turn, checking for victory.
;; main loop
(defun play (tree)
(print-info tree)
(if (game-node-failp tree)
(announce-winner tree)
(if (eq *ai-player* (game-node-player tree))
(play (handle-computer tree))
(play (handle-human tree)))))
Small party completely:
* (play (game-tree (new-board) *ai-player* -1))
current player = The Evil AI
...
...
...
abc
current player = Human
...
...
A..
abc
choose your move:
1. a
2. b
3. c
1
current player = The Evil AI
...
H..
A..
abc
current player = Human
...
H..
AA.
abc
choose your move:
1. a
2. b
3. c
1
current player = The Evil AI
H..
H..
AA.
abc
current player = Human
H..
HA.
AA.
abc
choose your move:
1. b
2. c
2
current player = The Evil AI
H..
HA.
AAH
abc
current player = Human
HA.
HA.
AAH
abc
The winner is The Evil AI
NIL
The computer won Although AI plays quite strange, it still won.