In info file (look about setup M2000) there is a newer vertsion of BlackJack wich using layer above console (change only the interface). Image of the new version module BJ in info (info.gsb)
So the code below run only in one layer (console).
This code has 417 lines of code, written with advanced techniques. As the game go on, hands may added because of split option (two same cards in one hand can work as one card for two hands, and if a third is same as the others we can split it also, and more if happen). Also we have standard bet 100 credits, but there is an option for doubling down, means double bet for one card more (we can make any hand from splits, if rule for doubling down holds).
So we have only one array for players. But this array has objects from a class PlayerJb
About this class. A class is a factory for Group objects. There aren't private members, for this class not needed. Only class members, after class: label. These members exist only in when "factory" produce the group. So Module PlayerJb is the module called as constructor. So here we ask for a PlayerMoney (see dot before name). Inner class is a function too. Has a class: label too. PlayerGame module is the constructor. We pass two values, the player hand's value and the current bet., also there is a need for storing sometime the last card (when had Face Down, in Doubling down). OneCard is a class also, a global one. Class PlayerJB is global by default. But class PlayrGame is member of PlayerJB only.
Groups no need any class to use them. Inventory PlayerCards just hold the last hand (from splits perhaps), but here not used extensive (exist for future plan). There are two groups made them form OneCard class, the standard Bet, PlayerMoney (without a value, get 0 by default), Playervalue (an accumulator for the hand, of cards), a done flag (true means the player leave the game), and OldPlayerValues as a stack of values (here we place PlayerGame groups).
We use OldPlayerValues as FiFo, so we place objects of PlayerGame from bottom using Data command, and read from top (the older value). So each player may have a number of PlayerGames, and all of them are in a Stack Object. OldPlayerValues is a pointer to Stack, so if we pass this by value, we pass only the pointer. M2000 use a special object to hold such objects. So each time we copy the variable with the pointer to "Container" such as the Stack of values, a new pointer object produced to point to container.
Class
PlayerJB {
Class
PlayerGame {
Playervalue,
Bet
OneCard
LastCard
Class:
Module
PlayerGame {
Read
.Playervalue,
.Bet
If
Not Empty Then
Read
.LastCard
}
}
Inventory
queue PlayerCards
OneCard
PlayerFaceUp2nd,
SplitCard
Bet=100,
PlayerMoney
Playervalue
OldPlayerValues=Stack
Done=false
Class:
Module
PlayerJb (.PlayerMoney)
{}
}
We can change NoPlayers from 1 to whatever...
NoPlayers=4
\\
Dealer get one hidden And one open Card
\\ Player's get two open
cards, one at a time
\\ Options for Split and Double Down
\\
If Player has a BlackJack then dealer play for 21, changing cards for
other players/splits
\\ Standard Bet 100 credits. Each
player start with 10000 credits
Font
"Arial"
Form
50,40
Form \\
cut border
Cls
7
Print $(4)
Inventory
Suits =
"♠":=0,
"♥":=4,
"♦":=4,
"♣":=0
'suit -> color
Inventory
Cards =
"two":=2,
"three":=3,
"four":=4,
"five":=5
Append
Cards,
"six":=6,
"seven":=7,
"eight":=8,
"nine":=9
Append
Cards,
"ten":=10,
"jack":=10,
"queen":=10,
"king":=10,
"ace":=1
\\
We use Module because each module has own use of dots..
\\ And
we call it inside a For Object {} And outside of
it
DealerMoney=0
Module
PrintCardOnly (k,
Suits,
Cards)
{
For
k {
Pen
Suits(.suit!)
{
Print
Part @(10),
Eval$(Suits,
.suit)+Eval$(Cards,
.card)
Print
}
}
}
'
Using a stack object
StackPack
= Stack
Module
AppendArray (N,
A)
{
Stack
N {Data
!A}
}
Class
OneCard {
suit=-1,
Card
Class:
Module
OneCard {
\\
? for optional reading
read
? .suit,
.card
}
}
\\ 3X52 cards
Dim
Pack(Len(Cards)*Len(Suits)*(NoPlayers+1))
\\ Not used here =OneCard()
Pen
1
Double
Pen
14 {Report
2, "BlackJack"}
Normal
Cls,
2
k=0
\\
fill cards to Pack()
For
times=NoPlayers+1
To 1 {
N=each(Suits)
While
N
{
M=each(Cards)
While
M
{
Pack(k)=OneCard(N^,
M^)
k++
}
}
}
Rem
: DisplayAll() '
in order
Suffle()
Rem
: DisplayAll() '
at random positions
Print
'
first cut for player
Print
"Make a Cut: 0-51:";
Repeat
{
N1=Random(0,51)
Try
{
Input
! N1,
10
}
Stack
StackPack {
Drop
N1
}
}
Until N1>=0
And N1<=51
Print
N1
\\ used to pass the Dealer's hidden
Card
Hidden=OneCard()
DealerHidden=OneCard()
Class
PlayerJB {
Class
PlayerGame {
\\
Class is a Group Factory - a function whuch return
Group
\\
Class Definition in a Group is local else is Global
\\
until erased when Definition Holder exit or end (a Module/Function
where we define a class)
Playervalue,
Bet
\\
we can define groups using class like this if class constructor work
without parammeters
OneCard
LastCard
Class:
\\
Class: means that this module exist only at construction
stage
Module
PlayerGame {
'
This module as part of constructor
'
so has own stack when called as constructor
Read
.Playervalue,
.Bet
If
Not Empty Then
Read
.LastCard
}
}
Inventory
queue PlayerCards
OneCard
PlayerFaceUp2nd,
SplitCard
Bet=100,
PlayerMoney
Playervalue
OldPlayerValues=Stack
Done=false
Class:
Module
PlayerJb (.PlayerMoney)
{}
}
Dim
Base 1,
Players(NoPlayers)=PlayerJB(10000)
Def
Val$(x)=If$(x=-1
-> "Black
Jack",
Str$(x,""))
Card=OneCard()
Function
ClearCards {
Inventory
queue
ClearCards
=ClearCards
}
Function
PlayerHasNoBlackJack (HasTheDealer)
{
' we get two
parameters
If
Not HasTheDealer
Then Exit '
the second parameter droped from stack
'
now we read 2nd
Read
k
Def
Range(X, X1,
X2)=X>=X1
and X<=X2
m=false
If
k.PlayerCards(0!).card=12
And Range(k.PlayerFaceUp2nd.card,8
,11) Then
m=m
or true
If
k.PlayerFaceUp2nd.card=12
And Range(k.PlayerCards(0!).card,8
,11) Then
m=m
or true
=Not
m
}
Repeat
{
For
i=1 to
NoPlayers {
For
Players(i)
{
.SplitCard=OneCard()
.OldPlayerValues=Stack
if
.done Then
Exit
If
.PlayerMoney<.Bet
Then
{
Print
Format$("Player({0}), you run out
of money...Bye Bye",
i)
.done=true
}
Else
{
Print
format$("Player({0}) Money:",i),
.PlayerMoney
Print
"Play Game ?(Y/N)"
If
Key$ ~
"[NnΝν]" Then
.done=true
}
}
}
AllPlayers=NoPlayers
BlackJack=false
PlayersBurst=0
Clear
dealervalue
DealerCards=ClearCards()
For
i=1 to
NoPlayers {
For
Players(i) {
If
.done Then
AllPlayers-- :
Exit
Clear
.playervalue
.PlayerCards=ClearCards()
Print
Format$("Player {0} Hand: 1st
Card",
i)
PlayerCard(&.playervalue,
.PlayerCards)
}
}
If
AllPlayers=0 Then
Print "No More Players" :
Exit
Print
"Dealer Hand: 1st Card"
DealerCard(&dealervalue)
For
i=1 to
NoPlayers {
If
Not Players(i).done
Then
{
Print
Format$("Player {0} Hand: 2nd
Card", i)
For
Players(i)
{
NextCard()
.PlayerFaceUp2nd<=Card
PrintCardOnly
Card,
Suits,
Cards
}
}
}
Print
"Dealer Hand: 2nd Card"
NextCard()
Print
@(10),
"Face Down Card"
DealerHidden=Card
'
now If dealer face up Card is Ace or 10 or Figure can see If has a
black jack
N2=Cards(Card.card!)
If
N2=10 And
Cards(DealerCards(0!).card!)=1
Then
DealerBlackJack()
If
N2=1 And
Cards(DealerCards(0!).card!)=10
Then
DealerBlackJack()
For
i=1 to
NoPlayers {
If
Not Players(i).done
Then
{
If
PlayerHasNoBlackJack(BlackJack,
Players(i)) Then
For Players(i) {.PlayerMoney-=.Bet
: DealerMoney+=.Bet}
: Exit
For
Players(i)
{
Bet=.Bet
Again:
Print
format$("Player {0} Play",
i)
if
.PlayerCards(0!).card=.PlayerFaceUp2nd.card
Then
{
If
.PlayerMoney<2*.Bet
Then
exit
Print
"Split Cards ?(Y/N)"
If
Key$ ~
"[NnΝν]" Then
Exit
AllPlayers++
.SplitCard<=.PlayerFaceUp2nd
NextCard()
.PlayerFaceUp2nd<=Card
Stack
.OldPlayerValues
{Push .PlayerGame(.playervalue,
Bet)}
}
Print
"Player
Hand:"
Hidden=.PlayerFaceUp2nd
:
.PlayerFaceUp2nd<=OneCard()
PrintCardOnly
.PlayerCards(0!),
Suits,
Cards '
show first
Card
PlayHand(.PlayerCards,&.playervalue,
False, False,
.PlayerMoney)
'
first we get
Bet
.PlayerMoney-=Bet
DealerMoney+=Bet
Print
If
.playervalue>21
Then
{
PlayersBurst++
Print
"Dealer Win"
}
else.if .playervalue=-1
Then
{
'
dealer has to play with player
now
PlayersBurst++
Print
Format$("Dealer play against
Player({0})",i)
PrintCardOnly
DealerCards(0!),
Suits,
Cards
Hidden=DealerHidden
: DealerHidden=OneCard()
\\
? means undefined
value
PlayHand(DealerCards,&dealervalue,
true, true,
?)
If
dealervalue<>21 Then
{
Print
"Player Win",
Bet*3/2 : .PlayerMoney+=Bet*5/2
' one we get
before
DealerMoney-=Bet*5/2
}
Else
{
Print
"Dealer Win"
}
If
PlayersBurst<AllPlayers
Then
{
Clear
dealervalue,
DealerCards
'
dealer take two cards to play with
others
Print
"Dealer Hand: 1st
Card"
DealerCard(&dealervalue)
Print
"Dealer Hand: 2nd
Card"
NextCard()
Print
@(10),
"Face Down
Card"
DealerHidden=Card
'
now If dealer face up Card is Ace or 10 or Figure can see If has a
black
jack
N2=Cards(Card.card!)
If
N2=10 And
Cards(DealerCards(0!).card!)=1
Then
DealerBlackJack()
If
N2=1 And
Cards(DealerCards(0!).card!)=10
Then
DealerBlackJack()
}
}
'
Data push to end of stack
'
Push push to top of stack
'
Read read always from top
If
.SplitCard.suit<>-1
Then
{
Card=If(Bet>.Bet
->
.PlayerCards((Len(.PlayerCards)-1)!),
OneCard())
Stack
.OldPlayerValues
{Data .PlayerGame(.playervalue,
Bet, Card)
: Read
NextGame}
Bet=NextGame.Bet
Drop
.PlayerCards
Len(.PlayerCards)
' erase all
cards
Append
.PlayerCards,
"Split":=.SplitCard
'.playervalue=Cards(.SplitCard.Card!) '
this is the
same
.playervalue=NextGame.playervalue
NextCard()
.PlayerFaceUp2nd<=Card
.SplitCard.Suit=-1
Goto
Again
}
Card=If(Bet>.Bet
->
.PlayerCards((Len(.PlayerCards)-1)!),
OneCard())
Stack
.OldPlayerValues
{Data .PlayerGame(.playervalue,
Bet,
Card)}
}
}
}
If
PlayersBurst<AllPlayers
And Not BlackJack
Then
{
Print
"Dealer Play"
PrintCardOnly
DealerCards(0!),
Suits,
Cards
Hidden=DealerHidden
:
DealerHidden=OneCard()
PlayHand(DealerCards,&dealervalue,
true, false, ?)
Pen
5 {
Print
"Table Results"
For
i=1 to
NoPlayers {
For
Players(i) {
Repeat
{
If
.done then
exit
Stack
.OldPlayerValues
{ Read
NextGame
}
playervalue=NextGame.playervalue
Bet=NextGame.Bet
If
Not playervalue=-1
Then
{
If
Bet>.Bet
then
{
Print
"Face Up
Card"
PrintCardOnly
NextGame.LastCard,
Suits,
Cards
}
If
playervalue>21 Then
{
Print
Format$("Dealer Win Player({0})",
i)
}
Else.If
dealervalue>playervalue
And dealervalue<22
Then
{
Print
Format$("Dealer Win Player({0})",
i)
}
Else.If
dealervalue>21
Or dealervalue<playervalue
Then
{
Print
Format$("Player({0}) Win Dealer",
i)
.PlayerMoney+=Bet*2
DealerMoney-=Bet*2
}
Else
{
Print
Format$("Player({0}) keep Bet for
next time",
i)
.PlayerMoney+=Bet
DealerMoney-=Bet
}
Print
format$("Player({0}): {1} Dealer:
{2}", i,
Val$(playervalue),
Val$(dealervalue))
}
}
Until
Len(.OldPlayerValues)=0
}
}
}
}
} Always
Print
"Dealer Money:",
DealerMoney
End
Sub
Suffle()
Print
Local
N=Len(Pack())-1,
N2, i,
j,
total=N*4+4,
cur=1
For
j=1 To
4 {
For
i=0 To
N {
If
cur Mod 4=3
Then Print Over format$("Suffle
{0:0}%",cur/total*100)
N2=random(0,
N)
While
N2=i
{N2=random(0,
N)}
Swap
Pack(i),
Pack(N2)
cur++
}
}
AppendArray
StackPack,
Pack()
Print
End
Sub
Sub
DisplayAll()
For
k=0 To
Len(Pack())-1
{
PrintCard(k)
}
End
Sub
Sub
PrintCard(k)
For
Pack(k) {
Pen
Suits(.suit!)
{
Print
Eval$(Suits,
.suit)+Eval$(Cards,
.card),
}
}
End
Sub
Sub
NextCard()
If
Len(StackPack)=0
Then
{
Suffle()
Stack
StackPack {
Drop
Random(0,
51)
}
}
Stack
StackPack {
Read
Card
}
End
Sub
Sub
PlayerCard(&acc,
MyCards)
NextCard()
PrintCardOnly
Card,
Suits,
Cards
acc+=Cards(Card.Card!)
Append
MyCards,
len(MyCards):=Card
End
Sub
Sub
DealerCard(&acc)
NextCard()
PrintCardOnly
Card,
Suits,
Cards
acc+=Cards(Card.Card!)
Append
DealerCards,
len(DealerCards):=Card
End
Sub
Sub
PlayHand(MyCards, &acc,
nomessage,
sorryblackjack)
'
Optional - We have to pass a ? if we have module or Sub
Read
? MyMoney
Local
N2,
morevalues=0,
ok,
Card=OneCard(),
DoublingDown
If
MyCards(0!).card=12
Then
morevalues=10
Repeat
{
If
Hidden.suit>=0 Then
{
N2=Hidden.card
PrintCardOnly
Hidden,
Suits,
Cards
Append
MyCards,
Len(MyCards):=Hidden
Hidden=OneCard()
}
Else
{
NextCard()
If
DoublingDown Then
{
Print
@(10),
"Face Down Card"
}
Else
{
PrintCardOnly
Card,
Suits,
Cards
}
N2=Card.Card
Append
MyCards,
Len(MyCards):=Card
}
If
N2=12 Then
{
If
morevalues=0 Then
{
morevalues=10
}
Else N2=13
: morevalues=-50
}
If
acc=10 And
N2=12 And
Len(MyCards)=2
Then
acc=-1: Pen
15 {Print
"BlackJack" }: Exit
If
morevalues>0
And Cards(if(N2<13
-> N2,
1)!)=10
And Len(MyCards)=2
Then
acc=-1: pen
15 {Print
"BlackJack" } :
Exit
If
N2<=12 Then
{
acc+=Cards(N2!)
}
Else
acc+=11
If
acc>21
And Not DoublingDown
Then Print
"Busting" :
Exit
If
acc=21 Then
Exit
If
nomessage Then
{
If
sorryblackjack Then
{
ok=acc>20
Or
acc+morevalues=21
} Else
ok=acc>16
Or (acc+morevalues<22
And acc+morevalues>16)
}
Else
{
If
DoublingDown then
ok=True
: Exit
If
Len(MyCards)=2
then if
acc=9 or
acc=10 or
acc=11 And
acc+morevalues<>21
then
DoublingDown=true
If
DoublingDown then
{
If
MyMoney>=2*Bet
Then
{
Print
"Doubling Down
?(Y/N)"
DoublingDown=Not
Key$ ~
"[NnΝν]"
}
Else
DoublingDown=False
}
If
DoublingDown Then
{
'
get a card Face
Down
Bet*=2
ok=false
}
Else
{
Print
Part "Stand or Hit
?(S/H)"
ok=Key$
~
"[SsΣσ]"
}
}
}
Until
ok
If
acc=-1 Then
morevalues=0
While
morevalues>0 {
If
acc+morevalues<22
Then
Exit
morevalues-=10
}
If
morevalues<0 Then
Exit Sub
acc+=morevalues
End
Sub
Sub
DealerBlackJack()
Pen
15 {Print
"BlackJack" }
PrintCardOnly
Card,
Suits,
Cards
Print
"Face Up Card"
Print
"Dealer Win All"
BlackJack=True
End
Sub