Well, a card game has very defined states, you can interact with your cards in play and in hand, and the rules of those cards are player indipendent and can do whatever they want.
This is not particularly hard to manage.
But, for example, in a economy game, if you are caught using speculative founds, you are forbidden to trade in a particular state.
A naive solution is the one to lock the button in the ui, but that does not work well with ia. Another is to code that in the trade function, but what if I want an hidden effect that forces the player to trade even if he can't?
The trade function shouldn't be able to know if the player can or cannot do that action, otherwise everything becomes too complex.
And networking is not even in the picture.
My current solution is done by using 3 classes.
Action, actor and target.
An action has a list of allowed types of targets and actors that can call it.
An actor has a list of allowed action that can execute.
And a target has a list of allowed actions and a list pairs of actions and actors that cannot interact with him.
this solves the problem I was talking about before., if a player is forbidden to trade in America you simply add him, and the trade action to the forbidden pairs in America.
Finally I made a wraparound to this system, where every action, actor and target has an id, so instead of calling actions using their object, you use their id, so you can send those data to the server.
This, as far as I can see, is the best way. But I don't know if other people have better ones