Πέμπτη 28 Δεκεμβρίου 2017

Αναθεώρηση 35 (Έκδοση 9.0)

Μια μικρή διόρθωση για την τελική έκδοση. Ένα μικρό bug έκανε το Exit (Έξοδος) σε μια συνάρτηση εξυπηρέτησης γεγονότων να δώσει λάθος (Στις τελευταίες εκδόσεις είχα βάλει ένα σύστημα να δείχνει λάθη σε τέτοιες συναρτήσεις, οι οποίες καλούνται από το σύστημα παραθύρων, και εκεί περίμενα ένα <>1 αριθμό αλλά αυτό ήταν λάθος, για το Exit, και η μόνη λύση ήταν να μπει ένα μπλοκ ΔΕΣ { } ή Try {} που "έτρωγε" την κατάσταση και έδινε το 1. Τώρα η αλλαγή έχει το =0 που τότε είναι το λάθος).
Επίσης διορθώθηκε και η Εισαγωγή ! Α, 20 όπου αν το Α δεν είχε οριστεί και δίναμε το Enter χωρίς τιμή το Α έπαιρνε τιμή 20 ενώ το 20 είναι το όρισμα για το μέγεθος πεδίου στην οθόνη για την εισαγωγή του Α.


Δευτέρα 25 Δεκεμβρίου 2017

BlackJack Version 3 (M2000 code)

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