Shuffle card deck and map values

tagwolf

Member
GM Version: GMS2
Target Platform: ALL

Download: https://host-a.net/f/226890-cardsyyz

(I found a place to upload thanks to a community suggestion! The project has all the card assets I reference but code doesn't exactly match the tutorial as it was part of some prototyping. It's got some fun goodies in it though. ENJOY!!)

Summary:
While replicating gambling machine logic, I did some research and found out that standard video poker machines are performing a continual shuffle on the card deck.

This is optional in the following tutorial. But overall, this should show you how to create a deck of card objects and shuffle them, then map the correct value to the objects you create in the gamespace.

If I get a good place to share the project files I'll upload my deck sprites and whole project. For now we'll do what we can! PM me if you would like the project or deck images to play with!

upload_2019-7-28_17-1-12.png

Tutorial:

Optional (depending on what you are trying to make)
I usually create several sprites, spr_spades, spr_diamonds, spr_clubs, spr_hearts, spr_cardback.
I then create multiple frames on each sprite with a value of A,2,3,4,5,6,7,8,9,J,Q,K

It's not important for the scope of this tutorial as it will depend on your game. But I'm going to move forward with the assumption that you want to use a 52 card deck of standard playing cards.

Create a script called scr_init_deck

This will fill a ds_list with 52 playing cards.

Code:
// Destroy any existing deck
if ds_exists(deck, ds_type_list) {
   ds_list_clear(deck);
   show_debug_message("Deck cleared.");
} else {
   deck = ds_list_create();
   show_debug_message("Deck created.");
}

// Factory Card Deck Order
// Spades
ds_list_add(deck, "Ace_Spades");
ds_list_add(deck, "2_Spades");
ds_list_add(deck, "3_Spades");
ds_list_add(deck, "4_Spades");
ds_list_add(deck, "5_Spades");
ds_list_add(deck, "6_Spades");
ds_list_add(deck, "7_Spades");
ds_list_add(deck, "8_Spades");
ds_list_add(deck, "9_Spades");
ds_list_add(deck, "10_Spades");
ds_list_add(deck, "Jack_Spades");
ds_list_add(deck, "Queen_Spades");
ds_list_add(deck, "King_Spades");
// Diamonds
ds_list_add(deck, "Ace_Diamonds");
ds_list_add(deck, "2_Diamonds");
ds_list_add(deck, "3_Diamonds");
ds_list_add(deck, "4_Diamonds");
ds_list_add(deck, "5_Diamonds");
ds_list_add(deck, "6_Diamonds");
ds_list_add(deck, "7_Diamonds");
ds_list_add(deck, "8_Diamonds");
ds_list_add(deck, "9_Diamonds");
ds_list_add(deck, "10_Diamonds");
ds_list_add(deck, "Jack_Diamonds");
ds_list_add(deck, "Queen_Diamonds");
ds_list_add(deck, "King_Diamonds");
// Clubs
ds_list_add(deck, "Ace_Clubs");
ds_list_add(deck, "2_Clubs");
ds_list_add(deck, "3_Clubs");
ds_list_add(deck, "4_Clubs");
ds_list_add(deck, "5_Clubs");
ds_list_add(deck, "6_Clubs");
ds_list_add(deck, "7_Clubs");
ds_list_add(deck, "8_Clubs");
ds_list_add(deck, "9_Clubs");
ds_list_add(deck, "10_Clubs");
ds_list_add(deck, "Jack_Clubs");
ds_list_add(deck, "Queen_Clubs");
ds_list_add(deck, "King_Clubs");
// Hearts
ds_list_add(deck, "Ace_Hearts");
ds_list_add(deck, "2_Hearts");
ds_list_add(deck, "3_Hearts");
ds_list_add(deck, "4_Hearts");
ds_list_add(deck, "5_Hearts");
ds_list_add(deck, "6_Hearts");
ds_list_add(deck, "7_Hearts");
ds_list_add(deck, "8_Hearts");
ds_list_add(deck, "9_Hearts");
ds_list_add(deck, "10_Hearts");
ds_list_add(deck, "Jack_Hearts");
ds_list_add(deck, "Queen_Hearts");
ds_list_add(deck, "King_Hearts");

show_debug_message("Deck initialized.");

// Return deck data structure
return deck;

Now that we have a script that creates a deck, understand that this is only creating a list of names. In order to perform logic operations on these cards, we need some more information available. So now create another script called scr_map_card

Code:
// Card Value Mapping
card = argument0;

switch (card) {
// Spades
case ("Ace_Spades"):     sprite_index = spr_spades; image_index = 0; value = 1; suit = "spades"; break;
case ("2_Spades"):       sprite_index = spr_spades; image_index = 1; value = 2; suit = "spades"; break;
case ("3_Spades"):       sprite_index = spr_spades; image_index = 2; value = 3; suit = "spades"; break;
case ("4_Spades"):       sprite_index = spr_spades; image_index = 3; value = 4; suit = "spades"; break;
case ("5_Spades"):       sprite_index = spr_spades; image_index = 4; value = 5; suit = "spades"; break;
case ("6_Spades"):       sprite_index = spr_spades; image_index = 5; value = 6; suit = "spades"; break;
case ("7_Spades"):       sprite_index = spr_spades; image_index = 6; value = 7; suit = "spades"; break;
case ("8_Spades"):       sprite_index = spr_spades; image_index = 7; value = 8; suit = "spades"; break;
case ("9_Spades"):       sprite_index = spr_spades; image_index = 8; value = 9; suit = "spades"; break;
case ("10_Spades"):      sprite_index = spr_spades; image_index = 9; value = 10; suit = "spades"; break;
case ("Jack_Spades"):    sprite_index = spr_spades; image_index = 10; value = 11; suit = "spades"; break;
case ("Queen_Spades"):   sprite_index = spr_spades; image_index = 11; value = 12; suit = "spades"; break;
case ("King_Spades"):    sprite_index = spr_spades; image_index = 12; value = 13; suit = "spades"; break;
// Diamonds
case ("Ace_Diamonds"):   sprite_index = spr_diamonds; image_index = 0; value = 1; suit = "diamonds"; break;
case ("2_Diamonds"):     sprite_index = spr_diamonds; image_index = 1; value = 2; suit = "diamonds"; break;
case ("3_Diamonds"):     sprite_index = spr_diamonds; image_index = 2; value = 3; suit = "diamonds"; break;
case ("4_Diamonds"):     sprite_index = spr_diamonds; image_index = 3; value = 4; suit = "diamonds"; break;
case ("5_Diamonds"):     sprite_index = spr_diamonds; image_index = 4; value = 5; suit = "diamonds"; break;
case ("6_Diamonds"):     sprite_index = spr_diamonds; image_index = 5; value = 6; suit = "diamonds"; break;
case ("7_Diamonds"):     sprite_index = spr_diamonds; image_index = 6; value = 7; suit = "diamonds"; break;
case ("8_Diamonds"):     sprite_index = spr_diamonds; image_index = 7; value = 8; suit = "diamonds"; break;
case ("9_Diamonds"):     sprite_index = spr_diamonds; image_index = 8; value = 9; suit = "diamonds"; break;
case ("10_Diamonds"):    sprite_index = spr_diamonds; image_index = 9; value = 10; suit = "diamonds"; break;
case ("Jack_Diamonds"):  sprite_index = spr_diamonds; image_index = 10; value = 11; suit = "diamonds"; break;
case ("Queen_Diamonds"): sprite_index = spr_diamonds; image_index = 11; value = 12; suit = "diamonds"; break;
case ("King_Diamonds"):  sprite_index = spr_diamonds; image_index = 12; value = 13; suit = "diamonds"; break;
// Clubs
case ("Ace_Clubs"):      sprite_index = spr_clubs; image_index = 0; value = 1; suit = "clubs"; break;
case ("2_Clubs"):        sprite_index = spr_clubs; image_index = 1; value = 2; suit = "clubs"; break;
case ("3_Clubs"):        sprite_index = spr_clubs; image_index = 2; value = 3; suit = "clubs"; break;
case ("4_Clubs"):        sprite_index = spr_clubs; image_index = 3; value = 4; suit = "clubs"; break;
case ("5_Clubs"):        sprite_index = spr_clubs; image_index = 4; value = 5; suit = "clubs"; break;
case ("6_Clubs"):        sprite_index = spr_clubs; image_index = 5; value = 6; suit = "clubs"; break;
case ("7_Clubs"):        sprite_index = spr_clubs; image_index = 6; value = 7; suit = "clubs"; break;
case ("8_Clubs"):        sprite_index = spr_clubs; image_index = 7; value = 8; suit = "clubs"; break;
case ("9_Clubs"):        sprite_index = spr_clubs; image_index = 8; value = 9; suit = "clubs"; break;
case ("10_Clubs"):       sprite_index = spr_clubs; image_index = 9; value = 10; suit = "clubs"; break;
case ("Jack_Clubs"):     sprite_index = spr_clubs; image_index = 10; value = 11; suit = "clubs"; break;
case ("Queen_Clubs"):    sprite_index = spr_clubs; image_index = 11; value = 12; suit = "clubs"; break;
case ("King_Clubs"):     sprite_index = spr_clubs; image_index = 12; value = 13; suit = "clubs"; break;
// Hearts
case ("Ace_Hearts"):     sprite_index = spr_hearts; image_index = 0; value = 1; suit = "hearts"; break;
case ("2_Hearts"):       sprite_index = spr_hearts; image_index = 1; value = 2; suit = "hearts"; break;
case ("3_Hearts"):       sprite_index = spr_hearts; image_index = 2; value = 3; suit = "hearts"; break;
case ("4_Hearts"):       sprite_index = spr_hearts; image_index = 3; value = 4; suit = "hearts"; break;
case ("5_Hearts"):       sprite_index = spr_hearts; image_index = 4; value = 5; suit = "hearts"; break;
case ("6_Hearts"):       sprite_index = spr_hearts; image_index = 5; value = 6; suit = "hearts"; break;
case ("7_Hearts"):       sprite_index = spr_hearts; image_index = 6; value = 7; suit = "hearts"; break;
case ("8_Hearts"):       sprite_index = spr_hearts; image_index = 7; value = 8; suit = "hearts"; break;
case ("9_Hearts"):       sprite_index = spr_hearts; image_index = 8; value = 9; suit = "hearts"; break;
case ("10_Hearts"):      sprite_index = spr_hearts; image_index = 9; value = 10; suit = "hearts"; break;
case ("Jack_Hearts"):    sprite_index = spr_hearts; image_index = 10; value = 11; suit = "hearts"; break;
case ("Queen_Hearts"):   sprite_index = spr_hearts; image_index = 11; value = 12; suit = "hearts"; break;
case ("King_Hearts"):    sprite_index = spr_hearts; image_index = 12; value = 13; suit = "hearts"; break;
}

return;
Granted it might be a bit expressive, but for our purposes it should do fine.

For our last script, call it scr_shuffle_deck

Code:
deck = argument0;

//TODO: error checking, better randomization, cards remaining,
// confirm shuffle, confirm random, confirm deck integrity.
//check if should be shuffling currently, if flipping a card we want to make sure we delete the
//correct value.

randomize()

ds_list_shuffle(deck);

var cards_in_deck = ds_list_size(deck);

if verbose
{
   for (i = 0; i <= cards_in_deck; i++)
   {
       card = ds_list_find_value(deck, i);
       show_debug_message(string(card));
   }
}

show_debug_message(string(cards_in_deck)+" cards shuffled.");

return;
This script does the leg work of randomizing every time we shuffle the deck (both the seed and the deck itself). If verbose is enabled it will also output our results, which is good for debugging purposes.

Object Code

** NOTE: Everything below is project specific. You don't need any of it and it's included as example of how to use the scripts above. ***

obj_deck - Create Event
Code:
// Uncomment for continuous shuffling
//shuffling = true;
//verbose = true;
deck = scr_init_deck()

// Let's create a deck card pile
// You can easily add mouse events to the cards that spawn on top of each other to pick them up.
// If I find a good place to host project files I'll include it and my tiny card deck sprites that I love a lot :)

