main.lisp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. ;;;; test/main.lisp
  2. (in-package #:gamao/test)
  3. (defvar *error-on-failing-tests* nil)
  4. (defun run-all ()
  5. (let ((test-results (multiple-value-list (run! 'all-tests))))
  6. (when (and (not (first test-results)) *error-on-failing-tests*)
  7. (error "There were failing tests."))
  8. (values-list test-results)))
  9. (def-suite all-tests
  10. :description "All gamao tests")
  11. (def-suite checker-game
  12. :in all-tests)
  13. (in-suite checker-game)
  14. (def-fixture pvector-test-fixture ()
  15. (let* ((v1 (make-pvector 3 :initial-contents '(1 2 3)))
  16. (v2 (pvector-update v1 0 -1))
  17. (v3 (pvector-update v2 1 -2)))
  18. (pvector-reroot v2)
  19. (&body)))
  20. (test pvector-test
  21. (with-fixture pvector-test-fixture ()
  22. (is (= 1 (pvector-ref v1 0)))
  23. (is (= -1 (pvector-ref v2 0)))
  24. (is (= -2 (pvector-ref v3 1)))))
  25. (test pvector-reroot-test
  26. (is (= (pvector-ref (pvector-reroot (pvector-update (pvector-update (make-pvector 28 :initial-element 0) 0 3) 25 1)) 25) 1)))
  27. (def-fixture checker-position-test-fixture ()
  28. (let* ((p1 (make-checker-position))
  29. (p2 (update-checker-position p1 1 :black 3))
  30. (p3 (update-checker-position p2 :off :white 1))
  31. (p4 (update-checker-position p3 :bar :white 1)))
  32. (&body)))
  33. (test checker-position-test
  34. (with-fixture checker-position-test-fixture ()
  35. (is (typep p1 'checker-position) )
  36. (is (= 3 (checker-position-checkers-at p2 1 :black)))
  37. (is (= 3 (checker-position-checkers-at p4 1 :black)))
  38. (is (= 0 (checker-position-checkers-at p4 1 :white)))
  39. (is (eq :white (nth-value 1 (checker-position-checkers-at p4 1 :white))))
  40. (is (eq :black (nth-value 1 (checker-position-checkers-at p4 1 :black))))
  41. (is (eq :black (nth-value 1 (checker-position-checkers-at p4 2 :black))))
  42. (is (null (nth-value 1 (checker-position-checkers-at p4 2 nil))))
  43. (is (= 1 (checker-position-checkers-at p4 :off :white)))
  44. (is (eq :white (nth-value 1 (checker-position-checkers-at p4 :off :white))))
  45. (is (= 1 (checker-position-checkers-at p4 :bar :white)))
  46. (is (eq :white (nth-value 1 (checker-position-checkers-at p4 :bar :white))))
  47. (is (= 0 (checker-position-checkers-at p4 :off :black)))
  48. (is (eq :black (nth-value 1 (checker-position-checkers-at p4 :off :black))))
  49. (signals type-error (checker-position-checkers-at p4 :black :off))))
  50. (test opponent-test
  51. (is (eq :white (opponent :black)))
  52. (is (eq :black (opponent :white)))
  53. (signals simple-type-error (opponent nil)))
  54. (def-fixture backgammon-game-fixture (&key (cube 1) checkers)
  55. (let ((game (if (null checkers)
  56. (make-instance 'backgammon-game :cube cube :checkers (gamao-impl::make-initial-backgammon-position))
  57. (make-instance 'backgammon-game
  58. :cube cube
  59. :checker-position (loop with checker-position = (make-checker-position)
  60. for update in checkers
  61. do (apply #'update-checker-position checker-position update))))))
  62. (&body)))
  63. (test backgammon-game-test
  64. (with-fixture backgammon-game-fixture ()
  65. ;; First turn: undecided, then black
  66. (is (new-dice game 1 1))
  67. (is (null (current-player game)))
  68. (is (new-dice game 2 1))
  69. (is (eq :black (current-player game)))
  70. (is (= 2 (remaining-dice-count game)))
  71. ;; Black must roll dice before moving checkers
  72. (is (null (move-checker game :white 1 1)))
  73. (is (null (move-checker game :black 13 1)))
  74. (is (move-checker game :black 24 1))
  75. (is (= 1 (remaining-dice-count game)))
  76. ;; Undo
  77. (is (undo-move game :black))
  78. (is (= 2 (remaining-dice-count game)))
  79. (is (null (undo-move game :black)))
  80. (is (move-checker game :black 24 1))
  81. ;; Pick-up
  82. (is (null (pick-up-dice game :black)))
  83. (is (move-checker game :black 13 2))
  84. (is (pick-up-dice game :black))
  85. ;; Current player changed to :white
  86. (is (eq :white (current-player game)))
  87. (is (null (new-dice game 6 4)))
  88. (is (roll-dice game :white))
  89. (is (dice-rolling-p game))
  90. (is (new-dice game 6 4))
  91. (is (not (dice-rolling-p game)))
  92. (is (move-checker game :white 1 6))
  93. (is (move-checker game :white 7 4))
  94. (is (pick-up-dice game :white))
  95. (is (roll-dice game :black))
  96. (is (new-dice game 6 6))
  97. ;; Black is hit and cannot enter
  98. (is (zerop (remaining-dice-count game)))
  99. (is (pick-up-dice game :black))
  100. ;; White doubles, black accepts
  101. (is (null (cube-owner game)))
  102. (is (not (cube-offered-p game)))
  103. (is (not (offer-double game :black)))
  104. (is (offer-double game :white))
  105. (is (cube-offered-p game))
  106. (is (eq :black (current-player game)))
  107. (is (accept-double game :black))
  108. (is (eq :white (current-player game)))
  109. (is (eq :black (cube-owner game)))
  110. ;; White can only roll dice
  111. (is (null (offer-double game :white)))
  112. (is (roll-dice game :white))
  113. (is (new-dice game 2 1))
  114. (is (move-checker game :white 1 1))
  115. (is (move-checker game :white 2 2))
  116. (is (pick-up-dice game :white))
  117. ;; Black redoubles, white drops.
  118. (is (offer-double game :black))
  119. (is (null (winner game)))
  120. (is (reject-double game :white))
  121. (is (eq :black (winner game)))
  122. (is (eq :single (game-result game)))
  123. (is (= 2 (game-score game)))
  124. ))
  125. (defun checker-position-from-list (list)
  126. (loop with checker-position = (make-checker-position)
  127. for update in list
  128. do (setf checker-position (apply #'update-checker-position checker-position update))
  129. finally (return checker-position)))
  130. ;;; A few end game tests.
  131. (def-fixture backgammon-game-fixture-2 ()
  132. (let* ((game (make-instance 'backgammon-game
  133. :cube nil
  134. :checkers (checker-position-from-list '((3 :black 1)
  135. (:off :black 14)
  136. (24 :white 14)
  137. (:off :white 1))))))
  138. (setf (current-player game) :black)
  139. (roll-dice game :black)
  140. (new-dice game 1 4)
  141. (&body)))
  142. ;; When one checker remains, one may bear it off using one die or both dice.
  143. (test backgammon-game-test-2
  144. (with-fixture backgammon-game-fixture-2 ()
  145. (is (may-move-checker-p game :black 3 1))
  146. (is (move-checker game :black 3 4))
  147. (is (eq :black (winner game)))
  148. (is (eq :single (game-result game)))
  149. ;; Make sure borne off checkers are not `hit'.
  150. (is (= 1 (checker-position-checkers-at (checkers game) :off :white)))
  151. (is (zerop (checker-position-checkers-at (checkers game) :bar :white)))
  152. ))
  153. ;; gammons, backgammons
  154. (def-fixture backgammon-game-fixture-3 (&key game-class cube checkers)
  155. (let* ((game (make-instance game-class
  156. :cube cube
  157. :checkers (checker-position-from-list checkers))))
  158. (setf (current-player game) :black)
  159. (roll-dice game :black)
  160. (new-dice game 1 4)
  161. (move-checker game :black 3 4)
  162. (&body)))
  163. ;; single
  164. (test backgammon-game-test-3a
  165. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game
  166. :cube 1
  167. :checkers '((3 :black 1)
  168. (:off :black 14)
  169. (24 :white 14)
  170. (:off :white 1)))
  171. (is (eq :black (winner game)))
  172. (is (eq :single (game-result game)))
  173. (is (= 1 (game-score game)))))
  174. ;; gammon
  175. (test backgammon-game-test-3b
  176. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game
  177. :cube 2
  178. :checkers '((3 :black 1)
  179. (:off :black 14)
  180. (24 :white 15)))
  181. (is (eq :black (winner game)))
  182. (is (eq :gammon (game-result game)))
  183. (is (= 4 (game-score game)))))
  184. ;; backgammon: one at home
  185. (test backgammon-game-test-3c
  186. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game
  187. :cube nil
  188. :checkers '((3 :black 1)
  189. (:off :black 14)
  190. (24 :white 14)
  191. (4 :white 1)))
  192. (is (eq :black (winner game)))
  193. (is (eq :backgammon (game-result game)))
  194. (is (= 3 (game-score game)))))
  195. ;; backgammon: one on bar
  196. (test backgammon-game-test-3d
  197. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game
  198. :cube nil
  199. :checkers '((3 :black 1)
  200. (:off :black 14)
  201. (24 :white 14)
  202. (:bar :white 1)))
  203. (is (eq :black (winner game)))
  204. (is (eq :backgammon (game-result game)))
  205. (is (= 3 (game-score game)))))
  206. ;; single: one on bar, one at home, but one is off
  207. (test backgammon-game-test-3e
  208. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game
  209. :cube nil
  210. :checkers '((3 :black 1)
  211. (:off :black 14)
  212. (24 :white 12)
  213. (4 :white 1)
  214. (:bar :white 1)
  215. (:off :white 1)))
  216. (is (eq :black (winner game)))
  217. (is (eq :single (game-result game)))
  218. (is (= 1 (game-score game)))))
  219. ;; single: one on bar, one at home, cube = 1, Jacoby rule
  220. (test backgammon-game-test-3f
  221. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game-with-jacoby
  222. :cube 1
  223. :checkers '((3 :black 1)
  224. (:off :black 14)
  225. (24 :white 13)
  226. (4 :white 1)
  227. (:bar :white 1)))
  228. (is (eq :black (winner game)))
  229. (is (eq :single (game-result game)))
  230. (is (= 1 (game-score game)))))
  231. ;; gammon, cube = 2, Jacoby rule
  232. (test backgammon-game-test-3g
  233. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game-with-jacoby
  234. :cube 2
  235. :checkers '((3 :black 1)
  236. (:off :black 14)
  237. (24 :white 15)))
  238. (is (eq :black (winner game)))
  239. (is (eq :gammon (game-result game)))
  240. (is (= 4 (game-score game)))))
  241. ;; backgammon, cube = 4, Jacoby rule
  242. (test backgammon-game-test-3h
  243. (with-fixture backgammon-game-fixture-3 (:game-class 'backgammon-game-with-jacoby
  244. :cube 4
  245. :checkers '((3 :black 1)
  246. (:off :black 14)
  247. (4 :white 15)))
  248. (is (eq :black (winner game)))
  249. (is (eq :backgammon (game-result game)))
  250. (is (= 12 (game-score game)))))