Nour
Nour

Reputation: 5449

How to represent this structure in Redis

Let's say I'm building a cards game (I'm using an analogy as I can't disclose the original project details). Consider the following structure:

Dealer1
    91 // Card 9 of spades (Second digit represents card type, check the legend below)
        Rejectors:
            John
    A2 // Ace of hearts
        Rejectors:
            Rowan
    J3
    K2
        Rejectors:
            David
    33
Dealer2
    43
    52
        Rejectors:
            David
    13
Dealer3
    44
    83
    93


//  1: spades ♠, 2: hearts ♥, 3 diamonds 4: clubs ♣.

The dealer deals a card (It gets added to his list), Only one player at a time gets one chance to pull the card, look at it and either keep it or reject it (put it back into the deck).

If the card is rejected, we mark the name of the player (so next time he can't pull it).

If the card is kept, it is removed from the list above.

If the card is being looked at by any player, it is not counted into any other player list (We can remove it temporarily from the list).

I want to be able at any moment to show a player how many cards left for him to pull.

For instance, if John asked how many cards left for Dealer 1 and Dealer 2, the answer would be 7 cards (A2, J3, K2, 33, 43, 52, 13), remember card 91 was rejected previously by John.

Now if Hanna asks how many cards for the same dealers the answer would be 8 (she hasn't rejected any card before, therefore her name is not in any dealer list)

Rules:

What is the best approach to save this in Redis? Sets? Hashes?

The first try, I just saved a serialized object as follows (not necessarily the same list above):

// Key 1
"Dealer1": [
    {
        "Card": "A1",
        "Rejecters": [
            "John"
        ]
    },
    {
        "Card": "K2",
        "Rejecters": [
            "David"
        ]
    }
]

// Key 2
"Dealer2": [
    {
        "Card": "31",
        "Rejecters": [
            "Adam"
        ]
    },
    {
        "Card": "Q2",
        "Rejecters": [
            "David"
        ]
    }
]

The key is the dealer id, the value is a serialized array of objects, each object represents a card and its "rejectors" (not the best name maybe) list.

I know this is not efficient, as every time I need to query the count of available cards for a player, I have to loop on the dealers' keys requested, fetch its whole list, count (client-side) how many objects in the list where the player name is not present.

PS: I'm using ServiceStack.Redis C# client (but I can handle raw Redis commands / Data types, and I can translate them into C# code).

Upvotes: 1

Views: 156

Answers (1)

AwesomeHunter
AwesomeHunter

Reputation: 750

Create a redis set for each card dealer.
For example,

"dealer_1_set" : ["91,"A1"]

"dealer_2_set" : ["A2,"A3"]

"dealer_3_set" : ["B9,"B10","36"]

For each card rejected by John, maintainn a redis set for him.

"cards_rejected_by_john_set" : ["91","A3","36"]

Now to calculate the available cards from dealer 1 and dealer 2 for John

use redis command

SINTER dealer_1_set dealer_2_set ... (add more dealer sets if you want)

You get new set, say temp_set ["91","A1","A2,"A3"]

Then use redis command

SDIFF temp_set cards_rejected_by_john_set

Then you get ["A1", "A2"] , which is the result.

The above operations should be pretty fast. But to make the above actions atomic, you'll need to write a Lua script.

Upvotes: 1

Related Questions