Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ;;
- ;; Artificial Intelligence - Lab 6 - Games
- ;;
- ; README: explicarea implementarii
- ; Strategia implementata functioneaza in felul urmator:
- ; - AI-ul tine intern o multime a tuturor cartilor din pachet,
- ; pe baza a ceea ce se afla pe masa si a ce s-a impartit anterior.
- ; - daca mana AI-ului e mai proasta decat a adversarului, acesta
- ; face hit, cu riscul de a pierde (nu tine cont de asta).
- ; - altfel, isi evalueaza sansele de a face bust: daca probabilitatea
- ; de bust (nr carti busted/nr total de carti din pachet) e cel
- ; putin 50%, atunci executa stand, altfel hit.
- ; - practic, se aduna mana curenta la fiecare tip de carte
- ; ce poate fi impartita si se vede daca vreo posibila mana
- ; viitoare poate da peste 21. Daca da, atunci se calculeaza
- ; probabilitatea de a face bust.
- ;
- ; Helper functions
- ;
- ; Generate a full set of card numbers
- (define gen-cardset
- (lambda ()
- (let do-gen ((n 10))
- (if (= n 0)
- '()
- (cons (cons n 4) (do-gen (- n 1)))
- )
- )
- )
- )
- ; Check if a given set contains a given card number
- (define contains-card?
- (lambda (n set)
- (if (null? set)
- #f
- (let* ((tup (car set))
- (rest (cdr set))
- (card (car tup))
- (num (cdr tup))
- )
- (if (and (= n card) (not (= num 0)))
- #t
- (contains-card? n rest)
- )
- )
- )
- )
- )
- ; Remove a given card from the set. Returns the
- ; modified set or the same set if card doesn't exist
- (define remove-card
- (lambda (n set)
- (if (null? set)
- '()
- (let* ((tup (car set))
- (rest (cdr set))
- (card (car tup))
- (num (cdr tup))
- )
- (if (= n card)
- (let ((num1 (- num 1)))
- (if (<= num1 0)
- rest
- (cons (cons card num1) rest)
- )
- )
- (cons tup (remove-card n rest))
- )
- )
- )
- )
- )
- ; Gets all existent card numbers from a set
- (define get-cards
- (lambda (set)
- (map car set)
- )
- )
- (define get-numbers
- (lambda (set)
- (map cdr set)
- )
- )
- ; Set difference - first set *must* be in the
- ; dotted pair format, second set can be a '(card type)
- ; list.
- (define set-diff
- (lambda (s1 s2)
- (let do-diff ((s1 s1)
- (cards (get-cards s2))
- )
- (if (null? cards)
- s1
- (do-diff (remove-card (car cards) s1)
- (cdr cards))
- )
- )
- )
- )
- ; Check the current state and return an action
- ; Game strategy goes here, basically
- (define check-state
- (lambda (state hishand myhand)
- (if (>= (sum-hand hishand) (sum-hand myhand))
- 'hit
- (let* ((handsum (sum-hand myhand))
- (addhand (lambda (tup) (cons (+ (car tup) handsum)
- (cdr tup))))
- (gt21 (lambda (tup) (cons (> (car tup) 21) (cdr tup))))
- (summed (map addhand state))
- (gt21-cards (map gt21 summed))
- (canlose? (foldl (lambda (a b) (or a b))
- #f (get-cards gt21-cards)))
- )
- (if canlose?
- (let* ((num-cards (foldl + 0 (get-numbers state)))
- (busted? (lambda (tup) (car tup)))
- (num-bust (get-numbers
- (filter busted? gt21-cards)))
- (tot-bust (foldl + 0 num-bust))
- )
- (if (< (/ tot-bust num-cards) (/ 1 2))
- 'hit
- 'stand
- )
- )
- 'hit
- )
- )
- )
- )
- )
- ; strategy for the AI player
- ; parameters:
- ; hand1 - player's hand
- ; hand2 - AI's hand
- ; ai-state - internal state of the player
- ; returns one of the following:
- ; (list 'hit new-ai-state)
- ; (list 'stand new-ai-state)
- ; where new-ai-state is the new internal state of the AI player
- (define do-ai-strategy
- (lambda (hand1 hand2 ai-state)
- (display "my hand: ") (display hand2) (newline)
- (display "my sum: ") (display (sum-hand hand2)) (newline)
- (display "ai-state: ") (display ai-state) (newline)
- (if (null? ai-state)
- (let* ((new-set (gen-cardset))
- (new-state (set-diff (set-diff new-set hand1)
- hand2))
- )
- (list (check-state new-state hand1 hand2) new-state)
- )
- (let ((new-state (set-diff (set-diff ai-state hand1)
- hand2))
- )
- (list (check-state new-state hand1 hand2) new-state)
- )
- )
- )
- )
- ; play a game of 21
- ; state of the game is (pack (hand1 hand2) ai-state round)
- ; where:
- ; pack is the pack of cards
- ; hand1 is player's hand
- ; hand2 is AI's hand
- ; ai-state is the internal state of the AI player
- ; round is the number of the current round
- (define play21
- (lambda ()
- (let* ((pack (random-shuffle (generate-pack)))
- (state (list pack '(() ()) '() 0)))
- (run-game state 0)
- )
- )
- )
- ; runs the game
- ; turn is:
- ; 0 for start of the game
- ; 1 for AI's turn
- ; 2 for player's turn
- ; 3 for end of round
- (define run-game
- (lambda (state turn)
- (let* ((winner (check-winner state (= turn 3)))
- (pack (car state))
- (hands (cadr state))
- (ai-state (caddr state))
- (round (cadddr state)))
- (cond
- ((= turn 0) ; start of round
- (let* ((hand1 (list (caddr pack) (car pack)))
- (hand2 (list (cadddr pack) (cadr pack)))
- (pack (cddddr pack))
- (hands (list hand1 hand2))
- (round (+ round 1))
- (state (list pack hands ai-state round)))
- (display "\n====================\n")
- (display "Round ")
- (display round)
- (display "\n====================\n\n")
- (run-game state 1)
- )
- )
- (winner ; end of game?
- (begin
- (display "Winner: ")
- (display winner)
- (newline)
- (display "Play again? (y/n): ")
- (if (eq? (read) 'y)
- (run-game state 0)
- )
- )
- )
- ((= turn 1) ; AI's turn
- (move-ai state))
- ((= turn 2) ; player's turn
- (move-player state))
- )
- )
- )
- )
- ; check if any player busts, or who wins if the game is over
- (define check-winner
- (lambda (state over)
- (let* ((pack (car state))
- (hands (cadr state))
- (hand1 (car hands)) ; player's hand
- (hand2 (cadr hands)) ; AI's hand
- (sum1 (sum-hand hand1))
- (sum2 (sum-hand hand2)))
- (show-hands hands)
- (cond
- ((> sum1 21) ; player busts, AI wins
- (begin
- (display "Player busts!\n")
- 'AI))
- ((> sum2 21) ; AI busts, player wins
- (begin
- (display "AI busts!\n")
- 'PLAYER))
- ((or (null? pack) over) ; pack finished or game over
- (cond
- ((> sum1 sum2) 'PLAYER)
- ((< sum1 sum2) 'AI)
- (else 'DRAW)
- )
- )
- (else #f) ; game not over yet
- )
- )
- )
- )
- ; do a move for the AI
- (define move-ai
- (lambda (state)
- (let* ((pack (car state))
- (hands (cadr state))
- (hand1 (car hands))
- (hand2 (cadr hands))
- (ai-state (caddr state))
- (round (cadddr state))
- (r (do-ai-strategy hand1 hand2 ai-state))
- (x (car r))
- (new-ai-state (cadr r)))
- (cond
- ((eq? x 'hit) (display ">>> AI: Hit!\n"))
- ((eq? x 'stand) (display ">>> AI: Stand!\n"))
- )
- (cond
- ((eq? x 'hit) (run-game (list (cdr pack) (list hand1 (cons (car pack) hand2)) new-ai-state round) 1))
- ((eq? x 'stand) (run-game (list pack (list hand1 hand2) new-ai-state round) 2))
- (else (display "AI tries to cheat with an invalid move!\n"))
- )
- )
- )
- )
- ; do a move for the player
- (define move-player
- (lambda (state)
- (let* ((pack (car state))
- (hands (cadr state))
- (hand1 (car hands))
- (hand2 (cadr hands))
- (ai-state (caddr state))
- (round (cadddr state))
- (x (read-move)))
- (cond
- ((eq? x 'hit) (display ">>> Player: Hit!\n"))
- ((eq? x 'stand) (display ">>> Player: Stand!\n"))
- )
- (cond
- ((eq? x 'hit) (run-game (list (cdr pack) (list (cons (car pack) hand1) hand2) ai-state round) 2))
- ((eq? x 'stand) (run-game state 3))
- ((eq? x 'surrender) (display "Game over\n"))
- )
- )
- )
- )
- ; show hands
- (define show-hands
- (lambda (hands)
- (display "### Player's hand: ")
- (show-hand (car hands))
- (display "### AI's hand: ")
- (show-hand (cadr hands))
- )
- )
- ; show a hand
- (define show-hand
- (lambda (hand)
- (map
- (lambda (h)
- (display (car h))
- (display (cadr h))
- (display " ")
- )
- hand
- )
- (display "=> ")
- (display (sum-hand hand))
- (newline)
- )
- )
- ; sum hand
- (define sum-hand
- (lambda (hand)
- (let* ((l (sort (map car hand) <))
- (s (apply + l)))
- (if (and (< s 13) (not (null? l)) (= (car l) 1))
- (let* ((l (cdr l))
- (s (+ s 9))) ; count first ace as 10 points
- (if (and (< s 13) (not (null? l)) (= (car l) 1))
- (+ s 9) ; count second ace as 10 points too
- s ; only one ace, or more aces but treating all except the first as 1 point
- )
- )
- s ; no ace, or ace but treating it as 1 point
- )
- )
- )
- )
- ; wait for a move from the player (either 'hit or 'stand)
- (define read-move
- (lambda ()
- (display "Enter player's move (hit, stand, exit): ")
- (let ((x (read)))
- (cond
- ((or (eq? x 'hit) (eq? x 'stand)) x)
- ((eq? x 'exit) 'exit)
- (else (begin (display "Invalid move!\n") (read-move)))
- )
- )
- )
- )
- ; generate a pack of cards for Blackjack
- ; suit encoding: Spades, Hearts, Diamonds, Clubs
- (define generate-pack
- (lambda ()
- (let add-cards ((n 11)
- (suits '())
- (pack '()))
- (if (<= n 0)
- pack
- (if (null? suits)
- (add-cards (- n 1) '(S H D C) pack)
- (add-cards n (cdr suits) (cons (list n (car suits)) pack))
- )
- )
- )
- )
- )
- ; do a special cut on the pack at the specified index
- (define cut-pack
- (lambda (pack n)
- (let do-cut-pack ((pack pack)
- (rest '())
- (n n))
- (if (<= n 0)
- (append pack rest)
- (do-cut-pack (cdr pack) (cons (car pack) rest) (- n 1))
- )
- )
- )
- )
- ; shuffle the pack
- (define random-shuffle
- (lambda (pack)
- (let do-random-shuffle ((pack pack)
- (n 1000))
- (if (<= n 0)
- pack
- (do-random-shuffle (cut-pack pack (random (length pack))) (- n 1))
- )
- )
- )
- )
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement