# Like a turned card

Here is another version of code to shuffle a deck of cards. This one is smaller than my original one and also allows you to shuffle the deck x number of times to get a better random order of the deck. This also causes a problem that I’m not sure what’s happening. Even though I’m calling shuffleCards with a value of 5, which results in the loop doing 5 shuffles, the size of table d2 never gets above 53, even though I do a table.insert 260 (5x52) times. If I put the statement print(#d2) after table.insert(d2,d1[s]), I see the size of d2 rise from 1 to 53 and stay at 53. I think I know what’s happening, but I’m not sure. I’ll wait for other explanations.

``````
function setup()
value={"2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace"}

Shuffled=shuffleCards(5)    -- shuffle cards 10 times

for z=1,52 do    -- print the shuffled deck
s=math.ceil(Shuffled[z]/13)   -- get suit
v=Shuffled[z]%13+1    -- get value
print(value[v].." of "..suit[s])
end
end

function shuffleCards(x)
local d1, d2, s, y, z = {}, {}
for z=1,52 do
d1[z]=z     -- fill table d1 with the numbers 1 to 52
end
for y=1,x do    -- shuffle x number of times
for z=1,52 do  -- loop thru 52 cards
s=math.random(1,#d1)    -- get a random number from table d1
table.insert(d2,d1[s])    -- insert it in table d2
table.remove(d1,s)    -- remove it from table d1
end
d1=d2  -- make d1 equal to d2 for the next shuffle of d1
end
return d2    -- return the shuffled deck in d2
end

``````

@dave1707 Shuffling five times does not make it more random! You really, truly do not need to do that.

Oh, and the problem is that after one shuffle you are only using one table. So on the second shuffle you are adding to the same table that you are deleting from. You probably meant to do:

``````d1,d2 = d2,{}
``````

@dave1707 @Andrew_Stacey - I’m with Andrew on this, Dave. As a statistician, I can assure you that randomising an already random shuffle doesn’t add anything. The reason we often do multiple manual shuffles in real life, is that our shuffles aren’t very random. The computer does a much better job.

I remember an amusing story from when bridge players first started using computer shuffled packs. They complained about the weird hands they were getting until they realised it was because their own shuffling had been non random.

@Ignatz After I sent the post I realized that wasn’t what I meant to say, but I didn’t want to try and correct it. Either something is random or it isn’t. It can’t be more random. I added multiple shuffles because it was only 2 more lines of code and I shuffle multiple times in real life.

@dave1707 - fair enough - if your shuffling is anything like mine, it takes a few of them to get some resemblance to being random!

@dave1707 but in your code you are then doing something for no reason at all so it’s a waste of time.

(Incidentally, it takes 7 riffle shuffles to randomise a pack. Unless you are a magician and can do “perfect” riffle shuffles.)

Either something is random or it isn’t. It can’t be more random.

Err, not quite. The point here is the probability distribution. If the thing you are doing is random, it might not be the right random but maybe doing it a few times gets you the right one. For example, if you have a biased coin then you can simulate a fair coin by flipping it in batches of two and taking only HT or TH as the two values.

So if your method of shuffling only introduces a little randomness then you need to shuffle multiple times to spread that through the whole pack. But the shuffling routines we’ve been discussing are already the right ones so doing them again is simply a waste of time.

This site give a lot of info on randomness. I like the cartoon in this section. http://www.random.org/analysis/

@ignatz ive tried out the code but it didn’t work.
Do you got a better solution?

@Draakk - without seeing your code, I can’t comment. My solution should work fine if you did it right. What is happening now?

@ignatz yes im sorry my bad, i forgot an extra end.
It is working now, but the following problem is, the cards keep repeating. It wont stop after card 52.
Maybe you can explain that?

Thnx

@Draakk, your deal function is a bit odd…

``````cards={}
for i=1,1 do
cards[i]=p:nextCard()
end
``````

Every time you deal you are clearing the cards table. That for loop makes no sense either as it starts at 1 and always ends at 1, so every time you are only inputting a card into index 1 of the table. If that was meant to be that way, you could accomplish the same thing by using cards[1]=p:nextCard().

I’m assuming Pack is your class to create your deck, including the randomized shuffle. If so, you don’t want to call that in the same function you use to draw a card, which I’m assuming p:nextCard() draws a card.

Let us see your Card and Pack classes and we can further investigate the issue.

@slashin8r
Here is my pack class

``````Pack = class()
--[[
Manages one or more packs of cards
Functions:

shuffle - shuffles the pack

nextCard - returns the next card in the pack
--]]

function Pack:init(p)
self.pack=self:shuffle(p)
end

function Pack:shuffle(p)
n=p or 1 --number of packs, defaults to 1
--set up pile with all the packs in order first
local t={}
for i=1,n do
for j=1,52 do
t[#t+1]=j
end
end
--now sort the pile randomly by pulling cards out at random
local pack={}  --table to hold shuffled cards
while #t>0 do
local i=math.random(1,#t)
pack[#pack+1]=t[i]
table.remove(t,i)
end
return pack
end

function Pack:nextCard(p)
if #self.pack==0 then return nil end
local value={"A","2","3","4","5","6","7","8","9","10","J","Q","K"}
local suit={"S","H","D","C"}
local c=self.pack[1]
table.remove(self.pack,1)
local v=(c-1)%13+1
local s=(c-v)/13+1
return {value=value[v],suit=suit[s],valueIndex=v,suitIndex=s,cardIndex=c}
end

function Pack:cards()
return #self.pack
end
``````

And here is my card class

``````--# Card
Card = class()
--[[this class builds and draws the card images from scratch and provides some utilities

--]]

--class initialises by creating card design
--Parameters:
--height of card in pixels
--the image to be used on the back
--background color on the face of the card
--(optional) background color on the back of the card
-- (optional) color along the border ofthe card

--returns nothing
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(240, 239, 237, 255)
self:createCard()
self:createSuits()
self.value={"A","2","3","4","5","6","7","8","9","10","J","Q","K"}
self.suit={"S","H","D","C"}
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*30/45+.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)
--set background colour
if face then fill(self.faceColor) else fill(self.backColor) end
--draw small circles at corners
ellipse(self.width-c+1,self.height-c+1,c*2)
ellipse(self.width-c+1,c-1,c*2)
ellipse(c-1,self.height-c+1,c*2)
ellipse(c-1,c-1,c*2)
if face then stroke(self.faceColor) else stroke(self.backColor) end
--now rectangles to fill in thre centre of the card
rect(0,c,self.width,self.height-c*2)
rect(c,0,self.width-c*2,self.height)
--now a border round the card
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 come from emoji
function Card:createSuits()
font("AppleColorEmoji")
self.suits={unicode2UTF8(9824),unicode2UTF8(9829),unicode2UTF8(9830),unicode2UTF8(9827)}
end

--draws a card at x,y with value of card (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) else sprite(self.cardFace,0,0) end
else
sprite(self.cardBack,0,0)
end
popMatrix()
end

--draws the numbers and symbols on the front of the card
--one parameter = card value
function Card:drawDetails(card)
sprite(self.cardFace,0,0)
pushStyle()
font("SourceSansPro-Regular")
fontSize(24*self.f)
--calculate suit and value of card
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 or s==4 then fill(0,0, 0, 255) else fill(255,0,0,255) end   --fill is red or black

--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, eg 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,.15*h)
text(u,w*.18,.15*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)
else --royalty
pushStyle()
font("AppleColorEmoji")
fill(255)
fontSize(84*self.f)
if i==1 then
if v==11 then text(unicode2UTF8(128113))
elseif v==12 then text(unicode2UTF8(128120))
else text(unicode2UTF8(128116))
end
end
popStyle()
end
end
popStyle()
end

--used by Main and other classes
--given a value 1-52, it returns the value and suit in text and numbers, eg 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 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

``````

Here is some pseudo code you could possibly work with.

shuffle 52 cards to make a deck

check if deck is empty (#deck ~= 0)

drawCard function to remove a card from your deck (cards[53-#deck] = table.remove(deck,1))

@Draakk, quick and easy fix for you.

Change the deal() line in touched function to:

cards[53-#p.pack]=p:nextCard()

My fix only works for 1 deck, make a variable for number of decks and then instead of running Pack(1) in deal(), run Pack(numDecks), then change my above fix to:

cards[((52*numDecks)+1)-#p.pack]=p:nextCard()

Add print(#p.pack) after above line to verify the card count is going down

``````    --draw a pack face down
for i=1,math.min(4,#p.pack) do
c:draw(312+i*2,590-i*2,1,false)
end
``````

This code will show your deck disappear when you use up all the cards.

@slashin8r hey thnx for the fix.
But the last one where do i need to put that?
And my following problem is; the turned cards are not placed at the same place anymore.
With 15 cards the turned cards, the next cards are leaving the screen to the right.