Trigger game end properly

Game development with Board Game Arena Studio
Post Reply
User avatar
Woodruff
Posts: 412
Joined: 08 March 2014, 00:53

Trigger game end properly

Post by Woodruff »

Hello everybody,

On PHP side, I have a function for transfering a card from some place to another (called self::transferCardFromTo).
Its execution can trigger the end of the game under some conditions. In that case, the game must stop immediately after this function has returned.

As far as I understand, to finish a game properly I have to do two things:
  • Call $this->gamestate->nextState('gameEnd'); which is the job of self::transferCardFromTo
  • Clear the stack of the parent functions which last child was the call for self::transferCardFromTo
Since I use self::transferCardFromTo everywhere in my code, with other instructions after that, it would be too clumsy to bubble the fact that the game end through parent function in order to make them return (using a boolean for example).
Is there a way to stop in place the execution of this stack? Can I throw a particular exception to do that?

Thanks a lot!

Tchebychev

PS: I want to apologise if I'm not clear in this message :| : There are a lot of technical terms I'm not familiar with in English so do not hesitate to make me rephrase.
User avatar
Victoria_La
Posts: 620
Joined: 28 December 2015, 20:55

Re: Trigger game end properly

Post by Victoria_La »

I think I understand what you saying, but it usually is not good idea to trigger transition to end game state from utility function,
the cleanest would be to make this function return a boolean indicating end of game, and do that in caller function, i.e.

if (self::transferCardFromTo(...)===true) {
$this->gamestate->nextState('gameEnd');
} else {
...
$this->gamestate->nextState('next');
}

Yes you can throw exception but then you have to process this exception yourself in every method it can be called from and process
transition, not sure its any better.
User avatar
Woodruff
Posts: 412
Joined: 08 March 2014, 00:53

Re: Trigger game end properly

Post by Woodruff »

Thanks Victoria_La,

Your piece of code is exactly what I had in mind when I said "bubbling", that is passing a boolean. But hold on; I have an hundred cards the game and each one has its specific piece of code :/ Does that mean I have to repeat this test an hundred times? Does not seems to be a clean way to do in my case...
Could you provide me an example of what it would look like using exceptions? I think it would be easier that way because I have far less methods that eventually trigger a call on the utility function than cards to code.

Thanks by advance :)

Tchebychev
User avatar
docthib
Posts: 73
Joined: 10 August 2015, 14:05

Re: Trigger game end properly

Post by docthib »

Which game it is ? :)

Maybe you could explain / illustrate how your states.inc.php is built and which and how your functions are called ?
Last edited by docthib on 15 June 2017, 20:44, edited 1 time in total.
User avatar
Woodruff
Posts: 412
Joined: 08 March 2014, 00:53

Re: Trigger game end properly

Post by Woodruff »

Hi docthib,

The game is Innovation by Carl Chudyk. But wow, the game state machine is hard to explain: the hard part is managing card effects (dogma), with nested states but I think it will be hard for you to understand, and me to explain, if you already don't know this game. But who knows :)
The game ends most of the time with a particular being transferred. Transferring cards is a base mechanism for this game, that's why there is an utility function dedicated for it.
I enables gameEnd transition on any state that call that utility function, there are currently 5. But the main problem is that I manage code for specific cards (like Seasons, each card has a specific effect) in four gigantic case/when in four dedicated functions. Among these four functions, three contains calls to the utility function, which match 3 of the 5 states.

Tchebychev
User avatar
docthib
Posts: 73
Joined: 10 August 2015, 14:05

Re: Trigger game end properly

Post by docthib »

Hi Tchebychev,

I don't know the game but tried to read the rules briefly.
From what I understand, you can win in 3 different states / action (correct me if I'm wrong) :
- Achieve
- Draw
- Dogma

During Player X Dogma action, every other players can also execute their dogma effects (under conditions) and eventually, win the game (or make someone win), right ?

So your states should look like

BeginPlayerTurn
-> PlayerChooseAction
(draw, meld, achieve, dogma)

--> PlayerChooseDogma
(Resolving effects)

---> ActionToTakeToResolveEffect (loop as long as need)
(Resolving effects)

--> OtherPlayerShareDogma (loop all players if eligible, then second action or end turn)
(Resolving effects)

---> ActionToTakeToResolveEffect (loop as long as need)
(Resolving effects)

EndPlayerTurn


So every state including 'Resolving effect' may trigger endGame.
I think you should have a function ResolveDogma that call a function ResolveEffects for every Dogma's effect.
If you don't want some effects to be resolved add some global boolean (self::setGameStateValue( 'endGameTriggered', true) and at start of the ResolveEffects function check if 'endGameTriggered' == true then just return.

Said like this it sounds simple but it may help you, else you can explain me more :p
User avatar
Woodruff
Posts: 412
Joined: 08 March 2014, 00:53

Re: Trigger game end properly

Post by Woodruff »

Hi docthib,

Congratulations, you correctly predicted how my gamestates are! For a game you did not know before, I can just say bravo!!
I have indeed an equivalent of the ResolveEffect function

The thing is there is another level of nesting in the case when player interaction is needed (a player has a choice to make on client side), so there is potentially another loop inside a given card effect.
Whether there is player interaction or not, game end can be triggered by achieve or draw (dogma not being a problem) inside the effect itself, interrupting it. So I cannot simply put the test on the ResolveEffect function.

For example, a card forces (through an "I demand" effect) a player to draw a card, then transfer a card from his hand to the opponent hand. Let's say there is no card left in stock. The first part of the effect triggers game end by draw, so the second part is not executed.
That's the point, I can't put a test on every effect that can trigger game end before being completed. In the way I designed the game, that would mean insert the same piece of code in dozens of case blocks.

I think I've solved the problem using try/catch blocks, like Victoria_La suggested. Now I just need to throw an custom exception (which inherits for the base class Exception) when the game ends and bubbles it on parent functions until it reaches the ultimate level: the state function or the action function from which all calls originated. Then I catch the exception for the last time and put the gamestate change to 'gameEnd' here. As a result, I have only six blocks of that kind (one in the ResolveEffect function) instead of many more test blocks.

I am still doing some tests to check everything's alright then I put a [SOLVED] flag on this thread.

Thanks a lot for your help :D

Tchebychev
Post Reply

Return to “Developers”