Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

BlackJack (Card game)

edited December 12 in Questions Posts: 83

A Card games logic.
First here is the Logic of the Game.

- - BlackJack Planning Phase
- - Dealer Cards
- - Player Cards
- - Deal the Cards 
- - Display the Cards
- - Sum of the Dealer
- - Sum of the Player                        
- - Compare the sum of the Cards, D vs. P
- - The Rules
- - if P cards sum is > 21 = Bust 
- - if P cards sum is < 21 = Option : Hit or Stay
- - if Option P Stay compare of, D vs. P 
- - if P sum is < 2 and > D sum then P Wins !
- - if P sum is < D sum then P loses !

Comments

  • dave1707dave1707 Mod
    edited August 11 Posts: 6,392

    @kendog400 There are plenty of card game examples on the forum. Do a forum search to see what you can find.

  • dave1707dave1707 Mod
    Posts: 6,392

    @kendog400 Here's a start for your card game. Some code to create a deck of cards. You can alter this to create what you want.

    supportedOrientations(LANDSCAPE_ANY)
    displayMode(FULLSCREEN)
    
    function setup()
        rectMode(CENTER)
        creatDeck()
    end
    
    function draw()
        background(207, 228, 211, 255)
        for value=1,13 do
            for suit=1,4 do
                sprite(cards[suit][value],value*70,HEIGHT-suit*150)
            end
        end
    end
    
    function creatDeck()
        cards={}
        local pic={"♦️","♣️","♥️","♠️"}
        local val={"2","3","4","5","6","7","8","9","10","J","Q","K","A"}
        for s=1,4 do
            cards[s]={}
            for v=1,13 do
                img=image(50,70)
                setContext(img)
                fill(255)
                stroke(0, 235, 255, 255)
                strokeWidth(3)
                rect(25,35,50,70)  
                sprite("SpaceCute:Star",25,35,75)
                fontSize(13)
                text(pic[s],12,57)
                text(pic[s],38,13)
                fill(255,0,0)
                fontSize(25)
                text(val[v],25,35)
                setContext()
                cards[s][v]=img
            end
        end
    end
    
  • Posts: 83

    Thank You....

  • dave1707dave1707 Mod
    edited August 14 Posts: 6,392

    @kendog400 Here's a version based on what you show above. It's a total waste of Codea's capabilities, but it can be done. Press "h" for hit, "s" for stay, and "a" to play again. It's in portrait mode and you should slide the output window all the way up to show all of the print statements. I think it runs without errors, but I didn't test it that well.

    EDIT: Made minor change for dealer.

    supportedOrientations(PORTRAIT_ANY)
    
    function setup()
        showKeyboard()
        output.clear()
        player,dealer={},{}
        for z=1,2 do
            table.insert(player,math.random(11))
            table.insert(dealer,math.random(11))
        end   
        showPlayer(1)
    end
    
    function draw()
        background(0)
        fill(255)
        if ans=="s" then
            output.clear()
            showDealer()
            showPlayer(2)
            showWinner()        
        elseif ans=="h" then
            output.clear()
            table.insert(player,math.random(11))
            showPlayer(1)
        elseif ans=="a" then
            setup()
        end
        ans=""        
    end
    
    function showDealer()
        dealerSum=0
        for a=1,#dealer do
            dealerSum=dealerSum+dealer[a]
        end
        while dealerSum<17 do
            dealerSum=0
            table.insert(dealer,math.random(11))
            for a=1,#dealer do
                dealerSum=dealerSum+dealer[a]
            end
        end
        print("The dealer has a total of "..dealerSum)
        print("from these cards "..table.concat(dealer," "))
    end
    
    function showPlayer(a)
        playerSum=0
        for a=1,#player do
            playerSum=playerSum+player[a]
        end
        print("You have a total of "..playerSum)
        print("from these cards "..table.concat(player," "))
        if playerSum>21 then
            showWinner()
        elseif a==1 then
            print("\n\nDo you want to stay(s) or hit(h)") 
        end   
    end
    
    function showWinner()
        if playerSum>21 then
            print("Dealer wins!")
        elseif dealerSum>21 then
            print("You win!")
        elseif playerSum>dealerSum then
            print("You win!")
        else
            print("Dealer wins!")
        end
        print("Play again?(a)")
    end
    
    function keyboard(k)
        ans=k
    end
    
  • edited November 28 Posts: 83

    This is a snapshot picture, notice the Royality Image (Queen). This will be replaced with the picture of the card suit...

    IMG-0010.PNG 105.7K
  • edited November 28 Posts: 83

    ...

  • dave1707dave1707 Mod
    Posts: 6,392

    @kendog400 You have the correct logic, but some of your values are wrong. Here’s an updated version.

        if numAces==1 then
            if myValue+11>21 then
                myValue=myValue+1
            else
                myValue=myValue+11
            end
        elseif numAces==2 then
            if myValue+12>21 then
                myValue=myValue+2
            else
                myValue=myValue+12
            end
        elseif numAces==3 then
            if myValue+13>21 then
                myValue=myValue+3
            else
                myValue=myValue+13
            end
        elseif numAces==4 then
            if myValue+14>21 then
                myValue=myValue+4
            else
                myValue=myValue+14
            end
        end
    
  • edited November 28 Posts: 83

    ...

  • dave1707dave1707 Mod
    Posts: 6,392

    @kendog400 You’re missing code. The above code has errors.

  • edited November 28 Posts: 83

    Here is the PGM. Its a Main and three Classes...

  • edited November 28 Posts: 83

    ...

  • edited November 28 Posts: 83

    ...

  • edited November 28 Posts: 83

    ...

  • The card game is from Ignaz..

  • dave1707dave1707 Mod
    edited November 24 Posts: 6,392

    @kendog400 When you post code, use ~~~ before and after your code. You’re missing code at the end of the card class and you have errors in the other code.

  • edited November 28 Posts: 83

    ...

  • edited November 28 Posts: 83

    ...

  • dave1707dave1707 Mod
    edited November 25 Posts: 6,392

    self.suits={“♥️”,”♦️”,”♠️”,”♣️”} Not sure what’s happening. I thought maybe you couldn’t show the emojis, but they work for me.

  • edited November 28 Posts: 83

    ...

  • edited November 28 Posts: 83

    ...

  • edited November 28 Posts: 83

    ...

  • dave1707dave1707 Mod
    Posts: 6,392

    I don’t think there should be a tie. The dealer should always pick a card until they either win or loose. I you have trouble with your code, then you should go back before you made the changes and just make minor changes until you get it to work the way you want.

  • edited November 28 Posts: 83

    ...

  • edited November 28 Posts: 83

    ...

  • dave1707dave1707 Mod
    Posts: 6,392

    @kendog400 My suggestion is to re-edit your previous discussions and remove all the code and replace it with the text “Updated code below” and repost your completed finished code. That would remove all confusion about what’s good and what’s not.

  • edited November 28 Posts: 83

    This card game is orginally from Ignatz...
    Overall its a good game, but it does need fixin..
    It does have a few bugs, that need to be squashed...

  • edited December 11 Posts: 83

    The code for this BlackJack game will be done in four parts..
    The first is the main PGM..

    --BlackJack, Part #1
    function setup()
    
    --Image for back of card
    img=readImage("Documents:C_Back _1") 
    deal21() 
    end
    
    function touched(touch)       
    end
    
    --===== 21 ========
    function deal21()
        -- The remember function
        parameter.watch("Score")
        parameter.watch("bankScore")
        -- The buttons
        parameter.action("Hold", function() playBank() end)
        parameter.action("Another card", function() AddMyCard() end) 
        parameter.action("Play again",function() play21Again() end) 
        -- Card size
        c=Card(200,img)  
        -- Deck location in height 
        t=CardTable(10,HEIGHT-10,c,false,1,5.5)
        p=Pack()
        p:shuffle()
        Score=0
        bankScore=0
        cards=2
        for i=1,2 do
       -- Player hand location in height 
            local crd=t:dealCard(p,i,3.2,true) 
            Score=GetScore(Score,crd)
        end 
        status="PLAY"
    end
    
    function playBank()
        bankCards=2
        bankScore=0
        for i=1,2 do
            local crd=t:dealCard(p,i,1,true)
            bankScore=GetScore(bankScore,crd)
        end
        while bankScore<Score do
            bankScore=addBankCard()
        end
        if bankScore==Score then status="Tie Score"
          elseif bankScore>Score and bankScore<22then status="Lose" 
            elseif bankScore<Score or bankScore>21 then status ="Winner" end
    end
    
    function GetScore(score,crd)
        local i,j,v,s=c:SuitValue(crd.c)
        -- if the score is <= to 10 then Ace==11
        -- if the score is > 10 then Ace==1
       if v==1 then 
         if score<=10 then score=score+11 else score=score+1 end
            if score>21 then score=score+1 end
        else
            score=score+math.min(10,v)
        end
        return score
    end
    
    --Add cards for the player
    function AddMyCard()
        cards = cards + 1
        sound("Game Sounds One:Bell 2")
        local crd=t:dealCard(p,cards,3.2,true)
        Score=GetScore(Score,crd)
        if Score>21 then status="Busted" end
    end
    
    --Add cards for the dealer
    function addBankCard()
        bankCards = bankCards + 1
        sound("Game Sounds One:Menu Back")
        local crd=t:dealCard(p,bankCards,1,true)
        bankScore=GetScore(bankScore,crd)
        return bankScore
    end
    
    function play21Again()
        deal21()
        sound("Game Sounds One:Knock 2")
    end
    
    function draw()
        background(31, 108, 39, 255)
    
        t:draw()
        if status=="Tie Score" or status=="Winner" or status=="Lose" or status=="Busted" then 
            pushStyle()
            font("Copperplate-Bold")
            fontSize(90)
            fill(0, 0, 0, 135)
            text(""..status.." !",435,125)
            fill(255)
            text(""..status.." !",440,130)
            popStyle() 
        end
    end
    
    
  • This is Part #2, the card class

    Card = class()
    -- This class builds and draws the card images 
    
    --Parameters :
    --Height of card (in pixels)
    --Image used on the back
    --Background color of the card
    --(optional) background color on the back of the card
    --(optional) color along the border ofthe card
    
    function Card:init(height,backImg,faceColor,backColor,borderColor)
        self.height = height
        self.backImg=backImg
        self.f=height/200 --Scale font size to card size
        self.faceColor=faceColor or color(255)
        local x=100       --Default border color
        self.borderColor=borderColor or color(x, x, x, 255)
        x=x*1.5 
        --Corners are drawn with circles 
        --Which appear darker than lines, so lighten colour for them
        self.cornerColor=borderColor or color(x,x,x, 150)
        self.backColor=backColor or color(154, 199, 203, 255)
        self:createCard()
        self:createSuits()
        self.value={"A","2","3","4","5","6","7","8","9","10","J","Q","K"}
        self.suit={"♥️","♦️","♠️","♣️"}      
    end
    
    --This and the next function build just the front and back of the card itself
    --The main problem is rounded corners
    --This is done by drawing circles at the corners 
    --And then overlapping rectangles forthe final effect
    function Card:createCard()
        self.cardFace=self:createOutline(true)
        self.cardBack=self:createOutline(false)
    end
    
    function Card:createOutline(face)
        --Use standard 25/35 ratio
        self.width=math.floor(self.height*25/35+.5)
        local img=image(self.width,self.height)
        --Create rounded corner on top right
        local corner=0.05 --Distance from end of card as percent of height
        local c=math.floor(corner*self.height+0.5)
        setContext(img)
        pushStyle()
        strokeWidth(1)
        stroke(self.cornerColor)
        if face then fill(self.faceColor) else fill(self.backColor) end
        ellipse(self.width-c,self.height-c,c*2)
        ellipse(self.width-c,c,c*2)
        ellipse(c,self.height-c,c*2)
        ellipse(c,c,c*2)
        if face then stroke(self.faceColor) else stroke(self.backColor) end
        rect(0,c,self.width,self.height-c*2)
        rect(c,0,self.width-c*2,self.height)
        stroke(self.borderColor)
        line(0,c,0,self.height-c)
        line(c,0,self.width-c,0)
        line(self.width,c,self.width,self.height-c)
        line(c,self.height,self.width-c,self.height)
        --do picture on back 
        if face~=true then
            sprite(self.backImg,img.width/2,img.height/2,img.width*.9)
        end
        popStyle()
        setContext()
        return img
    end
    
    --The suit images
    function Card:createSuits()
        font("ArialRoundedMTBold")
        self.suits={"♥️","♦️","♠️","♣️"}      
    end
    
    --Draws a card at x,y with value (1-52), 
    --Face=true if face up, a=angle in degrees (default 0)
    function Card:draw(x,y,card,face,a)
        pushMatrix()
        translate(x+self.width/2,y-self.height/2)
        if a==nil then a=0 end
        rotate(a)
        if face then 
            if card>0 then self:drawDetails(card) end
        else
            sprite(self.cardBack,0,0)
        end
        popMatrix()
    end
    
    --Draw the deck at x,y (4 cards that looks like a deck)
    function Card:drawPack(x,y)
        for i=1,4 do
            local s=(i-1)*3
            self:draw(x+s,y-s,1,false)
        end  
    end
    
    --Drawsthe numbers and symbols
    function Card:drawDetails(card)
        sprite(self.cardFace,0,0)
        pushStyle()
        font("ArialRoundedMTBold")
        fontSize(24*self.f)
        --Calculate suit and value
        card=card-1
        local v=card%13 
        local s=(card-v)/13+1
        v=v+1
        local w=self.cardFace.width
        local h=self.cardFace.height
        if s==1 then --hearts 
           fill(255,0,0)  
            elseif 
        s==2 then --diamonds
           fill(232, 12, 30, 255)  
            elseif 
        s==3 then --spades
           fill(0, 0, 0, 255)  
            elseif 
        s==4 then --clubs
           fill(0, 0, 0, 255)  
      end   
    
        --Half the images on a card are upside down
        --So we do them in two loops, turning the card upside down between them
        --Where the card is not exactly symmetrical, 
        --Ex : for odd numbers, we only draw on the first loop
        for i=1,2 do
            if i==2 then rotate(180) end --Turn 180 degrees to do second loop
            local u=self.suits[s]
            text(self.value[v],-w*.4,h*.4) --Text in corner of card
            fontSize(16*self.f)
            text(u,-w*.4,h*.28) --Suit image
            fontSize(28*self.f)
            local ss=.13*h
            --Now all the symbols arranged in the middle of the card
            if v==1 then
                if i==1 then text(u,0,0) end
            elseif v==2 then
                text(u,0,.3*h)
            elseif v==3 then
                if i==1 then text(u,0,0) end
                text(u,0,.3*h)
            elseif v==4 then
                text(u,-w*.18,.3*h)
                text(u,w*.18,.3*h)
            elseif v==5 then
                text(u,-w*.18,.3*h)
                text(u,w*.18,.3*h)
                if i==1 then text(u,0,0) end
            elseif v==6 then
                text(u,-w*.18,.3*h)
                text(u,w*.18,.3*h)
                text(u,-w*.18,0) 
            elseif v==7 then
                text(u,-w*.18,.3*h)
                text(u,w*.18,.3*h)
                text(u,-w*.18,0) 
                if i==1 then text(u,0,.15*h) end
            elseif v==8 then
                text(u,-w*.18,.3*h)
                text(u,w*.18,.3*h)
                text(u,-w*.18,0)
                text(u,0,.15*h)
            elseif v==9 then 
                text(u,-w*.18,.3*h)
                text(u,w*.18,.3*h)
                if i==1 then text(u,0,0) end
                text(u,-w*.18,.1*h)
                text(u,w*.18,.1*h)
            elseif v==10 then
                text(u,-w*.18,.3*h)
                text(u,w*.18,.3*h)
                text(u,-w*.18,.1*h)
                text(u,w*.18,.1*h)
                text(u,0,.2*h)
            --Or else the card must be Royality
            else 
                pushStyle()
                font("ArialRoundedMTBold")
                fill(255) 
                fontSize(84*self.f)
    
                -- This is the Royality & Aces
                if i==1 then --the i=1 is the Ace
                    if v==11 and s==1 then text("♥️")
                        elseif v==11 and s==2 then text("♦️")  
                        elseif v==11 and s==3 then text("♠️")
                        elseif v==11 and s==4 then text("♣️")   
                        elseif v==12 and s==1 then text("♥️")
                        elseif v==12 and s==2 then text("♦️")
                        elseif v==12 and s==3 then text("♠️")
                        elseif v==12 and s==4 then text("♣️")   
                        elseif s==1 then text("♥️")
                        elseif s==2 then text("♦️") 
                        elseif s==3 then text("♠️")
                        elseif s==4 then text("♣️")   
                    end
                end
                popStyle()
            end
        end
        popStyle()
    end
    
    --Given a value 1-52, it returns the value, ex S,J,1,11
    function Card:SuitValue(c)
        local v=(c-1)%13
        local s=(c-1-v)/13+1
        v = v + 1
        return self.value[v],self.suit[s],v,s
    end
    
    function Card:isOppositeColor(s1,s2)
        if s1==s2 or s1+s2==5 then return false else return true end
    end
    
    function unicode2UTF8(u) --needed for emoji
        u = math.max(0, math.floor(u)) -- A positive integer
        local UTF8
        if u < 0x80 then          -- less than  8 bits
            UTF8 = string.char(u)
        elseif u < 0x800 then     -- less than 12 bits
            local b2 = u % 0x40 + 0x80
            local b1 = math.floor(u/0x40) + 0xC0
            UTF8 = string.char(b1, b2)
        elseif u < 0x10000 then   -- less than 16 bits
            local b3 = u % 0x40 + 0x80
            local b2 = math.floor(u/0x40) % 0x40 + 0x80
            local b1 = math.floor(u/0x1000) + 0xE0
            UTF8 = string.char(b1, b2, b3)
        elseif u < 0x200000 then  -- less than 22 bits
            local b4 = u % 0x40 + 0x80
            local b3 = math.floor(u/0x40) % 0x40 + 0x80
            local b2 = math.floor(u/0x1000) % 0x40 + 0x80
            local b1 = math.floor(u/0x40000) + 0xF0
            UTF8 = string.char(b1, b2, b3, b4)
        elseif u < 0x800000 then -- less than 24 bits
            local b5 = u % 0x40 + 0x80
            local b4 = math.floor(u/0x40) % 0x40 + 0x80
            local b3 = math.floor(u/0x1000) % 0x40 + 0x80
            local b2 = math.floor(u/0x40000) % 0x40 + 0x80
            local b1 = math.floor(u/0x1000000) + 0xF8
            UTF8 = string.char(b1, b2, b3, b4, b5)
        else
            print("Error: Code point too large for Codea's Lua.")
        end
        return UTF8
    end
    
  • This is Part #3, The Pack class

    Packclass = class()
    Pack = class()
    -- Manages the pack of cards
    -- Functions:
    -- Shuffle : (shuffles the pack)
    -- NextCard - returns the next card in the pack
    
    function Pack:init(p)
        self.pack={}
        self:shuffle()
    end
    
    function Pack:shuffle()
        self.pack={}
        local t={}
        for i=1,52 do t[i]=i end
        for i=1,52 do
            local x=math.random(1,53-i) 
            self.pack[i]=t[x]
            t[x]=53-i
        end
        return self.pack
    end
    
    function Pack:nextCard()
        if #self.pack==0 then return nil end
        local c=self.pack[1]
        table.remove(self.pack,1)
        return c
    end
    
    function Pack:cards()
        return #self.pack
    end
    
  • edited December 11 Posts: 83

    This is Part #4, How the cards are laid out on the Table

    Tableclass = class()
    CardTable = class()
    
    --All the cards are in columns and rows
    --Most position references are in cols and rows, (can be fractional)
    
    --Cards :    table to scroll through the cards.
    --col,row :  (column and row)
    --TableMap : tableMap[2][3] (card in col-2, row-3)
    --x,y :      (actual pixel position)
    --c :        value of card (1-52)
    --face :     true if face showing 
    --x,y :      are top left of table
    --c :        reference to the card class
    --s :        whether cards stacked (overlay) on each other
    --pc,ps :    (location of the pack), pc=col, ps=row
    
    function CardTable:init(x,y,c,s,pc,ps)
        self.x,self.y = x,y
        self.stacked=s
        self.card=c
        self.margin=-94 --Overlap the cards, defualt = 4
        self.cards={}
        self.tableMap={}
        self.packCol,self.packRow=pc,ps
        self.counter=0
    end
    
    --Deals the next card to (col,row)
    --With face = true for face up, false for face down
    --Returns the card dealt
    function CardTable:dealCard(pack,col,row,face)
        local c=pack:nextCard()
        if c==nil then return nil end
        return self:addToCol(c,col,row,face) 
    end
    
    --Add card to column, 
    --Row can be set to nil (if you want the next available row)
    function CardTable:addToCol(c,col,row,face)
        --If row omitted,find next available
        if row==nil then row=self:findEmptyRowInCol(col) end 
        local x=self:colToX(col)
        local y=self:rowToY(row)
        self.counter = self.counter + 1 
        local crd={id=self.counter,x=x,y=y,col=col,row=row,c=c,face=face}
        --Table.insert(self.cards,crd)
        table.insert(self.cards,crd)
        self:updateTable(crd)
        return crd
    end
    
    function CardTable:UpdateCard(oldC, newC)   
    end
    
    --TableMap 
    function CardTable:updateTable(crd,action)
        if self.tableMap[crd.col]==nil then self.tableMap[crd.col]={} end
        self.tableMap[crd.col][crd.row]={}
        self.tableMap[crd.col][crd.row]=crd
    end
    
    --Helper function returns x value from a col reference
    --DontStack = true (if cards don't overlay)
    function CardTable:colToX(col,dontStack)
        local h
        if self.stacked and dontStack~=true then h=self.card.height*.25 else h=self.card.height end
        return self.x+(self.card.width+self.margin)*(col-1)
    end
    --Helper function returns y value from a row reference
    function CardTable:rowToY(row,dontStack)
        local h
        if self.stacked and dontStack~=true then h=self.card.height*.25 else h=self.card.height end
        return self.y-(h+self.margin)*(row-1)
    end
    
    function CardTable:draw()
        for i,card in ipairs(self.cards) do
            self.card:draw(card.x,card.y,card.c,card.face)
        end
        if self.packCol~=nil then
            local x,y=self:colToX(self.packCol,true),self:rowToY(self.packRow,true)
            self.card:drawPack(x,y)
        end
        if self.moving~=nil then 
            self.card:draw(self.moving.x,self.moving.y,self.moving.c,self.moving.face) 
        end
    end
    
    
    
  • edited December 12 Posts: 83

    Under the current rules a tie is a tie, the dealer wont win. Aces have been fixed to count as 1 if the users score is over 11.. Dealer will always try to beat the players score, meaning the dealer will not stand at 16..

  • Game has been Updated. Looking for someone to try the game to see if they could find any bugs that I have missed.

Sign In or Register to comment.