GMS 2 Playing card deck

Discussion in 'Programming' started by Flimshady, Feb 9, 2019.

  1. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    Hello,

    i am currently trying to create a simple deck of 24 playing cards. I want the cards to be randomised in order, but there lies my problem. I've tried using the choose() function, but this function can choose the same card twice sometimes, so it doesnt represent a real deck.
    Maybe if someone knows how to help me or can give me a little push in the right direction, I would be verry happy.

    Thank you!
     

    Attached Files:

  2. BeepBoop

    BeepBoop Member

    Joined:
    Feb 6, 2019
    Posts:
    6
    Use ds_lists! Create it, add your cards, shuffle, retrieve the first card from the list. Then delete that card from the list and add again (so it will become the last card in the list).

    OR make a simple cooldown. If you don't want to pick the same card twice, you can do something like this:

    Code:
    card = choose(val1,val2,val3,val4);
    cardcooldown = card;
    while (card=cardcooldown)
    {
       card = choose(val1,val2,val3,val4);
    }
     
    Last edited: Feb 9, 2019
    Flimshady likes this.
  3. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    Wow, I did not think about using a cooldown, thta would work for me. Thank you very much for your help! :)

    PS: Do you know how to use the choose function if I have different sprites with different subimages, imagine having a sprite for all spade cards, a sprite for all heart cards, and so on?
     
  4. NightFrost

    NightFrost Member

    Joined:
    Jun 24, 2016
    Posts:
    1,853
    You should make them either all different sprites, so each card has unique sprite identifier, or make them all subimages in the same sprite, so each card has unique subimage number. Now you have no single unique identifier for a card and must track suit and number separately to pick the correct image.
     
    Flimshady and BeepBoop like this.
  5. BeepBoop

    BeepBoop Member

    Joined:
    Feb 6, 2019
    Posts:
    6
    You can use Arrays to give each card its own ID. For example:

    Code:
    Card_Name[1] = "6 of Spades";
    Card_Sprite[1] = spr_6spades;
    Card_Name[2] = "7 of Spades";
    Card_Sprite[2] = spr_7spades;
    Card_Name[3] = "10 of Hearts";
    Card_Sprite[3] = spr_10hearts;
    etc...
    Code:
    sprite_index = Card_Sprite[mycardID];
    And here is the example of using ds_lists:

    Create the deck:
    Code:
    mydeck = ds_list_create();
    Add your cards to the deck:
    Code:
    ds_list_add(mydeck, mycardID);
    Shuffle the deck:
    Code:
    ds_list_shuffle(mydeck);
    Retrieve the first card from the deck:
    Code:
    firstcard = ds_list_find_value(mydeck, 0);
    Delete 'firstcard' card from the deck:
    Code:
    ds_list_delete(mydeck, 0);
    (Optional) Add it again:
    Code:
    ds_list_add(mydeck, firstcard);
    Don't forget to delete your ds_list deck when no longer needed:
    Code:
    ds_list_destroy(mydeck);
     
    Last edited: Feb 9, 2019
    dannyjenn and Flimshady like this.
  6. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    Yeah, thats what I thought, thank you for your quick answer! :)
     
  7. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    I will try again now, let's see how far I will come ^^ Thank you for your help :)
     
  8. dannyjenn

    dannyjenn Member

    Joined:
    Jul 29, 2017
    Posts:
    568
    As you've written it, that won't work. Because for one thing, you'd need to set cardcooldown after the loop, not before it.
    Code:
    // create event:
    cooldowncard = -1;
    Code:
    // whenever the player draws a card:
    while(cardcooldown==card){
        card = choose(val1,val2,val3,val4);
    }
    cardcooldown = card;
    Second, even with that change, it still won't work. Because there's nothing to prevent the player from drawing the first card again on the third turn. To fix that problem, cardcooldown would need to be a ds_list, not a single value. And even then, it's not the best way, since that loop could theoretically be infinite (if the computer keeps drawing the exact same card every time... which won't happen, but still...)


    Here's a very simple way of doing it for a standard deck of 52 cards, 13 of each of 4 suits (obviously this will need to be modified for non-standard decks):
    - Make a single sprite with 52 subimages, ordered as follows: A♠︎, 2♠︎, 3♠︎, 4♠︎, 5♠︎, 6♠︎, 7♠︎, 8♠︎, 9♠︎, 10♠︎, J♠︎, Q♠︎, K♠︎, A♥︎, 2♥︎, 3♥︎, 4♥︎, 5♥︎, 6♥︎, 7♥︎, 8♥︎, 9♥︎, 10♥︎, J♥︎, Q♥︎, K♥︎, A♣︎, 2♣︎, 3♣︎, 4♣︎, 5♣︎, 6♣︎, 7♣︎, 8♣︎, 9♣︎, 10♣︎, J♣︎, Q♣︎, K♣︎, A♦︎, 2♦︎, 3♦︎, 4♦︎, 5♦︎, 6♦︎, 7♦︎, 8♦︎, 9♦︎, 10♦︎, J♦︎, Q♦︎, K♦︎.
    - Set things up like this:
    Code:
    deck = ds_list_create(); // make the empty deck
    
    // add the 52 cards to the empty deck:
    for(var i=0;i<52;i+=1){
        deck[|i] = i; // <-- The | is a kind of 'accessor'. It's needed whenever you're using a ds_list rather than an array. Look up 'accessor' in the manual to learn more.
    }
    
    ds_list_shuffle(deck); // shuffle the 52 cards in the deck
    - Draw a card like this:
    Code:
    var card = deck[|0]; // copy the value of the top card in the deck to your 'card' variable.
    ds_list_delete(deck,0); // remove the top card from the deck (otherwise you'll keep drawing the same card every draw)
    - To get the card's numerical value, you do ((card mod 4)+1) edit: ((card mod 13)+1). To get the card's suit, you do (card mod 13) edit: (card div 13). And these macros should come in handy:
    Code:
    #macro ACE 1
    #macro JACK 11
    #macro QUEEN 12
    #macro KING 13
    
    #macro SPADE 0
    #macro HEART 1
    #macro CLUB 2
    #macro DIAMOND 3
    edit - And as @BeepBoop pointed out, be sure to call ds_list_destroy(deck) when you no longer need the deck (such as in its destroy event, or at game end).
     
    Last edited: Feb 10, 2019
    Flimshady and BeepBoop like this.
  9. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    Could you explain this part again, I am sorry but I don't quite get what you are trying to teach me ^^ I've looked up the modulo expression but I still don't get the hang of ((card mod 4)+1) and (card mod 13). And I don't see the coherence with macros... I hope I am not too bugging, thank you for your help anyways :)
     
  10. dannyjenn

    dannyjenn Member

    Joined:
    Jul 29, 2017
    Posts:
    568
    @Flimshady - Sorry, I got a little mixed up on those formulas. They should be ((card mod 13) + 1) for the value and (card div 13) for the suit.


    Values:
    Cards 0, 13, 26, and 39 should be 1
    Cards 1, 14, 27, and 40 should be 2
    Cards 2, 15, 28, and 41 should be 3
    Cards 3, 16, 29, and 42 should be 4
    Cards 4, 17, 30, and 43 should be 5
    Cards 5, 18, 31, and 44 should be 6
    Cards 6, 19, 32, and 45 should be 7
    Cards 7, 20, 33, and 46 should be 8
    Cards 8, 21, 34, and 47 should be 9
    Cards 9, 22, 35, and 48 should be 10
    Cards 10, 23, 36, and 49 should be 11
    Cards 11, 24, 37, and 50 should be 12
    Cards 12, 25, 38, and 51 should be 13

    The 'modulus operator' gets the "remainder" of the division, and can be used to "wrap" the numbers and keep them all within the range of 0 through whatever... in this case, we want all number to remain within the range of 0 through 12. We do that by doing card mod 13. The following sequence
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
    then becomes
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
    But we want the range to be 1 through 13, not 0 through 12. So we add 1: ((card mod 13)+1).


    Suits:
    Any card 0 through 12 is a SPADE (0)
    Any card 13 through 25 is a HEART (1)
    Any card 26 through 38 is a CLUB (2)
    Any card 39 through 52 is a DIAMOND (3)

    Basically, we want to scale the numbers down such as to force the range of 0 through 51 to fit into the range of 0 through 3. i.e. We want to change the sequence:
    0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
    into
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
    To do this, we use div, which is the 'integer division' operator. It's basically the same thing as division but it throws away the "remainder".
    So the formula would need to be (card div 13)
    0 div 13 is 0,
    1 div 13 is 0,
    2 div 13 is 0,
    . . .,
    13 div 13 is 1
    14 div 13 is 1,
    15 div 13 is 1,
    . . .,
    26 div 13 is 2,
    27 div 13 is 2,
    28 div 13 is 2,
    . . .,
    39 div 13 is 3,
    40 div 13 is 3,
    . . .,
    51 div 13 is 3.


    Macros:
    Macros are just a kind of constant. All they do is make the code more legible and easier to remember...
    e.g. card_suit==CLUB makes a lot more sense than card_suit==2
    e.g. card_value==QUEEN is a little easier to work with than card_value==12
     
    Flimshady likes this.
  11. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    Now that‘s what I call an answer. It makes much more sense to me now, thank you very much for taking the time. I am currently not at home, but I will try it out your way and you will be hearing from me. :)
     
    dannyjenn likes this.
  12. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    Okay, I am stuck again...
    Code:
    /// Create the deck
    deck = ds_list_create();
    
    // Add the cards
    for (var i = 0; i < 52; i+=1) {
        deck [|i] = i;
    }
    
    // Shuffle the deck
    ds_list_shuffle(deck);
    
    card = deck [|0];
    ds_list_delete(deck, 0);
    
    card_value = ((card mod 13) + 1);
    card_suit = (card div 13);
    if(card_value = 1 and card_suit = 0) {
         image_index = 0;
    }
    if(card_value = 2 and card_suit = 0) {
         image_index = 1;
    }
    if(card_value = 3 and card_suit = 0) {
         image_index = 2;
    }
    if(card_value = 4 and card_suit = 0) {
         image_index = 3;
    }
    if(card_value = 5 and card_suit = 0) {
         image_index = 4;
    
    /// And so on and so on...
    }
    This is what I got so far. I've placed this in my obj_deck create event, but when I start my game, the sprite subimages just cycle though. Thank you for your help ^^
     
  13. Tsa05

    Tsa05 Member

    Joined:
    Jun 21, 2016
    Posts:
    548
    Have you set the image_speed to zero?
     
    Flimshady likes this.
  14. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    Oh my god... I am dumb, thank you ^^ But now it only shows my the first subimage of the sprite, but the code should give it another, according to its card_value and card_suit. What am I doing wrong here?
     
  15. chamaeleon

    chamaeleon Member

    Joined:
    Jun 21, 2016
    Posts:
    931
    I don't know why you're not seeing different images, but I'm curious as to why you don't simply assign "card" to image_index, rather than having 52 if statements, given matching ordering of your frames in the sprite. The values you're assigning now are essentially reversing the mod/div computation to get back the original value.
     
    Flimshady and dannyjenn like this.
  16. dannyjenn

    dannyjenn Member

    Joined:
    Jul 29, 2017
    Posts:
    568
    Yeah, you don't need those if statements.

    But, where exactly are you putting that code? It should go in a controller object, not in the card object.
    Also, the 'creating the deck', 'adding the cards', and 'shuffling' should go in the create event, but the rest of the code should go someplace else (probably in some sort of mouse click event).
     
    Flimshady likes this.
  17. Flimshady

    Flimshady Member

    Joined:
    Jan 3, 2019
    Posts:
    9
    I've got it to work now, here is the code for everyone who is interessted! Thank you all very much for your support! <3
    Code:
    /// In obj_deck - Create Event - Create the deck
    deck = ds_list_create();
    // Add the cards
    for (var i=0; i < 52; i+=1) {
        deck[|i] = i;
    }
    // Real random shuffle
    randomize();
    //Shuffle the deck
    ds_list_shuffle(deck);
    Code:
    /// In obj_deck - Left Pressed - Remove the card from the deck
    if(ds_list_size(deck)>0) {
    var top_card = instance_create_depth(x, y, -1, obj_card);
    var card_sprite = ds_list_find_value(deck, 0);
    top_card.image_index = card_sprite;
    ds_list_delete(deck, 0);
    }
    Here, I just have 3 subimages for my playing card deck, which I want to change depending on how big the remaining list is.
    Code:
    // / In obj_deck - Step Event - Changing the deck's sprite
    var deck_size = ds_list_size(deck);
    image_index = min(3, deck_size);


    Code:
    /// In obj_controller - Create Event - Create the global var to keep track of drawed card
    global.card = noone;
    Code:
    /// In obj_controller - Step End - Move the card
    if(global.card !=noone) {
        with (global.card) {
            x=mouse_x;
            y=mouse_y;
        }
    }


    Code:
    /// In obj_card - Create Event - Set the image speed to 0
    image_speed = 0;
    Code:
    /// In obj_card - Left pressed - Pick up the card
    global.card = id;
    depth = -1;
    Code:
    /// In obj_card - Left Released - Drop the card on the ground or on the deck
    global.card = noone;
    depth = 0;
     
    Last edited: Feb 16, 2019
    dannyjenn likes this.

Share This Page

  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice