#### Howdy, Stranger!

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

# Like a turned card

edited July 2013 Posts: 18

Hey guys, i am looking for a script.
i need a random spawn. just like blackjack.
when you hit a button you will get a random card.
i hope somebody over here can help me Tagged:

• Posts: 391

You could use card = math.random(13) to determine whether it is an ace through king then do suit = math.random(4) to determine suit, then store both into a table of usedCards.

table.insert(usedCards, { card, suit })

Then when adding the next random card, make sure to check the table to see if that card was already used.

• Posts: 2,161

Better to shuffle the deck first and then deal out the randomised cards.

A straightforward algorithm for this is the Fischer-Yates-Knuth shuffle:

``````function KnuthShuffle(n,odd)
local l
local o = 0
local p = {}
for k = 1,n do
p[k] = k
end
for k = 1,n-1 do
l = math.random(k,n)
if l ~= k then
p[k],p[l] = p[l],p[k]
o = 1 - o
end
end
if not odd and o == 1 then
p,p = p,p
end
return p
end
``````

This will shuffle the integers from 1 to n. Modulo the usual remarks about `math.random` not being truly random, this gives the correct distribution on shuffles. The optional flag `odd` is because I wanted a way to ensure that the resulting shuffle was an even permutation (it was for a picture-sliding puzzle).

• Posts: 18

Yeah thats more like it, i Need it for all THE 52 cards.

• Posts: 3,297

@Andrew_stacey when i need a random order for a deck i do like this:
- 1/ get a random number Ri for each card i of the deck.
- 2/ sort the cards wrt the numbers Ri.
It is quick and simple. What do you think of this algorithm? How would you compare it to FYK shuffle?

• Posts: 2,161

@Jmv38 Apparently, `table.sort` uses quick sort which is O(n log n). Fisher-Yates-Knuth (and, according to Wikipedia, Durstenfeld) is O(n). So FYDK is quicker.

It would be easier to see the comparison if we replaced the quicksort by a bubble sort.

1. Generate n random numbers
2. Perform 1/2 n(n-1) comparisons (A bubble sort does n-1 + n-2 + n-3 + n-4 + ... + 1 comparisons).
3. Perform a bubble sort which on average performs 1/4 n(n-1) swaps (we expect half of the comparisons to result in a swap). If n is bigger than 4, this is bigger than n-1, and it grows with the square of n.

FYDK algorithm:

1. Generate n-1 random numbers.
2. Perform at most n-1 swaps.

So I'd say that the Fisher-Yates-Knuth-Durstensfeld algorithm is quicker.

Of course, the fact that the quicksort is internal might have an impact, but other than that I'd go for the other.

Incidentally, I discovered this algorithm not all that long ago and was so taken with it that I wrote a blog post about it: http://tex.blogoverflow.com/2011/08/do-the-knuth-shuffle/ I find it actually a very intuitive algorithm.

• Posts: 3,297

Thanks for the detailed argumentation.

• Posts: 8,554

Here's a routine that I used. You can setup a table of 52 cards instead of using 2 tables like I have here.

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

cards={}

for z=1,52 do    -- clear selected cards
cards[z]=0
end

for z=1,52 do    -- 52 cards
selectedCard=math.random(1,52)    -- random card
if cards[selectedCard]~=0 then    -- card already selected
while cards[selectedCard]~=0 do    -- look for next card not selected
selectedCard = selectedCard + 1    -- try next card
if selectedCard>52 then    -- end of deck
selectedCard=1    -- start over
end
end
end
cards[selectedCard]=1    -- set card as selected
s=math.ceil(selectedCard/13)   -- get suit
v=selectedCard%13+1    -- get value
print(value[v].." of "..suit[s])
end
end

``````
• Posts: 18

Verry nice dave but how do i link Some sprites to the numbers.
And how do i get text with every card?

• Posts: 2,161

@dave1707 That's pretty close to the original FY algorithm. The one I describe is meant to be an improvement on that.

• edited July 2013 Posts: 5,396

@Draakk - perhaps I can save you some trouble. In the posts 39 & 40 of the link below is code to draw your own cards (without any sprites), shuffle and deal them, etc

http://coolcodea.wordpress.com/2013/04/

• Posts: 8,554

@Draakk I'm not sure how you're creating your sprites, but if you have 1 sprite per card then you would use a table for the sprites. In my code above, selectedCard would be an offset into that table. My code would also have to be modified a little depending on how you want it to work with your code. It could be changed to return a table containing 52 random cards or changed to a function to return a random card for each call for the 52 cards.

• Posts: 8,554

@Andrew_Stacey That's a routine that I used probably 25+ years ago when I was messing around with card programs on my Apple II.

• Posts: 36

What is the best way to animate a turning over card given a front and back png? Maybe with a slight bend in the card as it turns using a swipe of the finger. Maybe even with some thickness to the card. Maybe with both sides of the card visible at the same time during part of the turn.

• Posts: 18

I dont want THE script draw THE cards, ive created 52 awsome .png's
How Will it end up with png's

• edited July 2013 Posts: 5,396

@Draakk - that is a very broad request - do you have a specific question?

• Posts: 18

I just want 2 stacks of cards 1 stack with the backside up you must hit it and the other stack is the random turned cards when you hit the first stack.
Ive created my own playing cards in illustrator and exported the 52 images to png files.

• edited July 2013 Posts: 3,297

@Draakk suggestion: post your own script, and if it doesnt work well some great folk on this forum will correct it or improve it. No one is going to code your game for you, if this is what you are looking for? >:D<
(with the exception of Dave, maybe, who is a really really nice guy and a coding machine!)

