Slots
January 14, 2011
We begin by defining the images on the wheels of the slot machines and displaying instructions to the user:
(define wheel #("BAR" "BELL" "ORANGE" "LEMON" "PLUM" "CHERRY"))
(define (display-instructions)
(display "WELCOME TO THE CASINO") (newline)
(display "BET IN INCREMENTS OF $1 FROM $1 TO $100") (newline)
(display "BET $0 WHEN YOU ARE FINISHED") (newline))
Pull emulates a single pull on the handle, with a bet of n dollars. The three wheels are spun and displayed, then the five possible outcomes are tested, a message is displayed to the user, and the gain or loss on the pull is returned:
(define (pull n)
(let ((x (randint 6)) (y (randint 6)) (z (randint 6)))
(display (vector-ref wheel x)) (display " ")
(display (vector-ref wheel y)) (display " ")
(display (vector-ref wheel z)) (newline)
(cond ((= x y z 0)
(let ((d (* 101 n)))
(display "***JACKPOT***") (newline)
(display "YOU WIN $") (display d) (newline) d))
((= x y z)
(let ((d (* 11 n)))
(display "***TOP DOLLAR***") (newline)
(display "YOU WIN $") (display d) (newline) d))
((or (= x y 0) (= x z 0) (= y z 0))
(let ((d (* 6 n)))
(display "***DOUBLE BAR***") (newline)
(display "YOU WIN $") (display d) (newline) d))
((or (= x y) (= x z) (= y z))
(let ((d (* 3 n)))
(display "***DOUBLE***") (newline)
(display "YOU WIN $") (display d) (newline) d))
(else (display "YOU LOSE $") (display n) (newline) (- n)))))
Play manages a game. It displays instructions, then repeatedly gets a bet, error-checks the input, pulls the handle, and reports status. When the user places a $o bet it displays the final status:
(define (play)
(display-instructions)
(display "ENTER YOUR BET: ")
(let loop ((bet (read)) (purse 0))
(cond ((or (not (integer? bet)) (negative? bet))
(display "ENTER YOUR BET: ")
(loop (read) purse))
((< 100 bet)
(display "HOUSE LIMIT $100") (newline)
(display "ENTER YOUR BET: ") (loop (read) purse))
((<= 1 bet 100)
(let* ((p (pull bet)) (purse (+ p purse)))
(cond ((positive? purse)
(display "YOU HAVE $") (display purse))
((negative? purse)
(display "YOU OWE $") (display (- purse)))
(else (display "YOU ARE EVEN")))
(newline) (display "ENTER YOUR BET: ")
(loop (read) purse)))
((negative? purse)
(display "PLACE $") (display (- purse))
(display " ON THE KEYBOARD") (newline))
((positive? purse)
(display "COLLECT $") (display purse)
(display " FROM THE CASHIER") (newline))
(else (display "YOU BROKE EVEN") (newline)))))
Here’s a sample game:
> (play)
WELCOME TO THE CASINO
BET IN INCREMENTS OF $1 FROM $1 TO $10
BET $0 WHEN YOU ARE FINISHED
ENTER YOUR BET: 10
BAR PLUM LEMON
YOU LOSE $10
YOU OWE $10
ENTER YOUR BET: 10
BELL ORANGE ORANGE
***DOUBLE***
YOU WIN $30
YOU HAVE $20
ENTER YOUR BET: 10
BAR BAR CHERRY
***DOUBLE BAR***
YOU WIN $60
YOU HAVE $80
ENTER YOUR BET: 10
ORANGE ORANGE BAR
***DOUBLE***
YOU WIN $30
YOU HAVE $110
ENTER YOUR BET: 10
LEMON PLUM ORANGE
YOU LOSE $10
YOU HAVE $100
ENTER YOUR BET: 10
BELL LEMON BELL
***DOUBLE***
YOU WIN $30
YOU HAVE $130
ENTER YOUR BET: 10
CHERRY LEMON PLUM
YOU LOSE $10
YOU HAVE $120
ENTER YOUR BET: 0
COLLECT $120 FROM THE CASHIER
We used randint from the Standard Prelude. You can run the program at http://programmingpraxis.codepad.org/A8iRnYpJ.
[…] today’s Programming Praxis exercise, our goal is to create a game that simulates a slot machine. […]
My Haskell solution (see http://bonsaicode.wordpress.com/2011/01/14/programming-praxis-slots/ for a version with comments):
import Control.Monad import Data.List import System.Random import Text.Printf import Text.Read.HT pull :: Int -> IO Int pull n = do ws <- replicateM 3 $ randomRIO (0,5) putStrLn . unwords $ map (wheel !!) ws result . group $ sort ws where wheel = words "BAR BELL ORANGE LEMON PLUM CHERRY" result [[0,0,0]] = win "JACKPOT" 101 result [_] = win "TOP DOLLAR" 11 result [[0,0],_] = win "DOUBLE BAR" 6 result [_,_] = win "DOUBLE" 3 result _ = printf "YOU LOSE $%d\n" n >> return (-n) win msg d = printf "***%s***\nYOU WIN $%d\n" msg (n*d) >> return (n*d) prompt :: IO Int prompt = do putStr "ENTER YOUR BET: " maybe prompt check . maybeRead =<< getLine where check bet | bet < 0 = prompt | bet > 100 = putStrLn "HOUSE LIMIT $100" >> prompt | otherwise = return bet main :: IO () main = instructions >> loop 0 where instructions = putStrLn "WELCOME TO THE CASINO\n\ \BET IN INCREMENTS OF $1 FROM $1 TO $100\n\ \BET $0 WHEN YOU ARE FINISHED" loop purse = prompt >>= \bet -> if bet == 0 then quit purse else fmap (+ purse) (pull bet) >>= \n -> status n >> loop n status n | n > 0 = printf "YOU HAVE $%d\n" n | n < 0 = printf "YOU OWE $%d\n" (-n) | otherwise = putStrLn "YOU ARE EVEN" quit total | total > 0 = printf "COLLECT $%d FROM THE CASHIER\n" total | total < 0 = printf "PLACE $%d ON THE KEYBOARD\n" (-total) | otherwise = putStrLn "YOU BROKE EVEN"My Python solution. Like the Haskell above, I factored out the
_winprocedure. I'm not terribly happy with the maze of ifs and elifs my code grew
into, but it'll do.
#!/usr/bin/env python
from random import randrange
WHEEL = ["BAR", "BELL", "ORANGE", "LEMON", "PLUM", "CHERRY"]
def display_instructions():
print "WELCOME TO THE CASINO"
print "BET IN INCREMENTS OF $1 FROM $1 TO $100"
print "BET $0 WHEN YOU ARE FINISHED"
return
def pull(n):
def _win(msg, d):
print "***{0}***".format(msg)
print "YOU WIN ${0}".format(n * d)
return n * d
x, y, z = randrange(6), randrange(6), randrange(6)
print WHEEL[x], WHEEL[y], WHEEL[z]
if x == y == z == 0:
return _win("JACKPOT", 101)
elif x == y == z:
return _win("TOP DOLLAR", 11)
elif x == y == 0 or x == z == 0 or y == z == 0:
return _win("DOUBLE BAR", 6)
elif x == y or x == z or y == z:
return _win("DOUBLE", 3)
else:
print "YOU LOSE ${0}".format(n)
return -n
def play():
display_instructions()
bet, purse = 1, 0
while bet != 0:
bet = raw_input("ENTER YOUR BET:\t")
try:
bet = int(bet)
except ValueError:
continue
if bet > 100:
print "HOUSE LIMIT $100"
continue
elif 1 <= bet <= 100:
purse += pull(bet)
if purse > 0:
print "YOU HAVE ${0}".format(purse)
elif purse < 0:
print "YOU OWE ${0}".format(-purse)
else:
print "YOU ARE EVEN"
if purse < 0:
print "PLACE ${0} ON THE KEYBOARD".format(-purse)
elif purse > 0:
print "COLLECT ${0} FROM THE CASHIER".format(purse)
else:
print "YOU BROKE EVEN"
return
if __name__ == "__main__":
play()
Oh no! I had a couple typos (messed up closing the code tag, and extra ” in ) in the comment above. Apologies!
Waddling through old code is fun, but I feel this exercise isn’t all it could have been. Slot machines are based on interesting statistical models that keep the game addictive while ensuring the House wins. In that vein, I modified the original task and created a weighted slot machine. I know it doesn’t earn me brownie points, but I hope someone finds it interesting or fun.
I also took the betting out of it so I can just hit the spin key mindlessly, like on a real machine :)
http://paste.lisp.org/display/119226
… incidentally, selecting a random wheel stop is a variant of the algorithm for selecting fortunes from the exercise #192.