Download
%
% Social golfer in Minizinc.
% 
% Translated from OPL code from
%
% http://www.dis.uniroma1.it/~tmancini/index.php?currItem=research.publications.webappendices.csplib2x.problemDetails&problemid=010
%
% """
% Problem description
% In a golf club there are 32 social golfers who play once a week in 8 groups of 4. The problem amounts to find a schedule for as many as possible weeks, such that no two golfers play in the same group more than once.

% Here we consider the decisional version of the problem (wrt the number of weeks 'weeks'), where the number of players and the group size are given as input.
% 
% Problem input
% 
% * groups, the number of groups to be formed each week
% * groupSize, the size of each group
% * weeks, the number of weeks for which a scheduling is requested 
% 
% Search space
% The set of all possible group assignments to all players in each of the weeks weeks.
% 
% Constraints
%
% * C1: Each group has exactly groupSize players
% * C2: Each pair of players only meets at most once
% """
%
% Model created by Hakan Kjellerstrand, hakank@bonetmail.com
% See also my MiniZinc page: http://www.hakank.org/minizinc
%
% Licenced under CC-BY-4.0 : http://creativecommons.org/licenses/by/4.0/
%
int: weeks = 4;
int: groups = 3;
int: groupSize = 3;
int: golfers = groups * groupSize;

set of int: Golfer = 1..golfers;
set of int: Week = 1..weeks;
set of int: Group = 1..groups;

% Search space: The set of all possible group assignments to all 
% players in each of the weeks
array[Golfer, Week] of var Group: assign;

% solve satisfy;
% solve :: int_search([assign[i,j] | i in Golfer, j in Week ], "first_fail", "indomain", "complete") satisfy;
solve :: int_search([assign[i,j] | i in Golfer, j in Week ], 
        first_fail, indomain_min, complete) satisfy;

constraint
   % C1: Each group has exactly groupSize players
   forall (gr in Group, w in Week)( % c1
     sum (g in Golfer) (bool2int(assign[g,w] = gr)) = groupSize
   )
   /\
   % C2: Each pair of players only meets at most once
   forall (g1, g2 in Golfer, w1, w2 in Week  where g1 != g2 /\ w1 != w2) (
     (bool2int(assign[g1,w1] = assign[g2,w1]) + bool2int(assign[g1,w2] = assign[g2,w2])) <= 1
   )
  /\
  % SBSA: Symmetry-breaking by selective assignment
  % On the first week, the first groupSize golfers play in group 1, the 
  % second groupSize golfers play in group 2, etc. On the second week, 
  % golfer 1 plays in group 1, golfer 2 plays in group 2, etc.
  forall(g in Golfer) (
    assign[g,1]=((g-1) div groupSize) + 1 % 
  )
  /\
  forall(g in Golfer where g <= groupSize)(
    assign[g,2]=g
  )

;

output [
  if j = 1 then "\n" else " " endif ++
  show(assign[i,j])
  | i in Golfer, j in Week
] ++ ["\n"];