• edited July 2013 Posts: 18

This is my current main script
But the problem is the cards are repeating... It doesnt stop at the end of the stack.
And when i hit the stack it draws almost 3 cards in 1 time.
And how do i get text drawn in the screen?
Thnq

``````-- Use this function to perform your initial setup
function setup()
--b=Backup("Cards v105")
img=readImage("Documents:cb") --image for back of card
deal()
print("Turn the card!")
end

function touched(touched)
-- this examines if the touch is within the rectangle's boundraries:
if CurrentTouch.x > 308 and CurrentTouch.x < 494 and CurrentTouch.y > 317 and CurrentTouch.y < 602 then
deal() --redeal if we touch the screen
end
end

function deal()
c=Card(250,img)  --big cards
p=Pack(1)
cards={}
for i=1,1 do
cards[i]=p:nextCard()
end
end

-- This function gets called once every frame
function draw()
-- This sets a background
sprite("Documents:bg1", 512, 384, 1024, 768)
-- sprite("Documents:cb", 401, 462, 186, 290)
-- This sets the line thickness
strokeWidth(5)

--draw our hand of cards
--spread out cards to look nice
for i,card in ipairs(cards) do
c:draw(523+i*18,555,card.cardIndex,true)
end
--draw a pack face down
for i=1,4 do
c:draw(312+i*2,590-i*2,1,false)
end
end
``````
• edited July 2013 Posts: 5,396

The reason it is dealing more than one card is that the touched function gets called at least twice for a touch - once at the beginning and once at the end. Try this, to only deal when the touch ends.

``````function touched(touch)
if touch.state==ENDED then
if touch.x>308 and touch.x<494 and .....  --your code goes here
end
end
``````
• Posts: 8,554

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

``````
• Posts: 2,161

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

• Posts: 2,161

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,{}
``````
• Posts: 8,554

• Posts: 5,396

@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.

• Posts: 8,554

@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.

• Posts: 5,396

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

• Posts: 2,161

@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.)

• Posts: 2,161

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.

• Posts: 8,554

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

• Posts: 18

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

• Posts: 5,396

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

• Posts: 18

@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

• edited July 2013 Posts: 391

@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=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.

• edited July 2013 Posts: 18

@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
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

``````
• edited July 2013 Posts: 391

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))

• Posts: 391

@Draakk, quick and easy fix for you.

Change the deal() line in touched function to:

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

• edited July 2013 Posts: 391

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

• Posts: 391
``````    --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.

• Posts: 18

@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.

• Posts: 391

The last one is to replace your last for loop in the draw function. It will simply display 3 face down when only 3 cards are left in the deck, then 2 when 2 are left, etc.

As for the cards going off the screen, you would need to modify the y coordinate of the images as well as the x coordinate. I will get back to you shortly with the code.

• edited July 2013 Posts: 391
``````-- Use this function to perform your initial setup
function setup()
--b=Backup("Cards v105")
img=readImage("Documents:Block") --image for back of card
numDecks = 2
deal()
print("Turn the card!")
end

function touched(touched)
-- this examines if the touch is within the rectangle's boundraries:
if touched.state == ENDED then
if CurrentTouch.x > 308 and CurrentTouch.x < 494 and CurrentTouch.y > 317 and CurrentTouch.y < 602 then
cards[((52*numDecks)+1)-#p.pack]=p:nextCard()
end
end
end

function deal()
c=Card(250,img)  --big cards
p=Pack(numDecks)
cards={}
cards=p:nextCard()
end

-- This function gets called once every frame
function draw()
-- This sets a background
sprite("Documents:bg1", 512, 384, 1024, 768)
-- sprite("Documents:cb", 401, 462, 186, 290)
-- This sets the line thickness
strokeWidth(5)

--draw our hand of cards
--spread out cards to look nice
for i,card in ipairs(cards) do
c:draw(541+((i-1)%13)*24,555-math.floor((i-1)/13)*60,card.cardIndex,true)
end
--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
end
``````

Replace your main tab with the code above.

• Posts: 18

Verry nice, but the cards keep turning to the right of the screen. I want to draw the turned card exactly on top of the other turned cards. You know what i mean?

• edited July 2013 Posts: 391

Replace

``````    for i,card in ipairs(cards) do
c:draw(541+((i-1)%13)*24,555-math.floor((i-1)/13)*60,card.cardIndex,true)
end
``````

With

``````    for i,card in ipairs(cards) do
c:draw(523,555,card.cardIndex,true)
end
``````

This will draw the flipped card in the same spot every time.

• edited July 2013 Posts: 18

Alright but the left pack is a pack of 4 cards. Can we count the turned cards up to 4 cards and the turn on the same spot? like the left pack?

• Posts: 391

Are you flipping over 4 cards at once, or just showing 4 cards in this manner?

Pack - A B C D

Then placing cards over those 4

Pack - A B C D

To accomplish this, replace the same code as above with this code:

``````    for i,card in ipairs(cards) do
c:draw(541+((i-1)%4)*24,555,card.cardIndex,true)
end
``````

Change 24 to a higher number if you want more space between the cards. If you want to see the whole card when flipped, I suggest moving the pack to the left by decreasing 312, and then move the flipped cards further left by also decreasing 541.

• Posts: 18

@slashin8r nice i was so close with coding it.
The following problem is, when you launch the game there is allready a flipped card. How do i start with none.

• Posts: 391

In your deal function, remove the line with the p:nextCard in it.