3 (defun score-better-p (this that)
6 (and (not (eq this :lose))
10 (defun invert-score (this)
16 (defparameter *plies* 2)
18 (defun make-board-connectivity-map (width height)
19 (let ((map (make-array (* width height)
21 :initial-element nil)))
22 (flet ((index (i j) (+ (* j width) i)))
25 (setf (aref map (index i j))
26 (nconc (and (> j 0) (list (index i (1- j))))
27 (and (> i 0) (list (index (1- i) j)))
28 (and (< i (1- width)) (list (index (1+ i) j)))
29 (and (< j (1- height)) (list (index i (1+ j))))))))
32 (deftype octet () '(unsigned-byte 8))
34 (defun make-critical-count-map (conn-map)
35 (make-array (length conn-map)
37 :initial-contents (map 'list #'length conn-map)))
39 (defun make-simple-board (size)
44 (defun copy-vector (vector)
45 (make-array (length vector)
46 :element-type (array-element-type vector)
47 :initial-contents vector))
49 (defun simple-score (who counts owners)
50 (reduce #'+ (mapcar (lambda (count owner)
51 (if (= owner who) count 0))
54 (defun make-checklist (size)
55 (make-array size :element-type 'fixnum :fill-pointer 0))
57 (defclass robot-state ()
58 ((n-players :type octet :reader robot-n-players :initarg :n-players)
59 (me :type octet :reader robot-me :initarg :me)
60 (size :type fixnum :reader robot-size :initarg :size)
61 (conn-map :type (vector list *) :reader robot-conn-map :initarg :conn-map)
62 (crit-map :type (vector octet *)
63 :reader robot-crit-map
65 (checklist-a :type (vector fixnum *)
66 :reader robot-checklist-a
67 :initarg :checklist-a)
68 (checklist-b :type (vector fixnum *)
69 :reader robot-checklist-b
70 :initarg :checklist-b)
71 (scores :type (vector fixnum *) :reader robot-scores :initarg :scores)
72 (seen :type bit-vector :reader robot-seen :initarg :seen)))
74 (defclass robot-position ()
75 ((who :type octet :reader robot-who :initarg :who)
76 (counts :type (vector octet *) :reader robot-counts :initarg :counts)
77 (owners :type (vector octet *) :reader robot-owners :initarg :owners)))
79 (defun make-robot-state (game player)
80 (let* ((grid (game-grid game))
81 (width (array-dimension grid 1))
82 (height (array-dimension grid 0))
83 (size (* width height))
84 (n-players (length (game-players game)))
85 (conn-map (make-board-connectivity-map width height)))
86 (make-instance 'robot-state
87 :me (1+ (position player (game-players game)))
91 :crit-map (make-critical-count-map conn-map)
92 :scores (make-array (1+ n-players) :element-type 'fixnum)
93 :checklist-a (make-checklist size)
94 :checklist-b (make-checklist size)
95 :seen (make-array size :element-type 'bit))))
97 (defun make-robot-position (who counts owners)
98 (make-instance 'robot-position
103 (defun make-initial-robot-position (state game)
104 (let* ((size (robot-size state))
105 (grid (game-grid game))
106 (counts (make-simple-board size))
107 (owners (make-simple-board size)))
110 (let ((cell (row-major-aref grid i)))
111 (setf (aref counts i) (cell-count cell)
112 (aref owners i) (let ((owner (cell-owner cell)))
113 (if owner (1+ owner) 0)))))
115 (make-robot-position (robot-me state) counts owners)))
117 (defclass robot-player (player)
118 ((robot-state :type robot-state :reader robot-player-state)))
119 (setf (player-type-name 'robot-player) "Robot")
121 (defun robot-update-scores (state counts owners)
122 (let ((scores (robot-scores state))
123 (n-players (robot-n-players state))
124 (size (robot-size state)))
125 (dotimes (i (1+ n-players)) (setf (aref scores i) 0))
126 (dotimes (i size) (incf (aref scores (aref owners i)) (aref counts i)))))
128 (defun robot-try-move (state position move)
129 (let ((conn-map (robot-conn-map state))
130 (crit-map (robot-crit-map state))
131 (n-players (robot-n-players state))
132 (size (robot-size state))
133 (seen (robot-seen state))
134 (checklist (robot-checklist-a state))
135 (next-checklist (robot-checklist-b state))
136 (who (robot-who position))
137 (scores (robot-scores state))
138 (owners (copy-vector (robot-owners position)))
139 (counts (copy-vector (robot-counts position))))
141 (let ((occupier (aref owners move)))
142 (unless (or (zerop occupier) (= occupier who))
143 (return-from robot-try-move nil)))
146 (setf (aref owners move) who)
147 (unless (>= (incf (aref counts move))
148 (aref crit-map move))
149 (return-from update-board))
151 (setf (fill-pointer checklist) 0)
152 (vector-push move checklist)
153 (let ((opponents (count-if (lambda (own)
154 (and (plusp own) (/= own who)))
157 (when (or (zerop (fill-pointer checklist))
159 (return-from update-board))
160 (setf (fill-pointer next-checklist) 0)
161 (dotimes (i size) (setf (bit seen i) 0))
162 (dotimes (i (fill-pointer checklist))
163 (let* ((pos (aref checklist i))
164 (crit (aref crit-map pos)))
165 (multiple-value-bind (dist left) (floor (aref counts pos) crit)
166 (setf (aref counts pos) left)
168 (setf (aref owners pos) 0))
169 (dolist (neigh (aref conn-map pos))
170 (let ((old-owner (aref owners neigh)))
171 (unless (= old-owner who)
172 (unless (zerop old-owner) (decf opponents))
173 (setf (aref owners neigh) who))
174 (when (and (>= (incf (aref counts neigh) dist)
175 (aref crit-map neigh))
176 (zerop (bit seen neigh)))
177 (vector-push neigh next-checklist)
178 (setf (bit seen neigh) 1)))))))
179 (rotatef checklist next-checklist))))
181 (robot-update-scores state counts owners)
182 (make-robot-position (do ((i (1+ (mod who n-players))
183 (1+ (mod i n-players))))
184 ((plusp (aref scores i)) i))
187 (defun simple-rating (state position)
188 (declare (ignore position))
189 (let* ((n-players (robot-n-players state))
190 (scores (robot-scores state))
191 (me (robot-me state))
192 (total (reduce #'+ scores))
193 (mine (aref scores me)))
194 (cond ((and (zerop mine) (>= total me)) :lose)
195 ((and (= mine total) (>= total n-players)) :win)
196 (t (- (* 2 mine) total)))))
198 (defparameter *robot-n-plies* 2)
200 (defun robot-choose-move (state game)
201 (let ((me (robot-me state))
202 (size (robot-size state)))
203 (labels ((walk (position depth alpha beta)
204 (let ((who (robot-who position)))
207 (format t ";; walk; who = ~A; depth remaining = ~A~%"
210 (let ((rating (simple-rating state position)))
214 (format t ";; final position ~A~%" rating)
215 (return-from walk (values rating nil))))
218 (format t ";; bottomed out; rating = ~A~%" rating)
219 (return-from walk (values rating nil))))
222 (let ((best-move nil))
225 (format t ";; try my move ~A~%"
228 (array-dimension (game-grid game)
230 (let ((next-pos (robot-try-move state
234 (let ((score (walk next-pos
237 (when (score-better-p score alpha)
239 (format t ";; best move so far~%")
242 (when (score-better-p alpha beta)
244 (values alpha best-move))
245 (let ((best-move nil))
248 (format t ";; try opponent #~A move ~A~%"
252 (array-dimension (game-grid game)
254 (let ((next-pos (robot-try-move state
258 (let ((score (walk next-pos
261 (when (score-better-p beta score)
263 (format t ";; best opponent move so far~%")
266 (when (score-better-p alpha beta)
268 (values beta best-move))))))
269 (let ((position (make-initial-robot-position state game)))
270 (robot-update-scores state
271 (robot-counts position)
272 (robot-owners position))
273 (multiple-value-bind (rating move)
274 (walk position *robot-n-plies* :lose :win)
275 (declare (ignore rating))
278 (defun robot-move (game player)
279 (let* ((state (robot-player-state player))
280 (move (robot-choose-move state game))
281 (grid (game-grid game))
282 (width (array-dimension grid 1)))
283 (multiple-value-bind (j i) (floor move width)
284 (play-cell game player i j))))
286 (defun stupid-robot-move (game player)
287 (let* ((state (robot-player-state player))
288 (grid (game-grid game))
289 (width (array-dimension grid 1))
290 (height (array-dimension grid 0))
291 (moves (make-array (array-total-size grid) :fill-pointer 0)))
294 (let ((occupier (cell-owner (aref grid j i))))
295 (when (or (null occupier)
296 (= occupier (1- (robot-me state))))
297 (vector-push (cons i j) moves)))))
298 (let ((move (aref moves (random (length moves)))))
299 (play-cell game player (car move) (cdr move)))))
301 (defmethod player-turn-begin (game (player robot-player))
302 (unless (slot-boundp player 'robot-state)
303 (setf (slot-value player 'robot-state) (make-robot-state game player)))
304 (robot-move game player))
306 (unless (find 'robot-player *player-types*)
308 (append *player-types* '(robot-player))))
311 (start-atom-game :width 7
313 ("RoboBob" :type robot-player)))