Page 1 of 1

Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 01:14
by MikeIsHere
So I am running into a problem two people ran into in 2014 and I could not find a good answer on -- how to keep track of cards played in order
right now from the heart tutorial I have

Code: Select all

$this->cards->moveCard($card_id, 'cardsontable', $player_id);
And the cards play fine left to right on both clients side because of CSS
But once the person reloads the page the cards are out of order in the Deck class (I believe because of the cardId)
So I figured there are a couple of ways to design this but I not sure if one is better than the other

1) I can change the above line to
$this->cards->moveCard($card_id, 'cardsontable_'.$player_id, $orderOfPlay);
or even
insertCardOnExtremePosition($card_id, 'cardsontable_'.$player_id, false);

Then keep track of the location so I can pull them out later
$this->cards->getCardsInLocation( 'cardsontable'.$player_id );
for each player passed through a gameData array

And then moveAllCardsInLocation will be a little more challenging to clear the boards

2) I can add another field to the 'card' table but it looks like I will have to write custom sql for every deck operation. While the sql structure / sql is not a problem, it does seem like recreating the wheel for the addition of one field, plus I am unsure of any other actions the build in methods perform rather than just returning a collection

3) similar to 2 I can build my own sql table to keep track of the cards played

Is there a best practice to handle this type of game state?

Re: Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 09:45
by RicardoRix
I think the only thing you might be missing is the the JS Stock item has a sort by weight. That you need to specify the played order.
http://en.doc.boardgamearena.com/Stock
Refreshing the page is likely a JS problem, otherwise you're not syncing your data correctly.

For the game Palace, I double used the card_location_arg, so when it was in the players hand, it was the player_id (no weight used for the players hand stock item), when it had been discarded it became the order_played(use the weight in the discarded stock item). The location changes from 'hand' to 'discard'.
If that doesn't work for you, then like you've already said I think you could either make a location per player, or add an extra sql field (best)

Re: Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 11:28
by DrKarotte
What exactly is the problem?
The deck (on server side) and stock (which displays the cards on client side) must be connected properly.
The card order in the stock is done by the itemweight property. In Hearts it is based on card value and color. If they should arrange otherwise, e.g. in the order they have been played, you need to change the item weight according to this value. Usually something like that is stored in the location arg.

Re: Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 15:28
by MikeIsHere
I am glad I asked this question because I think I am missing a concept

I start by creating the Deck and picking 6 cards, just like in the hearts demo

Code: Select all

        $cards = array();
        foreach ( $this->colors as $color_id => $color ) {
            for ( $value = 1; $value <= 13; $value ++) {
                $cards[] = array('type' => $color_id, 'type_arg' => $value, 'nbr' => 1);
            }
        }

        $this->cards->createCards( $cards, 'deck');

        // Shuffle deck
        $this->cards->shuffle('deck');

        // Deal 6 cards
        $players = self::loadPlayersBasicInfos();
        foreach ($players as $player_id=>$player) {
            $this->cards->pickCards(6, 'deck', $player_id);
        }
Then in the getAllDatas I return the hand data from the database
$result['hand'] = $this->cards->getCardsInLocation( 'hand', $current_player_id);

on the Js setup side I setup the stock with the current weight being suit+value as DrKarotte mentioned

Code: Select all

            this.playerHand = new ebg.stock();
            this.playerHand.create( this, $('myhand'), this.cardWidth, this.cardHeight)
 
            this.playerHand.image_items_per_row = 14;
            dojo.connect( this.playerHand, 'onChangeSelection', this, 'onPlayerHandSelectionChanged' );
            
            for(let color = 1; color <= 4; color++) {
                for(let value = 1; value <=13; value++) {
                    let card_type_id = this.getCardUniqueId(color, value);
                    this.playerHand.addItemType(card_type_id, card_type_id, g_gamethemeurl + 'img/cards.png', card_type_id);
                }
            }
            // card back 
            this.playerHand.addItemType(14, 14, g_gamethemeurl + 'img/cards.png', 14);
Then I read the hand data and assign each card to the playerHand

Code: Select all

          for ( let i in this.gamedatas.hand) {
                var card = this.gamedatas.hand[i];
                var color = card.type;
                var value = card.type_arg;
                console.log(card, color, value, this.getCardUniqueId(color, value), card.id);
                this.playerHand.addToStockWithId(this.getCardUniqueId(color, value), card.id);            
            }     
The stock is automatically sorted

Image

The DB looks like
Image

Now to play each card on playerSelection I have a call back to the server which moves the card from Deck to CardsOnTable
$this->cards->moveCard($card_id, 'cardsontable', $player_id);

A notification comes back from the server and the playCardOnTable, similar to the hearts demo but I slide the card to a specific position [and this may be my problem]

Code: Select all

        playCardOnTable: function (player_id, color, value, card_id) {
            var cardsPlayed = document.querySelectorAll("[id^=cardontable_" + player_id + "]").length;
            console.log('cardsPlayed='+cardsPlayed,'player_id='+player_id,'color='+color, 'value='+value, 'card_id='+card_id);
            dojo.place(this.format_block('jstpl_cardontable', {
                x: this.cardWidth*(value-1),
                y: this.cardHeight*(color-1),
                player_id: player_id,
                card_id: card_id
            }), 'playertablecard_' + player_id);
            console.log('dojo.placed');
            if (player_id != this.player_id) {
                this.placeOnObject('cardontable_'+player_id+'_'+card_id, 'overall_player_board_'+ player_id);                
            } else {
                if ($('myhand_item_' + card_id)) {
                    this.placeOnObject('cardontable_'+player_id+'_'+card_id, 'myhand_item_' + card_id);
                    this.playerHand.removeFromStockById(card_id);                                    
                }
            }
            this.slideToObjectPos('cardontable_'+player_id+'_'+card_id, 'playertablecard_' + player_id, cardsPlayed*this.cardWidth, 0, 1000, 0).play();
        },

Then after playing all cards both clients are in sync and the db just has cardsontable with an arg of just the player id
Image

Image

Now the issue

When either player reloads their browser I get the cards on the table from
$result['cardsontable'] = $this->cards->getCardsInLocation( 'cardsontable' );

and the setup in the .js file runs

Code: Select all

         for (let i in this.gamedatas.cardsontable) {
                var card = this.gamedatas.cardsontable[i];
                var color = card.type;
                var value = card.type_arg;
                var player_id = card.location_arg;
                this.playCardOnTable(player_id, color, value, card.id);
            }
Note here I am replaying everything on to the table -- but I don't know what the sort order of the array this.gamedatas.cardsontable is and the hand now looks like on the right

Image

So it is not sorted by weight or original insert into the DB the sort order seems to be by card_id, which I am not sure how the ids are out of order if the initial insert array was in suit-value order

So this is where I was walking through the ideas of changing the location and making the arg the playorder, or adding another field to the database so it is

cardsontable playerid playOrder

What am I missing

Re: Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 17:29
by RicardoRix
The short story is: use the weight argument of the stock.

Are you using stock items for all different things? You probably should be, and you can easily shift cards from one stock item to the other.

http://en.doc.boardgamearena.com/Stock
Look at the bottom - Situation B. You don't need the dojo.place and such.

In any stock items of the last 2 images the cards do not appear to be sorted in any consistent way.

When a card is played, does it need to be associated to the player anymore?
If yes, then add a new field: order, use this as the weight argument in all the stock items and adjust it as necessary in the DB.
In no, then you can double use the card_location_arg field and set the order there. In the 'Played' stock item make sure you using weight according to this. In player hand / other stock items according to the rank/suit.

Re: Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 17:53
by MikeIsHere
In any stock items of the last 2 images the cards do not appear to be sorted in any consistent way.
It is sorted by cardid that is retrieved from the getfromLocation, and then looped in the order of the records

Image
from this image you can see
cardId 2 - card type 4(diamonds) card_type_arg = 6 (value)
cardId 3- card type 3(heats) card_type_arg = 2 (value)
cardId 15 - card type 4(diamonds) card_type_arg = 1(Ace) (value)
cardId 17 - card type 2(spades) card_type_arg = 11(Jack) (value)
cardId 18 - card type 1(clubs) card_type_arg = 10 (value)
cardId 18 - card type 1(clubs) card_type_arg = 9 (value)
When a card is played, does it need to be associated to the player anymore?
Yes because at the end of play each player scores their hand (this game is going to be cribbage, I hope)
If yes, then add a new field: order, use this as the weight argument in all the stock items and adjust it as necessary in the DB.
In no, then you can double use the card_location_arg field and set the order there. In the 'Played' stock item make sure you using weight according to this. In player hand / other stock items according to the rank/suit.
This is where I am lost then I guess, because currently my playerboards are not officially stock items, maybe it should be. Currently it is just a div to move cards to for visual effect.

If on the other hand I make it a stock item and "adjust the DB" then will I have to write all custom queries or will getCardsInLocation return all fields and can I insert/update with moveCard

And if I write the custom queries is that all that is needed, the query and the execution or are there other items that must be maintained

BTW I am starting to look at Palace to understand concepts, it looks like a really polished game

Re: Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 18:43
by RicardoRix
yeah, you're probably right about the custom queries, I can't remember all the ins-and-outs.

But I definitely recommend using stock items everywhere for a card game like this, makes things much simpler. It's an 'in for a penny in for a pound' kinda thing.

From recollection in Situation B, using the from_id was key to get the animations smooth:
On the destination Stock, use addToStockWithId with a "from" argument which is the HTML id of the corresponding item in the source Stock. For example, if the source stock id is "myHand", then the HTML id of card 48 is "myHand_item_48".

Re: Keeping track of card play order - Best Practices with DB

Posted: 21 May 2020, 18:59
by DrKarotte
The card id from the deck cannot be used for sorting purposes, it is pure random, generated by the module.

It must not be confused with a card ID generated and used und client side.

If I remember correctly in Hearts there is a function "createUniqueCardId". You hand over value and color, and it returns an id, which represents the card order. There must be a reciproque function which returns color and value when handed over an id.

Re: Keeping track of card play order - Best Practices with DB

Posted: 23 May 2020, 19:18
by MikeIsHere
I just wanted to come back and say thank you -- with a better understanding of Stocks helped me push forward