Index: modules/sametime.c
===================================================================
RCS file: /home/avian/repository/tablix/modules/sametime.c,v
retrieving revision 1.5
retrieving revision 1.7
diff -u -3 -u -r1.5 -r1.7
--- modules/sametime.c	17 Oct 2004 09:37:05 -0000	1.5
+++ modules/sametime.c	30 Oct 2004 17:13:26 -0000	1.7
@@ -1,5 +1,5 @@
 /* TABLIX, PGA highschool timetable generator                              */
-/* Copyright (C) 2002 Tomaz Solc                                           */
+/* Copyright (C) 2002-2004 Tomaz Solc                                      */
 
 /* This program is free software; you can redistribute it and/or modify    */
 /* it under the terms of the GNU General Public License as published by    */
@@ -15,7 +15,7 @@
 /* along with this program; if not, write to the Free Software             */
 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
 
-/* $Id: sametime.c,v 1.5 2004/10/17 09:37:05 avian Exp $ */
+/* $Id: sametime.c,v 1.7 2004/10/30 17:13:26 avian Exp $ */
 
 /* 
  * AUTHOR:
@@ -34,6 +34,15 @@
  *  This restriction specifies that current class should never have lessons
  *  at the same time as the class specified in the restriction.
  *
+ *  <restriction type="group">group</restriction>
+ *
+ *  This restriction specifies that the current class is a part (a "column" as
+ *  it is sometimes called) of a group of classes. Students can choose freely
+ *  to take one subject from each column in a group. This means that tuples
+ *  with different subjects defined in such a class can be scheduled at the
+ *  same time, while two tuples from different columns in a group can never
+ *  be scheduled at the same time.
+ *
  */
 
 #ifdef HAVE_CONFIG_H
@@ -48,8 +57,55 @@
 #include "data.h"
 #include "gettext.h"
 
+struct cgroup {
+	char *name;
+	int *members;
+	int memnum;
+};
+
 int **conflicts;
 
+static struct cgroup *groups;
+
+static int find_group(char *name)
+{
+	int c;
+
+	c=0;
+	while(groups[c].name!=NULL&&c<cmapnum) {
+		if(!strcmp(name, groups[c].name)) {
+			return c;
+		}
+		c++;
+	}
+	if(c>=cmapnum) {
+		return(-1);
+	} else {
+		return c;
+	}
+}
+
+int getgroup(char *type, char *cont, int cid)
+{
+	int gid;
+
+	gid=find_group(cont);
+
+	if(gid<0) {
+		strcpy(moderror, _("too many group restrictions"));
+		return(1);
+	}
+
+	if(groups[gid].name==NULL) {
+		groups[gid].name=strdup(cont);
+	}
+
+	groups[gid].members[groups[gid].memnum]=cid;
+	groups[gid].memnum++;
+
+	return 0;
+}
+
 int getconflict(char *type, char *cont, int cid)
 {
 	char name[256];
@@ -78,6 +134,7 @@
 
 parop class_restrictions[] = { 
 	{ type : "conflicts-with", parfunc: getconflict },
+	{ type : "group", parfunc: getgroup },
 	{ type : 0, parfunc: 0 }
 };
 
@@ -86,18 +143,54 @@
 	int c,b;
 
 	conflicts=malloc(sizeof(*conflicts)*cmapnum);
-
 	for(c=0;c<cmapnum;c++) {
 		conflicts[c]=malloc(sizeof(*conflicts[c])*cmapnum);
 		for(b=0;b<cmapnum;b++) {
 			conflicts[c][b]=0;
 		}
-		conflicts[c][c]=1;	/* Class always conflicts with itself */
+		/* Class always conflicts with itself */
+		/* except when it is a part of a group */
+		/* in that case, this flag is cleared in precalc_mod() */
+		conflicts[c][c]=1;
+	}
+
+	groups=malloc(sizeof(*groups)*cmapnum);
+	for(c=0;c<cmapnum;c++) {
+		groups[c].name=NULL;
+		groups[c].members=malloc(sizeof(*groups[c].members)*cmapnum);
+		groups[c].memnum=0;
 	}
 	
 	return 0;
 }
 
+int precalc_mod()
+{
+	int c,n,m;
+	int cid1, cid2;
+
+	c=0;
+	while(groups[c].name!=NULL&&c<cmapnum) {
+		for(n=0;n<groups[c].memnum;n++) {
+			cid1=groups[c].members[n];
+
+			conflicts[cid1][cid1]=0;
+			for(m=0;m<groups[c].memnum;m++) {
+				if(n!=m) {
+					cid2=groups[c].members[m];
+
+					conflicts[cid1][cid2]=1;
+					conflicts[cid2][cid1]=1;
+				}
+			}
+
+		}
+		c++;
+	}
+
+	return 0;
+}
+
 int grade_function(chromo *t, int *cpnt, int *tpnt, int **start, int **lead)
 {
 	int a,b,c;
