-
Notifications
You must be signed in to change notification settings - Fork 707
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
reset behavior of activePlayers #445
Comments
activePlayers
Proposal 1 is implemented in 4a51096. I'll keep this RFC open for a while in case people come up with better ideas that would warrant reverting the change and implementing something else. |
I'll try out this implementation when I'm back at my computer, but I am still concerned about this approach as I wrote in #442:
There would need to be an opportunity to idiomatically intervene on this reset behaviour to at least declare that you want to disable it or pass a function that can return My instinct is still that a |
Oh, it's not specific to It just happens whenever I also like the idea of having What do you think of the following semantics?
|
Oh, right, once Quick scenario though, that I think still makes resetting to the previous state (as a default) a challenge:
This isn’t the best example, but I hope it demonstrates the problem. Maybe a better scenario would be if one of the players in the “discard” stage could play a card that causes all players to take an action before continuing to discard or something. If resetting is a default, it should be consistent, which would mean storing a full history. You could argue that the above scenario would be programmer error — that they should know not to empty I guess this is to say that whether dealing with a default reset behaviour or a With setActivePlayers({
others: 'discard',
next: {
value: { ...ctx.activePlayers }
},
}) |
The Let's say you build a generic Each time you reach the discard stage, you want to revert back to where you came from. Having a hardcoded In fact, this is how phases work at the moment. When you call |
Hmmm, right. Ok, here’s my understanding of the challenges/goals:
Is it worth exploring an extended // phases config
turn: {
activePlayers: {
setup: {
start: true,
currentPlayer: 'setup',
next: 'main',
},
main: {
currentPlayer: true,
},
militia: {
others: 'discard',
revert: true,
},
},
stages: {
setup: { moveLimit: 1, /* ... */ },
discard: { moves: { /* ... */ } },
}
} // respects `next` or `revert` in active player configs, sets to `null` otherwise
events.endActivePlayers()
// but also possible with a passed argument
events.endActivePlayers({ next: 'militia' })
// shorthand set syntax
events.setActivePlayers('militia') Not sure what the difference between set and end would be in the last two cases. Considerations
|
Couldn't have articulated it better myself. Yes, the key point is that with stages you're dealing with individual states (the stage that a particular player is in) and also a configuration (a set of stages). I actually did try to explore this direction (of using named configurations) when I was fleshing out the stages API, but decided against it because:
const SETUP = {
start: true,
currentPlayer: 'setup',
next: 'main',
};
const MAIN = {
currentPlayer: true,
};
const MILITIA = {
others: 'discard',
revert: true,
};
...
setActivePlayers(MILITIA); If supporting named configurations is merely going to force people to organize their code in a better way, I'd rather that we do that by publishing a style guide rather than adding to the API. |
This is an interested direction to explore as well. I think the main challenge would be communicating that these trigger for a player configuration, and not for individual players entering particular stages.
Yes, this is easy to do (and I'm for it). We should store a stack rather than just the previous value. It won't add any additional state unless you actually use it, so that's a good thing. |
Ok, great — this clarified a lot of stuff for me. So the only advantage of actually declaring active player configurations would be supporting function fields like |
Yes, that's right. I think let's revisit the named configuration thing after the branch is merged into master (and once we encounter a use case that's very painful to implement without things like endIf). |
So, it sounds like the things that we want to implement right now before merging the branch are the following. Just recording them for my own benefit so I know what to implement next. Feel free to contribute in any of these areas (just let me know so that we're not working on the same thing). Depending on how much help I get with these, maybe I'll start working on the docs first so things can happen in parallel.
Have I missed anything? |
This looks good to me. I’d add:
How would be best to support the current |
I’m working on the
Previously, |
Why don't we get rid of it entirely? People can check turn: {
endIf: (G, ctx) => ctx.activePlayers === null,
} |
Just to make sure we're on the same page when it comes to the semantics of If
If
Does this match what you had in mind as well, or did you imagine it differently? |
100% identical! I’ll also remove |
It’s worth noting that that solution is not sufficient, because endIf: (G, ctx) => ctx.numMoves && ctx.activePlayers === null |
…yersDone (#449) * feat: Implement `revert` flag and use array for `_prevActivePlayers` Contributes towards #445. `_prevActivePlayers` is now always an array, which will be empty unless `setActivePlayers` (or `turn.activePlayers`) is passed `{ revert: true }` at which point the previous state will be stored. If `activePlayers` becomes empty and there is something saved in `_prevActivePlayers`, the last item will be used to restore `activePlayers`. * feat: Remove `activePlayersDone`
I’ve been thinking about the next steps and here are the two discussion points I still think need tackling:
|
I think We can use |
re: moveLimit Dynamic
|
Also I just realized that there is probably no harm in merging the |
So I'll probably do that once #450 is merged. EDIT: |
…yersDone (#449) * feat: Implement `revert` flag and use array for `_prevActivePlayers` Contributes towards #445. `_prevActivePlayers` is now always an array, which will be empty unless `setActivePlayers` (or `turn.activePlayers`) is passed `{ revert: true }` at which point the previous state will be stored. If `activePlayers` becomes empty and there is something saved in `_prevActivePlayers`, the last item will be used to restore `activePlayers`. * feat: Remove `activePlayersDone`
Ok, so the to do looks like:
Later we could also add:
|
Yeah, let's go for the bare minimum since this is a new API and add stuff as we encounter use-cases that are difficult to implement. I'm working on |
Also, for // used to set different move limits for different players
setActivePlayers({
all: 'play',
moveLimit: {
currentPlayer: 2,
others: 1
}
}) and a more concise version: // used to set one move limit for all players
setActivePlayers({
all: 'play',
moveLimit: 2 // equivalent to moveLimit: { all: 2 }
}) The docs can introduce just the concise version initially and readers only need to learn about the more advanced version if they really need it. |
I’m working on this and had the exact same thought. Should we even support |
That's a good point. Maybe we should just support |
To support Here’s my proposal:
Some implementations and their issues:
I’ll go with 1 for now, but let me know if you have any thoughts. |
Spawning off a thread from a previous discussion at #442, which is talking about (among other things) what to do to
activePlayers
after it becomes empty (this is a new concept in thephases-overhaul
branch).Background
activePlayers
is a map that keeps track of all the players that can make a move on the current turn. This is an evolution of the current conceptactionPlayers
. It also keeps track of what "stage" each active player is in. A "stage" is analogous to a "phase", and basically restricts what moves the player in that stage can make. It can be manipulated using something like this:which does the following things:
activePlayers
.discard
.activePlayers
.This allows implementing cards that allow other players to take an action before reverting back to the current player (the Militia card in Dominion, for example).
Problem
Players are removed from
activePlayers
once they make a move. AfteractivePlayers
becomes empty, it is set tonull
(which means that only the current player can play, but they are not in any stage).However, if the
currentPlayer
was in a stage to begin with (i.e.activePlayers
was something like{ currentPlayer: 'play' }
beforesetActivePlayers
was called), then this state is lost.Proposals
Reset
activePlayers
to the previous state beforesetActivePlayers
was called once it becomes empty.Pass in the state to reset to in the
setActionPlayers
call itself.Notes
activePlayers
becomes empty?The text was updated successfully, but these errors were encountered: