Skip to content

Instantly share code, notes, and snippets.

@mrryanjohnston
Created August 30, 2025 01:11
Show Gist options
  • Save mrryanjohnston/e896094fb4108f8d5de54840686c8a30 to your computer and use it in GitHub Desktop.
Save mrryanjohnston/e896094fb4108f8d5de54840686c8a30 to your computer and use it in GitHub Desktop.
CLIPS Blackjack

CLIPS Blackjack

Implementation of the game Blackjack (21) in CLIPS

Usage

Run this from the command line with ./clips -f2 program.bat like so:

$ ./clips -f2 program.bat
%%!!!!$*************

== Scoreboard =====
Player
(12) ♠4, ♣8

Dealer
(14) ♥Jack, ♦4
===================

Hit or Stay (h/s)?: h

--> Player hits and draws ♣Ace

== Scoreboard =====
Player
(13) ♠4, ♣8, ♣Ace

Dealer
(14) ♥Jack, ♦4
===================

Hit or Stay (h/s)?: h

--> Player hits and draws ♠2

== Scoreboard =====
Player
(15) ♠4, ♣8, ♣Ace, ♠2

Dealer
(14) ♥Jack, ♦4
===================

Hit or Stay (h/s)?: h

--> Player hits and draws ♥4

== Scoreboard =====
Player
(19) ♠4, ♣8, ♣Ace, ♠2, ♥4

Dealer
(14) ♥Jack, ♦4
===================

Hit or Stay (h/s)?: s

--> Dealer hits and draws ♦9

== Scoreboard =====
Player
(19) ♠4, ♣8, ♣Ace, ♠2, ♥4

Dealer
(23) ♥Jack, ♦4, ♦9
===================

--> Dealer busted. Player wins!
;(watch statistics)
(load program.clp)
(reset)
(run)
(exit)
(deftemplate card
(slot rank)
(slot suit))
(deftemplate deck
(multislot cards))
(deffunction hand-value ($?cards)
(bind ?hand-value 0)
(bind ?aces 0)
(foreach ?card ?cards
(if (eq Ace (fact-slot-value ?card rank)) then (bind ?aces (+ 1 ?aces)))
(bind ?hand-value
(+ ?hand-value (switch (fact-slot-value ?card rank)
(case Ace then 1)
(case King then 10)
(case Queen then 10)
(case Jack then 10)
(default (fact-slot-value ?card rank))))))
(if (and (< 0 ?aces) (<= ?hand-value 11))
then (bind ?hand-value (+ ?hand-value 10)))
(return ?hand-value))
(deffunction print-card (?card)
(switch (fact-slot-value ?card suit)
(case clubs then (print ♣))
(case spades then (print ♠))
(case hearts then (print ♥))
(case diamonds then (print ♦)))
(print (fact-slot-value ?card rank)))
(deffunction announce-player-hand (?name $?cards)
(println ?name)
(printout t "(" (hand-value ?cards) ") ")
(foreach ?card ?cards
(print-card ?card)
(if (neq ?card (nth$ (length$ ?cards) ?cards)) then (print ", ")))
(println))
(deffunction announce-scoreboard (?player1name ?player1cards ?player2name ?player2cards)
(println)
(println "== Scoreboard =====")
(announce-player-hand ?player1name ?player1cards)
(println)
(announce-player-hand ?player2name ?player2cards)
(println "==================="))
(deffacts init
(suit clubs)
(suit spades)
(suit hearts)
(suit diamonds)
(rank 2)
(rank 3)
(rank 4)
(rank 5)
(rank 6)
(rank 7)
(rank 8)
(rank 9)
(rank 10)
(rank Jack)
(rank Queen)
(rank King)
(rank Ace))
(defrule shuffle
=>
(seed (integer (time)))
(bind ?cards (create$))
(do-for-all-facts ((?s suit) (?r rank)) TRUE
(bind ?cards (create$ ?cards (assert (card (suit (nth$ 1 ?s:implied)) (rank (nth$ 1 ?r:implied)))))))
(loop-for-count (?from 1 52)
(bind ?to (random 1 52))
(bind ?cards
(replace$ (replace$ ?cards ?from ?from (nth$ ?to ?cards)) ?to ?to (nth$ ?from ?cards))))
(assert (deck (cards ?cards))))
(defrule deal-cards
?deck <- (deck (cards $?cards&:(= (length$ ?cards) 52)))
=>
(assert (player-hand (create$ (nth$ 1 ?cards) (nth$ 3 ?cards))))
(assert (dealer-hand (create$ (nth$ 2 ?cards) (nth$ 4 ?cards))))
(modify ?deck (cards (subseq$ ?cards 5 52))))
(defrule prompt-user-for-choice
(player-hand $?cards&:(> 21 (hand-value ?cards)))
(dealer-hand $?d&:(> 21 (hand-value ?d)))
(not (player-choice ?))
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(printout t "Hit or Stay (h/s)?: ")
(assert (player-choice (readline))))
(defrule wrong-choice
?p <- (player-choice ~"h"&~"s")
=>
(println "Invalid choice")
(retract ?p))
(defrule player-hit
?choice <- (player-choice "h")
?hand <- (player-hand $?c)
?deck <- (deck (cards ?top $?cards))
=>
(retract ?choice ?hand)
(println)
(printout t "--> Player hits and draws ")
(print-card ?top)
(println)
(assert (player-hand ?c ?top))
(modify ?deck (cards ?cards)))
(defrule player-bust
(player-hand $?cards&:(> (hand-value ?cards) 21))
(dealer-hand $?d)
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(println "--> Player busted! Game over..."))
(defrule dealer-hit
(player-hand $?p)
?hand <- (dealer-hand $?c&:(> 17 (hand-value ?c)))
?deck <- (deck (cards ?top $?cards))
(or
(player-choice "s")
(and
(test (< 2 (length$ ?p)))
(test (= 21 (hand-value ?p)))))
=>
(retract ?hand)
(println)
(printout t "--> Dealer hits and draws ")
(print-card ?top)
(println)
(assert (dealer-hand ?c ?top))
(modify ?deck (cards (subseq$ ?cards 2 (length$ ?cards)))))
(defrule dealer-blackjack
(player-hand $?cards&:(> 21 (hand-value ?cards)))
(dealer-hand $?d&:(= (hand-value ?d) 21)&:(= 2 (length$ ?d)))
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(println "--> Dealer blackjack, automatic loss :("))
(defrule player-blackjack
(player-hand $?cards&:(= 2 (length$ ?cards))&:(= 21 (hand-value ?cards)))
(dealer-hand $?d&:(<> (hand-value ?d) 21))
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(println "--> Player blackjack! You win!"))
(defrule push
(player-hand $?cards&:(>= 21 (hand-value ?cards)))
(dealer-hand $?d&:(>= (hand-value ?d) 17))
(test (= (hand-value ?cards) (hand-value ?d)))
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(println "--> Push (Tie)..."))
(defrule player-wins
(player-hand $?cards)
(dealer-hand $?d&:(>= (hand-value ?d) 17))
(test (> (hand-value ?cards) (hand-value ?d)))
(test (or
(and (= 2 (length$ ?cards)) (> 21 (hand-value ?cards)))
(and (< 2 (length$ ?cards)) (>= 21 (hand-value ?cards)))))
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(println "--> Player wins!"))
(defrule dealer-wins
(player-hand $?cards&:(> 21 (hand-value ?cards)))
(dealer-hand $?d&:(>= (hand-value ?d) 17)&:(>= 21 (hand-value ?d)))
(player-choice "s")
(test (< (hand-value ?cards) (hand-value ?d)))
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(println "--> Dealer wins..."))
(defrule dealer-busted
(player-hand $?cards)
(dealer-hand $?d&:(> (hand-value ?d) 21))
=>
(announce-scoreboard Player ?cards Dealer ?d)
(println)
(println "--> Dealer busted. Player wins!"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment