Page 1 of 1

Advice for multi-card actions

Posted: 25 July 2020, 20:01
by jephly
I'm looking for advice on the best way to implement an action where the player plays multiple cards.

In this game (Letter Tycoon), the player has a hand of cards, each with a letter. The player can form a word from these cards and play it. There are also several nuances: some letters in the word can come from a shared "community pool", some letters can be added to the word using special powers, and some letters have options associated with them (the player can choose whether each Y is a consonant or a vowel, which can affect scoring). There is also a special power that allows the player to play two words.

Once the word is played, other players have a chance to see it and possibly challenge it. So, the played word needs to be stored in the database regardless. The question is whether it gets stored only after it is "played", or incrementally as the player is building it up.

Option 1: Player builds up the word (or words) on the client, and sends the whole word as a single action.
Option 2: Player builds up the word (or words) one letter at a time, sending each letter as a separate action.

Here are some pros and cons:
- Sending the whole word, with all the necessary options, in a single action is awkward, given the available arg types. I'd probably need to send several different coordinated AT_numberlist args to capture every property of each letter.
- If the word is sent one letter at a time, then it'll be stored in the database before it's supposed to be visible to others, so I'll have to be careful not to show it to others before it is "played". If it's sent only once it is played, this isn't a risk.
- If the word is sent one letter at a time, then the in-progress word will persist if the active player refreshes their browser. This is probably a good thing, but I'm not sure what the expectations are around this. Might this be confusing to the player? Might they think the word is visible to others when it's not (yet)?
- I want to provide a "clear" or "reset" button to start building the word over, since the user could change their mind once they see all or part of the word, or they might make a mistake partway through. If the word is sent all at once, then this "clear" is pure client-side, and therefore simpler to implement. If the word is sent letter-by-letter, then this would have to be a separate action that updates the database. This is slightly more complex, though not too bad.
- The order of the letters is of course important. I'm not sure if relying on the order of the actions to play each letter could be a problem. Perhaps this is a non-issue, and order of actions is preserved even if they are done quickly. (Formed as a question: is there any chance of actions sent by the same player in quick succession to be received by the game logic out of order?)

Any thoughts or advice you have on this question would be appreciated. Thanks!

Re: Advice for multi-card actions

Posted: 25 July 2020, 23:00
by paramesis
I would strongly encourage option 1. The two main reasons you would want multi-step actions to each have their own database transactions would be
1. You want to verify the legality of each part of a move and wouldn't want to (and shouldn't) duplicate complex server-side logic.
2. You want other people to see each step as it happens.

It doesn't sound like either applies here, as the verification of each letter sounds fairly simple. I would go with organizing the entire turn on the client side and sending it as a single action.

The arguments don't need to be as complex as you're imagining since you can pass strings of variable length.

You could send the arguments back as a "Structure of Arrays" where each array is a string.

Maybe one string is just the sequence of letters representing the word(s) played, and another is a sequence of card id's delimited by underscores, and another is a sequence of card source locations or powers used, etc...

Code: Select all

card_letters = "car_hat"
card_sources = "hhp_pph" (hand hand pool, pool pool hand)
card_ids = "21_18_85_82_1_6"
...
I don't know the upper limit on length of string arguments, you may need to test that.

Re: Advice for multi-card actions

Posted: 25 July 2020, 23:15
by Tisaac
I would say that the "refreshing their browser" might be crucial depending on how much action/click is needed before "confirming" the word.

For the privacy, it should be pretty easy to add a field "public" that you set to false at the start of the state, and that is then set to true when leaving the state.

The order of letters can be guaranted using "lock : true" when doing ajaxCall for each single letter if you choose this solution.

Are there any letters that can no longer be selected because of some already selected letters ? That could also give solution 2 some advantage.

Re: Advice for multi-card actions

Posted: 26 July 2020, 00:50
by jephly
Thanks paramesis for the good ideas of how to structure the args. I had something like that in mind, but you've provided even more options. Since the number of letters is small (no more than a dozen) I'm not worried about lengths of strings.

You're right that there's no need to verify each letter server-side (before the whole word is officially "played"), and there's certainly no need for others to see the word before it is "played".

Thanks Tisacc for the suggestions of how to ensure the data is private and to ensure the ordering is guaranteed (in the option 2 scenario).

Since the user is playing cards to make their word, and possibly using some "once-per-turn" powers, there are several kinds of restrictions on what they can play. However, these are easy to ensure client-side during word-building (for ease of use), and verify again server-side when the word is "played" (for correctness). In fact, some rules (e.g. minimum word length of 3) would have to be broken temporarily while word-building in either scenario, so the checks need to be slightly different client-side and server-side anyway. I don't think these constraints point conclusively towards either option.

I suspect the main tradeoff is between persistence of a word-in-progress (with option 2) and likely faster (pure client-side) interactions (with option 1). Since it's probably uncommon for a user to leave the game and return while building a word, and losing a word-in-progress isn't a big loss anyway (it's just a few clicks to re-build), I'm not sure how much of a benefit persistence would be. On the other hand, requiring a (synchronous) round-trip for each letter will likely slow down the interaction considerably - and this is the single most frequent action in the whole game. (I already have basic client-side interactions implemented, and it's quite fast and smooth.) So, I am leaning towards option 1.

Thanks again for your thoughts.