You can divide players into groups for multiplayer games. (If you just need groups in the sense of “treatment groups”, where players don’t actually interact with each other, then see Treatments.)
To set the group size, go to your app’s Constants and set
players_per_group. For example, for a 2-player game,
players_per_group = 2.
If all players should be in the same group,
or if it’s a single-player game, set it to
Each player has an attribute
which will tell you if it is player
Group objects have the following methods:
Returns a list of the players in the group (ordered by
Returns the player in the group with the given
Returns the player with the given role. If you use this method, you must define the role method. For example:
class Group(BaseGroup): def set_payoff(self): buyer = self.get_player_by_role('buyer') print(buyer.decision) # etc ... class Player(BasePlayer): decision = models.BooleanField() def role(self): if self.id_in_group == 1: return 'buyer' else: return 'seller'
Getting other players¶
Player objects have methods
get_others_in_subsession() that return a list of the other players
in the group and subsession.
By default, in each round, players are split into groups of
They are grouped sequentially – for example, if there are 2 players per group,
then P1 and P2 would be grouped together, and so would P3 and P4, and so on.
id_in_group is also assigned sequentially within each group.
This means that by default, the groups are the same in each round,
and even between apps that have the same
If you want to rearrange groups, you can use the below techniques.
Subsessions have a method
group_randomly() that shuffles players randomly,
so they can end up in any group, and any position within the group.
If you would like to shuffle players between groups but keep players in fixed roles,
For example, this will group players randomly each round:
class Subsession(BaseSubsession): def creating_session(self): self.group_randomly()
This will group players randomly each round, but keep
class Subsession(BaseSubsession): def creating_session(self): self.group_randomly(fixed_id_in_group=True)
For the following example, assume that
players_per_group = 3, and that there are 12 participants in the session:
class Subsession(BaseSubsession): def creating_session(self): print(self.get_group_matrix()) # outputs the following: # [[<Player 1>, <Player 2>, <Player 3>], # [<Player 4>, <Player 5>, <Player 6>], # [<Player 7>, <Player 8>, <Player 9>], # [<Player 10>, <Player 11>, <Player 12>]] self.group_randomly(fixed_id_in_group=True) print(self.get_group_matrix()) # outputs the following: # [[<Player 1>, <Player 8>, <Player 12>], # [<Player 10>, <Player 5>, <Player 3>], # [<Player 4>, <Player 2>, <Player 6>], # [<Player 7>, <Player 11>, <Player 9>]] self.group_randomly() print(self.get_group_matrix()) # outputs the following: # [[<Player 8>, <Player 10>, <Player 3>], # [<Player 4>, <Player 11>, <Player 2>], # [<Player 9>, <Player 1>, <Player 6>], # [<Player 12>, <Player 5>, <Player 7>]]
To copy the group structure from one round to another round,
The argument to this method is the round number
whose group structure should be copied.
In the below example, the groups are shuffled in round 1, and then subsequent rounds copy round 1’s grouping structure.
class Subsession(BaseSubsession): def creating_session(self): if self.round_number == 1: # <some shuffling code here> else: self.group_like_round(1)
Subsessions have a method called
return the structure of groups as a matrix, i.e. a list of lists,
with each sublist being the players in a group, ordered by
The following lines are equivalent.
matrix = self.get_group_matrix() # === is equivalent to === matrix = [group.get_players() for group in self.get_groups()]
set_group_matrix() lets you modify the group structure in any way you want.
First, get the list of players with
get_players(), or the pre-existing
group matrix with
Construct your matrix using Python list operations like
and list indexing and slicing (e.g.
Then pass this modified matrix to
class Subsession(BaseSubsession): def creating_session(self): matrix = s.get_group_matrix() for row in matrix: row.reverse() # now the 'matrix' variable looks like this, # but it hasn't been saved yet! # [[<Player 3>, <Player 2>, <Player 1>], # [<Player 6>, <Player 5>, <Player 4>], # [<Player 9>, <Player 8>, <Player 7>], # [<Player 12>, <Player 11>, <Player 10>]] # save it self.set_group_matrix(matrix)
You can also pass a matrix of integers.
It must contain all integers from 1 to the number of players
in the subsession. Each integer represents the player who has that
class Subsession(BaseSubsession): def creating_session(self): matrix = s.get_group_matrix() new_structure = [[1,3,5], [7,9,11], [2,4,6], [8,10,12]] self.set_group_matrix(new_structure) print(self.get_group_matrix()) # will output this: # [[<Player 1>, <Player 3>, <Player 5>], # [<Player 7>, <Player 9>, <Player 11>], # [<Player 2>, <Player 4>, <Player 6>], # [<Player 8>, <Player 10>, <Player 12>]]
You can even use
set_group_matrix to make groups of uneven sizes.
To check if your group shuffling worked correctly,
open your browser to the “Results” tab of your session,
and look at the
id_in_group columns in each round.
Shuffling during the session¶
creating_session is usually a good place to shuffle groups,
but remember that
creating_session is run when the session is created,
before players begin playing. So, if your shuffling logic needs to depend on
something that happens after the session starts, you should do the
shuffling in a wait page instead.
Let’s say you have defined a method on the
do_my_shuffle() that uses
You need to make a
and put the shuffling code in
class ShuffleWaitPage(WaitPage): wait_for_all_groups = True after_all_players_arrive = 'do_my_shuffle'
To apply the same grouping to multiple rounds without needing
wait_for_all_groups in each round, add this to the method where you shuffle the groups:
for subsession in self.in_rounds(2, Constants.num_rounds): subsession.group_like_round(1)
Example: configurable group size¶
Let’s say you want to be able to configure the number of players per group each time you create a session.
As described in Configure sessions, create a key in your session config
(you can call it
players_per_group), then use this code to chunk the players
into groups of that size:
class Subsession(BaseSubsession): def creating_session(self): group_matrix =  players = self.get_players() ppg = self.session.config['players_per_group'] for i in range(0, len(players), ppg): group_matrix.append(players[i:i+ppg]) self.set_group_matrix(group_matrix)