Blackjack - A Solution to 2005 Project Two
; CS 130 Project Two - Fall, 2005
; Blackjack problem from 2005 ACM Regional Programming Contest
INCLUDE Irvine16.inc
.DATA;
IntArray WORD 1000 DUP (?)
Greeting BYTE "Welcome to Las Vegas Blackjack Game." , 0
Prompt BYTE "Enter the array of integers (ending with 0)." , 0
ErrMessage BYTE "ERROR: integer out of allowable range." , 0
DeckMessage BYTE "Deck number " , 0
WonMessage BYTE "Number of games won: " , 0
LostMessage BYTE "Number of games lost: " , 0
TiedMessage BYTE "Number of games tied: " , 0
OptCaseMes BYTE "OptCase = " , 0
OptExtraMes BYTE "OptExtra = " , 0
OptDealtMes BYTE "OptDealt = " , 0
DeckCounter WORD 0
HouseScore WORD ?
PlayerScore WORD ?
HouseHasAce WORD ?
PlayerHasAce WORD ?
DeckSize WORD ?
FirstCardIndex WORD ?
TooFarIndex WORD ?
OptExtra WORD ?
OptCase WORD ?
OptDealt WORD ?
NumSkip WORD ?
NumExtra WORD ?
NumDealt WORD ?
NumWon WORD ?
NumLost WORD ?
NumTied WORD ?
.CODE
MAIN PROC
mov ax, @data
mov ds, ax
call CrLf
mov dx, OFFSET Greeting
call WriteString
call CrLf
call CrLf
call ReadArray
call CheckArray
call ProcessArray
exit
MAIN ENDP
ReadArray PROC
; Load IntArray with user input until receiving a zero.
push dx
push ax
push si
mov dx, OFFSET Prompt
call WriteString
call CrLf
call CrLf
mov si, 0
L1: call ReadInt
call CrLf
mov IntArray[si], ax
add si, 2
cmp ax,0
jne L1
pop si
pop ax
pop dx
ret
ReadArray ENDP
CheckArray PROC
; Check that data entered agrees with specs in project.
; Terminate program if not.
push si
mov si, 0
L1: cmp IntArray[si], 0
je quit
cmp IntArray[si], 500
ja err
mov cx,IntArray[si]
add si, 2
L2: cmp IntArray[si],0
je err
cmp IntArray[si],10
ja err
add si, 2
loop L2
jmp L1
quit: pop si
ret
err: mov dx, OFFSET ErrMessage
call WriteString
call CrLf
exit
CheckArray ENDP
ProcessArray PROC
; Process all data in the array. Simulate multiple Blackjack games
; using multiple decks.
push si
push ax
mov si, 0
lewp: mov ax, IntArray[si] ; get next deck size
cmp ax, 0 ; quit if zero
je done
call PlayDeck ; process a whole deck
inc ax
shl ax, 1
add si, ax ; skip ahead to next deck
jmp lewp ; loop back
done: pop ax
pop si
ret
ProcessArray ENDP
PlayDeck PROC
; Simulate playing several hands of Blackjack using same deck,
; until all cards have been used. Display results.
; Pre:
; SI = index for start of current deck
; Post:
; NumWon = # player wins
; NumLost = # player losses
; NumTied = # ties
; increment DeckCounter
push ax
push dx
mov NumWon, 0
mov NumLost, 0
mov NumTied, 0
mov NumSkip, 0
lewp: call FindBestPlay ; play a hand
cmp OptCase, 0 ; increment one of 3 counters
jl loss
jg win
inc NumTied
jmp skip
loss: inc NumLost
jmp skip
win: inc NumWon
skip:
mov ax, numSkip
add ax, optDealt
cmp ax, IntArray[si] ; IntArray[si] is deck size
jge done ; quit when whole deck has been used
mov NumSkip, ax ; otherwise loop back to play again,
jmp lewp ; dealing after last card previously dealt
done:
inc DeckCounter
call CrLf ; report tallies
mov dx, OFFSET DeckMessage
call WriteString
movsx eax, DeckCounter
call WriteInt
call CrLf
mov dx, OFFSET WonMessage
call WriteString
movsx eax, NumWon
call WriteInt
call CrLf
mov dx, OFFSET LostMessage
call WriteString
movsx eax, NumLost
call WriteInt
call CrLf
mov dx, OFFSET TiedMessage
call WriteString
movsx eax, NumTied
call WriteInt
call CrLf
pop dx
pop ax
ret
PlayDeck ENDP
FindBestPlay PROC
; Determine least number of extra cards player can draw in order
; to obtain best possible outcome (win, tie or loss).
; Pre:
; SI = index for start of current deck
; NumSkip = # cards to skip in deck before dealing
; Post:
; OptExtra = optimal # extra cards for player
; OptDealt = # cards dealt
; OptCase = -1 (loss), 0 (tie) or 1 (win)
push ax
push bx
mov NumExtra, 0
mov OptCase, -2
lewp: call PlayHand
cmp ax, OptCase
jle skip ; skip ahead unless we got better outcome
mov OptCase, ax ; record new optimal data
mov bx, NumExtra
mov OptExtra, bx
mov bx, NumDealt
mov OptDealt, bx
cmp ax, 1
je done ; quit if win was discovered
skip: cmp PlayerScore, 21
ja done ; quit if player went bust last time (cannot ...
; take extra cards after busting, right?)
; OOPS. BAD IDEA:
; mov bx, NumExtra
; inc bx
; cmp bx, IntArray[si]
; jae done ; quit when # extra cards becomes silly
inc NumExtra
jmp lewp ; otherwise, try again, taking more cards
done:
push dx ; diagnostic stuff
call CrLf
mov dx, OFFSET OptCaseMes
call WriteString
movsx eax, OptCase
call WriteInt
call CrLf
mov dx, OFFSET OptExtraMes
call WriteString
movsx eax, OptExtra
call WriteInt
call CrLf
mov dx, OFFSET OptDealtMes
call WriteString
movsx eax, OptDealt
call WriteInt
call CrLf
pop dx
pop bx
pop ax
ret
FindBestPlay ENDP
PlayHand PROC
; Simulate playing a hand of Blackjack using a given deck, starting to deal
; from a particular place in the deck, and having player take a specified
; number of extra cards.
;Pre:
;SI = index of the start of the deck (where # cards in deck is stored)
;NumSkip = number of cards to skip before dealing
;NumExtra = number of extra cards to be dealt to the player
;Post:
;ax = 1 (win for player), -1 (loss for player) or 0 (tie)
push cx
push si
mov NumDealt, 0
mov HouseHasAce,0
mov PlayerHasAce,0
mov HouseScore, 0
mov PlayerScore, 0
mov ax, IntArray[si]
mov DeckSize, ax ; how many cards in deck?
add si, 2
mov FirstCardIndex, si ; mark location of 1st card in deck
shl ax,1
add ax, si
mov TooFarIndex, ax ; mark location just beyond current deck
mov ax, NumSkip
shl ax, 1
add si, ax ; si now points to first card to be dealt
call DealPlayer ; now deal first four cards
call DealHouse
call DealPlayer
call DealHouse
mov cx, NumExtra ; now deal extra cards to player
cmp cx, 0
je houseLp
playrLp:call DealPlayer
loop playrLp
; now deal cards to house until 17
houseLp:mov ax,HouseHasAce ; skip ahead if house has an ace
cmp HouseHasAce, 1
je hasAce
cmp HouseScore, 17
jae stopDeal ; done dealing if 17 or over
jmp needMore ; haven't reached 17 yet, so deal
hasAce: cmp HouseScore, 17
jae stopDeal ; done dealing if 17 or over, else
cmp HouseScore, 12
jae needMore ; deal again if 12 to 16, else
cmp HouseScore, 7
jae stopDeal ; done dealing if 7 to 11 (because of ace),
; else deal again if 1 to 6
needMore:call DealHouse
jmp houseLp
StopDeal:
cmp PlayerScore, 11 ; if player's score is under 12...
ja skip1
cmp PlayerHasAce, 1 ; and if player holds an ace, then...
jne skip1
add PlayerScore, 10 ; add 10 to player's score
skip1: cmp HouseScore, 11 ; if house's score is under 12...
ja decision
cmp HouseHasAce, 1 ; and if house holds an ace, then...
jne decision
add HouseScore, 10 ; add 10 to house's score
decision:
cmp PlayerScore, 21
jbe skip2
cmp HouseScore, 21
ja tie ; tie if both went bust
jmp loss ; loss if only player went bust
skip2: cmp HouseScore, 21
jbe skip3
jmp win ; win if only house went bust
skip3: mov ax, PlayerScore
cmp ax, HouseScore ; if neither went bust, compare scores
je tie
jb loss
win: mov ax, 1
jmp done
loss: mov ax, -1
jmp done
tie: mov ax, 0
done: pop si
pop cx
ret
PlayHand ENDP
DealPlayer PROC
; Simulate dealing a card to player.
; Pre:
; SI = index of next card to be dealt
; Post:
; PlayerScore will be updated.
; Checks for ace and sets PlayerHasAce flag if so.
; Advance SI and check for wrap around.
; Increment NumDealt.
push ax
mov ax, IntArray[si]
add PlayerScore, ax
cmp ax, 1
jne S1
mov PlayerHasAce, 1
S1: add si, 2
cmp si, TooFarIndex
jne S2
mov si, FirstCardIndex
S2: inc NumDealt
pop ax
ret
DealPlayer ENDP
DealHouse PROC
; Simulate dealing a card to house.
; Pre:
; SI = index of next card to be dealt
; Post:
; HouseScore will be updated.
; Checks for ace and sets HouseHasAce flag if so.
; Advance SI and check for wrap around.
; Increment NumDealt.
push ax
mov ax, IntArray[si]
add HouseScore, ax
cmp ax, 1
jne S1
mov HouseHasAce, 1
S1: add si, 2
cmp si, TooFarIndex
jne S2
mov si, FirstCardIndex
S2: inc NumDealt
pop ax
ret
DealHouse ENDP
END MAIN
Here is what happened when I ran it with the test data:
C:\Masm615\Projects\proj2\mine>bj
Welcome to Las Vegas Blackjack Game.
Enter the array of integers (ending with 0).
10
1
2
3
4
5
6
7
8
9
10
13
8
4
9
1
4
9
2
10
7
3
1
4
4
20
4
6
3
7
10
1
5
5
6
10
1
8
4
4
10
9
2
2
1
5
0
OptCase = +0
OptExtra = +1
OptDealt = +7
OptCase = +0
OptExtra = +1
OptDealt = +5
Deck number +1
Number of games won: +0
Number of games lost: +0
Number of games tied: +2
OptCase = +1
OptExtra = +1
OptDealt = +8
OptCase = +0
OptExtra = +2
OptDealt = +8
Deck number +2
Number of games won: +1
Number of games lost: +0
Number of games tied: +1
OptCase = +1
OptExtra = +0
OptDealt = +5
OptCase = -1
OptExtra = +0
OptDealt = +5
OptCase = +1
OptExtra = +0
OptDealt = +5
OptCase = +1
OptExtra = +2
OptDealt = +7
Deck number +3
Number of games won: +3
Number of games lost: +1
Number of games tied: +0