Skip to main content

On Sale: GamesAssetsToolsTabletopComics
Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
TagsGame Engines

Pico-8 card game 'engine'

A topic by RhizGames created Nov 15, 2021 Views: 217 Replies: 5
Viewing posts 1 to 3
(1 edit) (+1)

I was thinking of trying to make a couple classic card games in Pico-8 (starting with war) so here is my best attempt at making a shuffled deck: 72 characters

Feel free to use it if you think it's interesting.

'd' is the shuffled deck, I usually use the label 's' for start/setup loop.

d={}for i=1,52do::s::x=rnd(52)\1+1
if(d[x]==nil)d[x]=i%13else goto s
end
Submitted

Neat! Seems like it doesn’t take suits into consideration, so there would be four cards with the value 0, right?

You are right. I'm working on War now and probably Go Fish next, neither of which need suits. I figure I'll think of something when I need it. My intuition is filling 'd' with 1 through 52 then in the game logic you would mod 13 for the value and integer divide (\) by four for the suit.

(1 edit) (+2)

Here is my first draft of a two tweet card game simulation of the card game war.


In the card game war, the deck is shuffled and each player gets half the cards. The players then simultaneously draw one card at a time, the player who draws a higher card wins the round and takes all the cards drawn that round. If both players draw the same card, then they do a 'war', which means the round continues with each player drawing four cards and comparing the last one. The game ends when one player is out of cards.

u=unpack
function s(a)for i=1,#a do
q=a[i]r=i+rnd(#a-i)\1a[i]=a[r]a[r]=q
end
return a
end
function c(a,b)for i=1,#b do
add(a,b[i])end
end
d={}g={}h={}v={}w=0
for i=1,52do d[i]=i end
s(d)x={u(d,1,26)}y={u(d,27)}::_::
if(#x<1)x=s(g)g={}
if(#y<1)y=s(h)h={}
if(#x<1)print('lose')
if(#y<1)print('win')
if(btnp(🅾️)and#x*#y!=0)then
o=x[#x]%13p=y[#y]%13c(v,{o,p})x[#x]=z y[#y]=z 
if(w<1)then
if(#v<3)cls()
?'1:'..o..' 2:'..p
if(o==p)then
w=3
else
if(o>p)c(g,v)else c(h,v)
v={}
?'s:'..(#x+#g-#y-#h)/2+26
end
else
?sub('raw',w,w)
w-=1end
end
flip()goto _

There is still plenty of work to be done, but I will explain this code as it is in another post.

(+1)
u=unpack --shortening the name of the unpack function


function s(a) --A function to shuffle a stack of cards
    --for each card in a pile, swap it with any card to its right
    for i=1,#a do 
        q=a[i]
        r=i+rnd(#a-i)\1 --i is the index of the card we are swapping, rnd(#a-i)\1 is the number of cards to the right of it
                        --\1, backslash does integer division, which takes the floor of the quotient, is less characters than using flr()
        a[i]=a[r] --the swap
        a[r]=q
    end
    return a --this function doesn't need a return value since it modifies a directly, but I found it useful for shuffling the discard before putting it in your hand
end


function c(a,b) --this function puts a stack of cards, b, on top of the stack of cards, a
    for i=1,#b do
        add(a,b[i]) --adds each card of b in order
    end
end


d={}g={}h={}v={}w=0 --initializing some variables. In order:
                                                            original deck of cards,
                                                            the player's discard pile, 
                                                            the opponent's discard pile, 
                                                            the current cards at stake, 
                                                            how many cards are left to the current war


for i=1,52do d[i]=i end --filling the deck with cards
s(d) --shuffle the deck
x={u(d,1,26)} --the player gets half
y={u(d,27)} --the cpu gets half

Here I use the unpack function to cut the deck by taking a subtable by enclosing the returned tuple with { and }.

::_::        --Usually '_' is used for a label because it would be an awful variable name and so is free
...          --The game loop
flip()goto _ --flip() is necessary to avoid accidentally turning over too many cards
(+1)
if (#x<1) x=s(g) g={}   --If either player's hand is empty, shuffle their discard and put it in their hand, empty the discard
if (#y<1) y=s(h) h={}


if (#x<1) print('lose') --If either player runs out of cards, the game ends
if (#y<1) print('win')


if (btnp(🅾️) and #x*#y!=0) then --if the player tries to draw a card and the game isn't over (if either #x or #y are zero, their product is also zero)


o=x[#x]%13 --o and p are the top cards of each player's hand
p=y[#y]%13 --we use 13 because we are only concerned with the value, not the suit
c(v,{o,p}) --add the top cards of each player's hand to cards in play
x[#x]=z    --z is an unused uninitialized variable so it is equal to nil
y[#y]=z    --this removes the top cards from the players' hands


if (w<1) then --are we currently in a "war"?

If we aren't in a war then

if (#v<3) cls() --if there are only two cards in play, then a new round has begun and we clear the screen
?'1:'..o..' 2:'..p --reveal the cards
if(o==p)then --if doubles, start a war
    w=3 --set the number of cards left to draw for a war to 3
else --not doubles
    if (o>p) c(g,v) else c(h,v) --If the player wins, they get the cards on the table put in their discard pile
    v={} --empty the table
    ?'s:'..(#x+#g-#y-#h)/2+26 --the round is over, display how many cards the player currently has
end

If we are in a war

?sub('raw',w,w) --prints the letters of war one at a time
w-=1            --reduce the number of cards left in the war
                --we have already drawn the card at the beginning of the game loop

I've commented every line, I'll go back through and point out some tweetcart tricks.