3 /************************************
4 * Automatic group generataion
5 ************************************/
7 // @@@ TO DO - Some of this code could be simplified a lot I realised
8 // after I wrote it and got it working!
11 * Seeds the random number generator used by groups_create_automatic_grouping.
12 * This must be called before using groups_create_automatic_grouping and should
13 * only be called once in each script even if you are calling
14 * groups_create_automatic_grouping more than once.
16 function groups_seed_random_number_generator() {
17 $seed = (double)microtime()*1234567 ;
23 * Distributes students into groups randomly and creates a grouping with those
26 * You need to call groups_seed_random_number_generator() at some point in your
27 * script before calling this function.
29 * Note that this function does not distribute teachers into groups - this still
30 * needs to be done manually.
32 * @param int $courseid The id of the course that the grouping should belong to
33 * @param int $nostudentspergroup The number of students to put in each group -
34 * this can be set to false if you prefer to specify the number of groups
36 * @param int $nogroups The number of groups - this can be set to false if you
37 * prefer to specify the number of student in each group. If both are specified
38 * then $nostudentspergroup takes precedence. If neither is
39 * specified then the function does nothing and returns false.
40 * @param boolean $distribevenly If $noofstudentspergroup is specified, then
41 * if this is set to true, any leftover students are distributed evenly among
42 * the groups, whereas if it is set to false then they are put in a separate
44 * @param object $groupsettings The default settings to give each group.
45 * This should contain prefix and defaultgroupdescription fields. The groups
46 * are named with the prefix followed by 1, 2, etc. and given the
47 * default group description set.
48 * @param int $groupid If this is not set to false, then only students in the
49 * specified group are distributed into groups, not all the students enrolled on
51 * @param boolean $alphabetical If this is set to true, then the students are
52 * not distributed randomly but in alphabetical order of last name.
53 * @return int The id of the grouping
55 function groups_create_automatic_grouping($courseid, $nostudentspergroup,
56 $nogroups, $distribevenly,
59 $alphabetical = false) {
61 if (!$nostudentspergroup and !$noteacherspergroup and !$nogroups) {
64 // Set $userids to the list of students that we want to put into groups
67 $users = get_course_students($courseid);
68 $userids = groups_users_to_userids($users);
70 $userids = groups_get_members($groupid);
73 // Distribute the users into sets according to the parameters specified
74 $userarrays = groups_distribute_in_random_sets($userids,
75 $nostudentspergroup, $nogroups, $distribevenly, !$alphabetical);
80 // Create the grouping that the groups we create will go into
81 $groupingid = groups_create_grouping($courseid, $groupingsettings);
83 // Get the prefix for the names of each group and default group
84 // description to give each group
85 if (!$groupingsettings->prefix
) {
86 $prefix = get_string('defaultgroupprefix', 'groups');
88 $prefix = $groupingsettings->prefix
;
91 if (!$groupingsettings->defaultgroupdescription
) {
92 $defaultgroupdescription = '';
94 $defaultgroupdescription = $groupingsettings->defaultgroupdescription
;
97 // Now create a group for each set of students, add the group to the
98 // grouping and then add the students
100 foreach ($userarrays as $userids) {
101 $groupsettings->name
= $prefix.' '.$i;
102 $groupsettings->description
= $defaultgroupdescription;
104 $groupid = groups_create_group($courseid, $groupsettings);
105 $groupadded = groups_add_group_to_grouping($groupid,
107 if (!$groupid or !$groupadded) {
111 foreach($userids as $userid) {
112 $usersadded = groups_add_member($groupid, $userid);
113 // If unsuccessful just carry on I guess
125 * Takes an array and a set size, puts the elements of the array into an array
126 * of arrays of size $setsize randomly.
127 * @param array $array The array to distribute into random sets
128 * @param int $setsize The size of each set - this can be set to false, if you
129 * would prefer to specify the number of sets.
130 * @param int $nosets The number of sets - this can be set to false if you would
131 * prefer to specify the setsize.
132 * If both $setsize and $nosets are set then $setsize takes precedence. If both
133 * are set to false then the function does nothing and returns false.
134 * @param $distribevenly boolean Determines how extra elements are distributed
135 * if $setsize doesn't divide exactly into the number of elements if $setsize is
136 * specified. If it is true then extra elements will be distributed evenly
137 * amongst the sets, whereas if it is set to false then the remaining elements
138 * will be put into a separate set.
139 * @param boolean $randomise If this is true then the elements of array will be
140 * put into the arrays in a random order, otherwise they will be put into the
141 * array in the same order as the original array.
142 * @return array The array of arrays of elements generated.
144 function groups_distribute_in_random_sets($array, $setsize, $nosets,
145 $distribevenly = true,
147 $noelements = count($array);
149 // Create a list of the numbers 1,..., $noelements, in either random order
150 // or in numerical order depending on whether $randomise has been set.
152 $orderarray = groups_random_list($noelements);
154 // Just create the array (1,2,3,....)
155 $orderarray = array();
156 for($i = 0; $i < $noelements; $i++
) {
157 array_push($orderarray, $i);
161 // Now use the ordering in $orderarray to generate the new arrays
162 $arrayofrandomsets = array(); //
164 for ($i = 0; $i < $noelements; $i++
) {
165 $arrayofrandomsets[$arrayno][$i] = $array[$orderarray[$i]];
166 if (groups_last_element_in_set($noelements, $setsize, $nosets,
168 and $i != $noelements - 1) {
170 $arrayofrandomsets[$arrayno] = array();
175 return $arrayofrandomsets;
179 * Returns an array of the numbers 0,..,$size - 1 in random order
180 * @param int $size the number of numbers to return in a random order
181 * @return array The array of numbers in a random order
183 function groups_random_list($size) {
184 $orderarray = array();
186 while($noelementsset != $size) {
187 $newelement = rand() %
$size;
188 // If the array doesn't already contain the element, add it.
189 if (array_search($newelement, $orderarray) === false) {
190 array_push($orderarray, $newelement);
199 * A helper function for groups_distribute_in_random_sets().
200 * When distributing elements into sets, determines if a given element is the
201 * last element in the set.
202 * @param int $totalnoelements The total number of elements being distributed.
203 * @param int $setsize See groups_distribute_in_random_sets()
204 * @param int $nosets See groups_distribute_in_random_sets()
205 * @param boolean $distribevenly See groups_distribute_in_random_sets()
206 * @param int $elementno The element number that we are considering i.e. if this
207 * is the 15th element then this would be 15.
208 * @return boolean True if the element under consideration would be the last
209 * element in the set, fals otherwise.
211 function groups_last_element_in_set($totalnoelements, $setsize, $nosets,
212 $distribevenly, $elementno) {
213 $lastelement = false;
214 $elementno = $elementno +
1; // Counting from zero is just too confusing!
216 // If $nosets has been specified, make sure $setsize is set to the right
217 // value, so that we can treat the two cases identically. Then work out how
218 // many extra elements will be left over.
220 $setsize = floor($totalnoelements / $nosets);
221 $noextra = $totalnoelements %
$nosets;
223 $noextra = $totalnoelements %
$setsize;
226 if (!$distribevenly) {
227 // If we're putting our extra elements in a set at the end, everything
229 if ($elementno %
$setsize == 0) {
233 // Work out the number of elements that will be in the bigger sets that
234 // have the leftover elements in
236 $noinbiggersets = $noextra * ($setsize +
1);
237 // Work out if this element is a last element in a set or not - we need
238 // to separate the case where the element is one of the ones that goes
239 // into the bigger sets at the beginning
240 // and the case where it's one of the elements in the normal sized sets.
241 if (($elementno <= $noinbiggersets and $elementno %
($setsize +
1) == 0)
242 or ($elementno > $noinbiggersets and
243 ($elementno - $noinbiggersets ) %
$setsize == 0) ) {