private static int score(Station S, Group G, int Day, int Slot)
        {
            int ret = 0;

            int i, j;

            int groupIndex = getGroupIndex(G);

            // check if other constraints will be violated if this assignment happens.
            // station cap - 1 for the current assigmment
            int stationIndex = getStationIndex(S);
            int stationTotalAvailableSlotsLeft = stationTotalAvailabilityCounts[stationIndex, Day, Slot] - 1;

            int otherGroupsNeedThisStation = 0;

            if (stationTotalAvailableSlotsLeft < 0)
            {
                return -1000000;
            }

            // look for anyone else who wants this station.
            for (i = 0; i < AllConstraints.Count; i++)
            {
                if (ConstraintMet[i] || AllConstraints[i].S != S || AllConstraints[i].G == G)
                    continue;

                otherGroupsNeedThisStation++;
            }

            if (otherGroupsNeedThisStation > stationTotalAvailableSlotsLeft)
            {
                ret += CONSTRAINT_PENALTY * (otherGroupsNeedThisStation - stationTotalAvailableSlotsLeft);
            }

            // nNotGettingPicks[0] is the count of groups that aren't getting their first picks because of this group
            int[] nNotGettingPicks = new int[5] { 0, 0, 0, 0, 0 };

            // Check how many groups get their second pick instead of first, and how many groups aren't getting any picks

            // Copy the total assignment count for station, starting at this timeslot.
            int[] StationAssignmentsCountsTemp = new int[MAXN];
            StationAssignmentsCountsTemp[stationIndex]++;

            int stationPickAvailableSlots;
            int nPossible;

            for (i = 0; i < AllGroups.Count; i++)
            {
                if(AllGroups[i].nStationsPicked >= 3 )
                    continue;

                nPossible = 0;

                for (j = 0; j < 5; j++)
                {
                    if (AllGroups[i].StationPicks[j] == -1 || AllGroups[i].StationPicked[j] || AllStations[AllGroups[i].StationPicks[j]] != S)
                        continue;

                    int prefStationIndex = AllGroups[i].StationPicks[j];
                    nPossible++;
                    stationPickAvailableSlots = stationTotalAvailabilityCounts[prefStationIndex, Day, Slot] -
                                                StationSlotAssignmentsCounts[prefStationIndex, Day, Slot] - StationAssignmentsCountsTemp[prefStationIndex];

                    if (stationPickAvailableSlots <= 0)
                        nNotGettingPicks[j]++;
                    else
                        StationAssignmentsCountsTemp[AllGroups[i].StationPicks[j]]++;

                    break;
                }
            }

            for (i = 0; i < 5; i++)
                ret += PREF_PENALTIES[i] * nNotGettingPicks[i];

            // check if the same group was assigned to another station with the same category
            int nSameCat = 0;
            int nSameStation = 0;
            int nPins = 0;

            for (i = 1; i <= Slot; i++)
            {
                foreach (KeyValuePair<int, int> P in masterSchedule[Day, i])
                {
                    if( groupIndex == P.Key )
                    {
                        if (P.Value != stationIndex && S.Category != "" && AllStations[P.Value].Category == S.Category)
                            nSameCat++;
                        else if (P.Value == stationIndex)
                            nSameStation++;
                        else if (AllStations[P.Value].isActivityPin && S.isActivityPin)
                            nPins++;
                    }
                }
            }

            ret += SAME_CATEGORY_PENALTY * nSameCat;
            ret += SAME_STATION_PENALTY * nSameStation;
            ret += SAME_STATION_PENALTY * ( nPins / 2);
            // if there is any entries in the old schedule, try to minimize them.
            bool isSameSched = false;

            foreach(KeyValuePair<int,int> P in oldMasterSchedule[Day,Slot])
            {
                if (P.Key == groupIndex && P.Value == stationIndex)
                {
                    isSameSched = true;
                    break;
                }
            }

            if ( !generateNewScheduleFromScracth &&!isSameSched)
                ret += ASSIGNMENT_CHANGE_PENALTY;

            // space the station out, if it is a pin, space it out from another pin too

            int slotDifference = totalTimeSlots;
            KeyValuePair<int, int> Q;

            if( S.isActivityPin )
                Q = lastDaySlotAssignedToPin[groupIndex];
            else
                Q = lastDaySlotAssignedToStation[groupIndex, stationIndex];

            if( Q.Key != -1 )
                slotDifference = getNumberOfSlotDifference(Q.Key, Q.Value, Day, Slot);

            ret += (int)(1.0 * (totalTimeSlots - slotDifference) * NOT_SPACED_OUT_PENALTY);

            // if this station is a pin, and the group already got their preferences, don't schedule it

            if (S.isActivityPin && G.nStationsPicked == 3)
                ret += -1000;

            return ret;
        }
        private static int getGroupIndex(Group g)
        {
            int i;

            for (i = 0; i < AllGroups.Count; i++)
            {
                if (AllGroups[i].ID == g.ID)
                    return i;
            }

            return -1;
        }
 public Constraint(Group g, Station s, int nV)
 {
     G = g;
     S = s;
     nVisits = nV;
 }
 public Assignment(Group g, Station s)
 {
     G = g;
     S = s;
 }