(in-package "ACL2")
(include-book "standard-52-card-deck/top")
(defun sum (x)
(declare (xargs :guard (nat-listp x)))
(cond ((endp x) 0)
(t (+ (car x) (sum (cdr x))))))
(defun rank-natp-filter (x)
(declare (xargs :guard (true-listp x)))
(cond ((endp x) nil)
((natp (car x))
(cons (car x) (rank-natp-filter (cdr x))))
(t (rank-natp-filter (cdr x)))))
(defun rank-facep-filter (x)
(declare (xargs :guard (true-listp x)))
(cond ((endp x) nil)
((rank-facep (car x))
(cons (car x) (rank-facep-filter (cdr x))))
(t (rank-facep-filter (cdr x)))))
(defmacro rank-face-list-to-score (x)
`(* 10 (len ,x)))
(defmacro score-without-aces (x)
`(+ (sum (rank-natp-filter ,x))
(rank-face-list-to-score (rank-facep-filter ,x))))
(defthm natp-score-without-aces
(let ((s (score-without-aces x)))
(and (integerp s)
(<= 0 s))))
(defun ace-count (x)
(declare (xargs :guard (rank-listp x)))
(cond ((endp x) 0)
((rank-acep (car x)) (+ 1 (ace-count (cdr x))))
(t (ace-count (cdr x)))))
(defthm natp-ace-count
(and (integerp (ace-count x))
(<= 0 (ace-count x))))
(defmacro add-ace-scores (s ac)
`(cond
((equal ,ac 0) ,s)
((< (+ ,s 10) 21) (+ ,s 11 (- ,ac 1)))
(t (+ ,s 1 (- ,ac 1)))))
(defthm natp-add-ace-scores
(implies (and (integerp x)
(<= 0 x)
(integerp y)
(<= 0 y))
(let ((s (add-ace-scores x y)))
(and (integerp s)
(<= 0 s)))))
(defmacro nat-score (x)
`(add-ace-scores (score-without-aces ,x)
(ace-count ,x)))
(defthm natp-nat-score
(implies (rank-listp x)
(and (integerp (nat-score x))
(<= 0 (nat-score x))))
:rule-classes (:rewrite :forward-chaining))
(defmacro score (x)
`(cond
((and (< 21 (nat-score ,x))) 'BUST)
((and (equal (len ,x) 2) (equal (nat-score ,x) 21))
'NATURAL-BLACKJACK)
(t (nat-score ,x))))
(defmacro scorep (x)
`(or (equal ,x 'bust)
(equal ,x 'natural-blackjack)
(if (integerp ,x)
(if (< ,x 0)
nil
(< ,x 22))
nil)))
(defthm natp-sum
(implies (nat-listp x)
(and (integerp (sum x))
(<= 0 (sum x))))
:rule-classes (:rewrite :forward-chaining))
(defthm nat-listp-rank-natp-filter
(implies (rank-listp x)
(rank-nat-listp (rank-natp-filter x)))
:rule-classes (:rewrite :forward-chaining))
(defthm scorep-score
(implies (rank-listp x)
(scorep (score x))))
(defmacro score-judge (player dealer)
`(cond
((and (equal ,player 'NATURAL-BLACKJACK)
(equal ,dealer 'NATURAL-BLACKJACK))
'PUSH)
((equal ,player 'NATURAL-BLACKJACK) 'WIN)
((equal ,dealer 'NATURAL-BLACKJACK) 'LOSE)
((equal ,player 'BUST) 'LOSE)
((equal ,dealer 'BUST) 'WIN)
((< ,player ,dealer) 'LOSE)
((> ,player ,dealer) 'WIN)
(t 'PUSH)))
(defmacro judge (player dealer)
`(score-judge (score (card-list-to-rank-list ,player))
(score (card-list-to-rank-list ,dealer))))
(defmacro judgementp (x)
`(or (equal ,x 'NATURAL-BLACKJACK)
(equal ,x 'BUST)
(equal ,x 'LOSE)
(equal ,x 'WIN)
(equal ,x 'PUSH)))
(defthm judgementp-score-judge
(judgementp (score-judge p d)))
(defthm if-bust-then-lose
(equal (score-judge 'BUST x) 'LOSE))
(defthm if-draw-a-face-card-and-have-a-ace-card-only-then-natural-blackjack
(implies (and (rank-facep face)
(rank-acep ace))
(equal (score (list ace face))
'NATURAL-BLACKJACK)))
(defun no-rank-acep (x)
(declare (xargs :guard (true-listp x)))
(if (endp x)
t
(and (not (rank-acep (car x)))
(no-rank-acep (cdr x)))))
(defthm if-draw-a-face-when-12-then-bust
(implies (and (rank-listp rs)
(no-rank-acep rs)
(rank-facep face)
(equal (nat-score rs) 12))
(equal (score (cons face rs)) 'BUST)))
(defthm safe-to-hit
(implies (and (rank-listp rs)
(rankp new)
(<= (nat-score rs) 11))
(not (equal (score (cons new rs)) 'BUST))))