for (var i = 0; i <= ds_list_size(deck) - 1; i++) {
 
   var card = ds_list_find_value(deck,i);
 
   show_debug_message(string(card));
 
   scr_assign_card(card);
 
   // spawn card in pile
   new_card = instance_create_depth(random_range(63, 65), random_range(63, 65), 0, obj_card);
 
   // randomize angle
   new_card.image_angle = random_range(-5,5);
 
 
   // set values
   new_card.card_name = card;
   new_card.card_suit = card_suit;
   new_card.card_value = card_value
   new_card.card_sprite = card_sprite;
   new_card.card_image = card_image;
   // set card image
   //new_card.sprite_index = card_sprite;
   //new_card.image_index = card_image;
 
   // set card image face down
   new_card.sprite_index = spr_cardback;
 
}
obj_deck - Step Event
Code:
/// @description Main deck logic

// Determine if we need to shuffle
if (shuffling) {
   scr_shuffle_deck(deck);
}
For the cards themselves, you can place 52 in your room or setup a for loop to stack them onto a deck you can grab, whatever works best for your use-case!

obj_card - Create Event
Code:
card_drag = false;
card_name = 0;
card_suit = 0;
card_value = 0;
card_image = 0;
card_sprite = 0;
obj_card - Step Event (if you want card dragging and stuff include the things below)
Code:
if (card_drag) {

   x = mouse_x;
   y = mouse_y;

}
obj_card - Left Pressed Event
Code:
show_debug_message("Card Clicked");
show_debug_message("NAME: " + string(card_name));
show_debug_message("VALUE: " + string(card_value));
show_debug_message("SUIT: " + string(card_suit));
show_debug_message("SPRITE: " + string(card_sprite));
show_debug_message("IMAGE: " + string(card_image));

if (global.any_card_drag == false) {
   global.any_card_drag = true;
   card_drag = true;
 
   sprite_index = card_sprite;
   image_index = card_image;
 
}
obj_card - Left Released Event
Code:
if (card_drag == true) {

   card_drag = false;
   global.any_card_drag = false;
 
}
Then just put the obj_deck (no sprite) in a room and you're good to go! In this example the obj_card doesn't need a sprite either as it's dynamically assigned one. obj_card's do not need to be added to your room (in THIS example).
 
Last edited:
P

Papajustify

Guest
Thank you for this tutorial. I have been looking for a tutorial, regarding cards, for a long time. I'm very new to GML code (mainly using DnD). This was so well written I was able to work it out.

As a side note, it also answered a question I had about a simple way for item dragging.
 
J

jimbojetset2

Guest
Hi, any chance you could post another link to your source files please? I think your card game may really help me. Many thanks, James
 
Last edited:
J

jimbojetset2

Guest
Cheers for your version. I am hoping this will help point me in the right directions for making a kind of language word game using shuffled cards. I'm trying to make use of all this extra time during the lockdown. Many thanks, James
 
Cheers for your version. I am hoping this will help point me in the right directions for making a kind of language word game using shuffled cards. I'm trying to make use of all this extra time during the lockdown. Many thanks, James
Best of luck to you, James. Make sure to post it in the "Made with GameMaker" forum when you're done. I'd like to check it out.
 
H

HarrowedScrub

Guest
Hi, I'm new to GameMaker and I am trying to learn the ropes on how to create a shuffling deck of cards from a list. I found this tutorial helpful, but I am now stuck. I'm working in 1.4, and since YYZ files can't be imported into it I can't check out the script "scr_assign_card" that is missing from the first post. Could you possibly post that script here like the others? I apologize for any inconvenience this may cause and that I am working from an older version of the program, but any help would be greatly appreciated.
 
Hi, I'm new to GameMaker and I am trying to learn the ropes on how to create a shuffling deck of cards from a list. I found this tutorial helpful, but I am now stuck. I'm working in 1.4, and since YYZ files can't be imported into it I can't check out the script "scr_assign_card" that is missing from the first post. Could you possibly post that script here like the others? I apologize for any inconvenience this may cause and that I am working from an older version of the program, but any help would be greatly appreciated.
No worries, @HarrowedScrub. I'd be happy to do that for you. I'm away from keyboard right now, but I'll do this just as soon as I can.


 
Last edited:
H

HarrowedScrub

Guest
No worries, @HarrowedScrub. I'd be happy to do that for you. I'm away from keyboard right now, but I'll do this just as soon as I can.


Thanks for helping me out with this @SilentxxBunny . It's greatly appreciated!
 
Top