    001package org.cpsolver.coursett.constraint;
    002
    003import java.util.ArrayList;
    004import java.util.BitSet;
    005import java.util.Collection;
    006import java.util.Enumeration;
    007import java.util.HashSet;
    008import java.util.List;
    009import java.util.Set;
    010
    011import org.cpsolver.coursett.Constants;
    012import org.cpsolver.coursett.criteria.BrokenTimePatterns;
    013import org.cpsolver.coursett.criteria.UselessHalfHours;
    014import org.cpsolver.coursett.model.Lecture;
    015import org.cpsolver.coursett.model.Placement;
    016import org.cpsolver.coursett.model.RoomSharingModel;
    017import org.cpsolver.coursett.model.TimeLocation;
    018import org.cpsolver.coursett.model.TimetableModel;
    019import org.cpsolver.ifs.assignment.Assignment;
    020import org.cpsolver.ifs.assignment.context.AssignmentConstraintContext;
    021import org.cpsolver.ifs.assignment.context.ConstraintWithContext;
    022import org.cpsolver.ifs.model.Model;
    023import org.cpsolver.ifs.util.DataProperties;
    024
    025
    026/**
    027 * Room constraint. <br>
    028 * Classes with the same room can not overlap in time.
    029 *
    030 * @author  Tomáš Müller
    031 * @version CourseTT 1.3 (University Course Timetabling)<br>
    032 *          Copyright (C) 2006 - 2014 Tomáš Müller<br>
    033 *          <a href="mailto:muller@unitime.org">muller@unitime.org</a><br>
    034 *          <a href="http://muller.unitime.org">http://muller.unitime.org</a><br>
    035 * <br>
    036 *          This library is free software; you can redistribute it and/or modify
    037 *          it under the terms of the GNU Lesser General Public License as
    038 *          published by the Free Software Foundation; either version 3 of the
    039 *          License, or (at your option) any later version. <br>
    040 * <br>
    041 *          This library is distributed in the hope that it will be useful, but
    042 *          WITHOUT ANY WARRANTY; without even the implied warranty of
    043 *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    044 *          Lesser General Public License for more details. <br>
    045 * <br>
    046 *          You should have received a copy of the GNU Lesser General Public
    047 *          License along with this library; if not see
    048 *          <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.
    049 */
    050
    051public class RoomConstraint extends ConstraintWithContext<Lecture, Placement, RoomConstraint.RoomConstraintContext> {
    052    private Long iResourceId;
    053    private String iName;
    054    private Long iBuildingId;
    055    private int iCapacity = 0;
    056    private List<Placement>[] iAvailable = null;
    057    private boolean iConstraint = true;
    058
    059    private Double iPosX = null, iPosY = null;
    060    private boolean iIgnoreTooFar = false;
    061
    062    private RoomSharingModel iRoomSharingModel = null;
    063
    064    private Long iType = null;
    065    private int iDayOfWeekOffset = 0;
    066
    067    private RoomConstraint iParentRoom;
    068    private List<RoomConstraint> iPartitions;
    069
    070    /**
    071     * Constructor
    072     * @param id room unique id
    073     * @param name room name
    074     * @param buildingId building unique id
    075     * @param capacity room size
    076     * @param roomSharingModel room sharing model
    077     * @param x X-coordinate (latitude)
    078     * @param y Y-coordinate (longitude)
    079     * @param ignoreTooFar ignore distances if set to true
    080     * @param constraint hard constraint if true (classes cannot overlap in this room)
    081     */
    082    public RoomConstraint(Long id, String name, Long buildingId, int capacity, RoomSharingModel roomSharingModel,
    083            Double x, Double y, boolean ignoreTooFar, boolean constraint) {
    084        iResourceId = id;
    085        iName = name;
    086        iBuildingId = buildingId;
    087        iCapacity = capacity;
    088        iConstraint = constraint;
    089        iRoomSharingModel = roomSharingModel;
    090        iPosX = x;
    091        iPosY = y;
    092        iIgnoreTooFar = ignoreTooFar;
    093    }
    094
    095    @Override
    096    public void setModel(Model<Lecture, Placement> model) {
    097        super.setModel(model);
    098        if (model != null) {
    099            DataProperties config = ((TimetableModel)model).getProperties();
    100            iDayOfWeekOffset = config.getPropertyInt("DatePattern.DayOfWeekOffset", 0);
    101        }
    102    }
    103
    104    @SuppressWarnings("unchecked")
    105    public void setNotAvailable(Placement placement) {
    106        if (iAvailable == null) {
    107            iAvailable = new List[Constants.SLOTS_PER_DAY * Constants.NR_DAYS];
    108            for (int i = 0; i < iAvailable.length; i++)
    109                iAvailable[i] = null;
    110        }
    111        for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    112            int slot = e.nextElement();
    113            if (iAvailable[slot] == null)
    114                iAvailable[slot] = new ArrayList<Placement>(1);
    115            iAvailable[slot].add(placement);
    116        }
    117        for (Lecture lecture: variables())
    118            lecture.clearValueCache();
    119    }
    120
    121    public boolean isAvailable(int slot) {
    122        if (getConstraint() && iAvailable != null && iAvailable[slot] != null && !iAvailable[slot].isEmpty())
    123            return false;
    124        if (getSharingModel() != null && getSharingModel().isNotAvailable(slot))
    125            return false;
    126        return true;
    127    }
    128
    129    public boolean isAvailable(Lecture lecture, TimeLocation time, Long scheduler) {
    130        if (iAvailable != null && getConstraint()) {
    131            for (Enumeration<Integer> e = time.getSlots(); e.hasMoreElements();) {
    132                int slot = e.nextElement();
    133                if (iAvailable[slot] != null) {
    134                    for (Placement p : iAvailable[slot]) {
    135                        if (lecture.canShareRoom(p.variable()))
    136                            continue;
    137                        if (time.shareWeeks(p.getTimeLocation()))
    138                            return false;
    139                    }
    140                }
    141            }
    142        }
    143
    144        // room partition checking
    145        if (getParentRoom() != null && getParentRoom().getConstraint() && getParentRoom().iAvailable != null) { // check parent room's availability
    146            for (Enumeration<Integer> e = time.getSlots(); e.hasMoreElements();) {
    147                int slot = e.nextElement();
    148                if (getParentRoom().iAvailable[slot] != null) {
    149                    for (Placement p : getParentRoom().iAvailable[slot]) {
    150                        if (lecture.canShareRoom(p.variable()))
    151                            continue;
    152                        if (time.shareWeeks(p.getTimeLocation()))
    153                            return false;
    154                    }
    155                }
    156            }
    157        }
    158        if (getPartitions() != null) { // check partitions for availability
    159            for (RoomConstraint partition: getPartitions()) {
    160                if (partition.iAvailable != null && partition.getConstraint()) {
    161                    for (Enumeration<Integer> e = time.getSlots(); e.hasMoreElements();) {
    162                        int slot = e.nextElement();
    163                        if (partition.iAvailable[slot] != null) {
    164                            for (Placement p : partition.iAvailable[slot]) {
    165                                if (lecture.canShareRoom(p.variable()))
    166                                    continue;
    167                                if (time.shareWeeks(p.getTimeLocation()))
    168                                    return false;
    169                            }
    170                        }
    171                    }
    172                }
    173            }
    174        }
    175
    176        if (getSharingModel() != null && !getSharingModel().isAvailable(time, scheduler))
    177            return false;
    178        return true;
    179    }
    180
    181    public List<Placement>[] getAvailableArray() {
    182        return iAvailable;
    183    }
    184
    185    public RoomSharingModel getSharingModel() {
    186        return iRoomSharingModel;
    187    }
    188
    189    /**
    190     * Add partition of this room. This room is unavailable at a time when one of the partition
    191     * is not available and vice versa.
    192     * @param room room partition
    193     */
    194    public void addPartition(RoomConstraint room) {
    195        room.iParentRoom = this;
    196        if (iPartitions == null) iPartitions = new ArrayList<RoomConstraint>();
    197        iPartitions.add(room);
    198    }
    199
    200    /**
    201     * If this room is a partition of some other room, returns the parent room (which is partitioned).
    202     * @return parent room
    203     */
    204    public RoomConstraint getParentRoom() { return iParentRoom; }
    205
    206    /**
    207     * If this room is partitioned into multiple rooms, return room partitions
    208     * @return room partitions
    209     */
    210    public List<RoomConstraint> getPartitions() { return iPartitions; }
    211
    212    /** Room id
    213     * @return room unique id
    214     **/
    215    public Long getResourceId() {
    216        return iResourceId;
    217    }
    218
    219    /** Building id
    220     * @return building unique id
    221     **/
    222    public Long getBuildingId() {
    223        return iBuildingId;
    224    }
    225
    226    /** Room name */
    227    @Override
    228    public String getName() {
    229        return iName;
    230    }
    231
    232    public String getRoomName() {
    233        return iName;
    234    }
    235
    236    /** Capacity
    237     * @return room size
    238     **/
    239    public int getCapacity() {
    240        return iCapacity;
    241    }
    242
    243    @Override
    244    public void computeConflicts(Assignment<Lecture, Placement> assignment, Placement placement, Set<Placement> conflicts) {
    245        if (!getConstraint())
    246            return;
    247        if (!placement.hasRoomLocation(getResourceId()))
    248            return;
    249
    250        // room partition checking
    251        if (getParentRoom() != null && getParentRoom().getConstraint()) { // check parent room's availability
    252            Lecture lecture = placement.variable();
    253            Placement current = assignment.getValue(lecture);
    254            Set<Placement> shared = null;
    255            BitSet weekCode = placement.getTimeLocation().getWeekCode();
    256            RoomConstraintContext context = getParentRoom().getContext(assignment);
    257            for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    258                int slot = e.nextElement();
    259                for (Placement confPlacement : context.getPlacements(slot)) {
    260                    if (!confPlacement.getTimeLocation().shareWeeks(weekCode))
    261                        continue;
    262                    if (confPlacement.equals(current))
    263                        continue;
    264                    if (shared != null && shared.contains(confPlacement))
    265                        continue;
    266                    if (confPlacement.canShareRooms(placement) && checkRoomSize(placement, shared, confPlacement)) {
    267                        if (shared == null) shared = new HashSet<Placement>();
    268                        shared.add(confPlacement);
    269                        continue;
    270                    }
    271                    conflicts.add(confPlacement);
    272                }
    273            }
    274        }
    275        if (getPartitions() != null) { // check partitions for availability
    276            Lecture lecture = placement.variable();
    277            Placement current = assignment.getValue(lecture);
    278            Set<Placement> shared = null;
    279            BitSet weekCode = placement.getTimeLocation().getWeekCode();
    280            for (RoomConstraint partition: iPartitions) {
    281                if (!partition.getConstraint()) continue;
    282                RoomConstraintContext context = partition.getContext(assignment);
    283                for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    284                    int slot = e.nextElement();
    285                    for (Placement confPlacement : context.getPlacements(slot)) {
    286                        if (!confPlacement.getTimeLocation().shareWeeks(weekCode))
    287                            continue;
    288                        if (confPlacement.equals(current))
    289                            continue;
    290                        if (shared != null && shared.contains(confPlacement))
    291                            continue;
    292                        if (confPlacement.canShareRooms(placement) && checkRoomSize(placement, shared, confPlacement)) {
    293                            if (shared == null) shared = new HashSet<Placement>();
    294                            shared.add(confPlacement);
    295                            continue;
    296                        }
    297                        conflicts.add(confPlacement);
    298                    }
    299                }
    300            }
    301        }
    302
    303        Lecture lecture = placement.variable();
    304        Placement current = assignment.getValue(lecture);
    305        Set<Placement> shared = null;
    306        BitSet weekCode = placement.getTimeLocation().getWeekCode();
    307        RoomConstraintContext context = getContext(assignment);
    308
    309        for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    310            int slot = e.nextElement();
    311            for (Placement confPlacement : context.getPlacements(slot)) {
    312                if (!confPlacement.getTimeLocation().shareWeeks(weekCode))
    313                    continue;
    314                if (confPlacement.equals(current))
    315                    continue;
    316                if (shared != null && shared.contains(confPlacement))
    317                    continue;
    318                if (confPlacement.canShareRooms(placement) && checkRoomSize(placement, shared, confPlacement)) {
    319                    if (shared == null) shared = new HashSet<Placement>();
    320                    shared.add(confPlacement);
    321                    continue;
    322                }
    323                conflicts.add(confPlacement);
    324            }
    325        }
    326    }
    327
    328    public boolean checkRoomSize(Placement placement, Collection<Placement> other, Placement extra) {
    329        int day = -1;
    330        TimeLocation t1 = placement.getTimeLocation();
    331        while ((day = t1.getWeekCode().nextSetBit(1 + day)) >= 0) {
    332            int dow = (day + iDayOfWeekOffset) % 7;
    333            if ((t1.getDayCode() & Constants.DAY_CODES[dow]) == 0) continue;
    334            if (extra != null) {
    335                TimeLocation t2 = extra.getTimeLocation();
    336                if (!t2.hasDay(day) || (t2.getDayCode() & Constants.DAY_CODES[dow]) == 0) continue;
    337            }
    338            for (int i = 0; i < t1.getLength(); i++) {
    339                int slot = t1.getStartSlot() + i;
    340                int size = placement.variable().maxRoomUse();
    341                if (extra != null) {
    342                    TimeLocation t2 = extra.getTimeLocation();
    343                    if (t2.getStartSlot() <= slot && slot < t2.getStartSlot() + t2.getLength())
    344                        size += extra.variable().maxRoomUse();
    345                    else
    346                        continue;
    347                }
    348                if (other != null)
    349                    for (Placement p: other) {
    350                        TimeLocation t2 = p.getTimeLocation();
    351                        if (t2.hasDay(day) && (t2.getDayCode() & Constants.DAY_CODES[dow]) != 0 && t2.getStartSlot() <= slot && slot < t2.getStartSlot() + t2.getLength())
    352                            size += p.variable().maxRoomUse();
    353                    }
    354                if (size > getCapacity()) {
    355                    return false;
    356                }
    357            }
    358        }
    359        return true;
    360    }
    361
    362    public boolean checkRoomSize(Placement placement, Collection<Placement> other) {
    363        return checkRoomSize(placement, other, null);
    364    }
    365
    366    @Override
    367    public boolean inConflict(Assignment<Lecture, Placement> assignment, Placement placement) {
    368        if (!getConstraint())
    369            return false;
    370        if (!placement.hasRoomLocation(getResourceId()))
    371            return false;
    372
    373        // room partition checking
    374        if (getParentRoom() != null && getParentRoom().getConstraint()) { // check parent room's availability
    375            Lecture lecture = placement.variable();
    376            Placement current = assignment.getValue(lecture);
    377            Set<Placement> shared = null;
    378            BitSet weekCode = placement.getTimeLocation().getWeekCode();
    379            RoomConstraintContext context = getParentRoom().getContext(assignment);
    380            for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    381                int slot = e.nextElement();
    382                for (Placement confPlacement : context.getPlacements(slot)) {
    383                    if (!confPlacement.getTimeLocation().shareWeeks(weekCode))
    384                        continue;
    385                    if (confPlacement.equals(current))
    386                        continue;
    387                    if (shared != null && shared.contains(confPlacement))
    388                        continue;
    389                    if (confPlacement.canShareRooms(placement) && checkRoomSize(placement, shared, confPlacement)) {
    390                        if (shared == null) shared = new HashSet<Placement>();
    391                        shared.add(confPlacement);
    392                        continue;
    393                    }
    394                    return true;
    395                }
    396            }
    397        }
    398        if (getPartitions() != null) { // check partitions for availability
    399            Lecture lecture = placement.variable();
    400            Placement current = assignment.getValue(lecture);
    401            Set<Placement> shared = null;
    402            BitSet weekCode = placement.getTimeLocation().getWeekCode();
    403            for (RoomConstraint partition: iPartitions) {
    404                if (!partition.getConstraint()) continue;
    405                RoomConstraintContext context = partition.getContext(assignment);
    406                for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    407                    int slot = e.nextElement();
    408                    for (Placement confPlacement : context.getPlacements(slot)) {
    409                        if (!confPlacement.getTimeLocation().shareWeeks(weekCode))
    410                            continue;
    411                        if (confPlacement.equals(current))
    412                            continue;
    413                        if (shared != null && shared.contains(confPlacement))
    414                            continue;
    415                        if (confPlacement.canShareRooms(placement) && checkRoomSize(placement, shared, confPlacement)) {
    416                            if (shared == null) shared = new HashSet<Placement>();
    417                            shared.add(confPlacement);
    418                            continue;
    419                        }
    420                        return true;
    421                    }
    422                }
    423            }
    424        }
    425
    426        Lecture lecture = placement.variable();
    427        Placement current = assignment.getValue(lecture);
    428        Set<Placement> shared = null;
    429        BitSet weekCode = placement.getTimeLocation().getWeekCode();
    430        RoomConstraintContext context = getContext(assignment);
    431
    432        for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    433            int slot = e.nextElement();
    434            for (Placement confPlacement : context.getPlacements(slot)) {
    435                if (!confPlacement.getTimeLocation().shareWeeks(weekCode))
    436                    continue;
    437                if (confPlacement.equals(current))
    438                    continue;
    439                if (shared != null && shared.contains(confPlacement))
    440                    continue;
    441                if (confPlacement.canShareRooms(placement) && checkRoomSize(placement, shared, confPlacement)) {
    442                    if (shared == null) shared = new HashSet<Placement>();
    443                    shared.add(confPlacement);
    444                    continue;
    445                }
    446                return true;
    447            }
    448        }
    449        return false;
    450    }
    451
    452    @Override
    453    public boolean isConsistent(Placement p1, Placement p2) {
    454        if (!getConstraint())
    455            return true;
    456        if (getParentRoom() != null) { // partition checking -- one of the placement is with the parent room
    457            if ((p1.hasRoomLocation(getResourceId()) && p2.hasRoomLocation(getParentRoom().getResourceId())) ||
    458                (p2.hasRoomLocation(getResourceId()) && p1.hasRoomLocation(getParentRoom().getResourceId()))) {
    459                if (p1.getTimeLocation().hasIntersection(p2.getTimeLocation())) {
    460                    if (!p1.canShareRooms(p2) || (p1.variable()).maxRoomUse() + (p2.variable()).maxRoomUse() > getCapacity())
    461                        return true;
    462                }
    463            }
    464        }
    465        if (!p1.hasRoomLocation(getResourceId()))
    466            return false;
    467        if (!p2.hasRoomLocation(getResourceId()))
    468            return false;
    469        if (p1.getTimeLocation().hasIntersection(p2.getTimeLocation())) {
    470            if (!p1.canShareRooms(p2) || (p1.variable()).maxRoomUse() + (p2.variable()).maxRoomUse() > getCapacity())
    471                return true;
    472        }
    473        return false;
    474    }
    475
    476    @Override
    477    public void assigned(Assignment<Lecture, Placement> assignment, long iteration, Placement placement) {
    478        if (placement.hasRoomLocation(getResourceId()))
    479            super.assigned(assignment, iteration, placement);
    480    }
    481
    482    @Override
    483    public void unassigned(Assignment<Lecture, Placement> assignment, long iteration, Placement placement) {
    484        if (placement.hasRoomLocation(getResourceId()))
    485            super.unassigned(assignment, iteration, placement);
    486    }
    487
    488    /**
    489     * Lookup table getResource()[slot] &rarr; lecture using this room placed in the
    490     * given time slot (null if empty)
    491     * @param assignment current assignment
    492     * @param slot time slot
    493     * @return list of placements in the room in the given time
    494     */
    495    public List<Placement> getResource(Assignment<Lecture, Placement> assignment, int slot) {
    496        return getContext(assignment).getPlacements(slot);
    497    }
    498
    499    public Placement[] getResourceOfWeek(Assignment<Lecture, Placement> assignment, int startDay) {
    500        return getContext(assignment).getResourceOfWeek(startDay);
    501    }
    502
    503    @Override
    504    public String toString() {
    505        return "Room " + getName();
    506    }
    507
    508    /** Position of the building
    509     * @param x X-coordinate (latitude)
    510     * @param y Y-coordinate (longitude)
    511     **/
    512    public void setCoordinates(Double x, Double y) {
    513        iPosX = x;
    514        iPosY = y;
    515    }
    516
    517    /** X-position of the building
    518     * @return X-coordinate (latitude)
    519     **/
    520    public Double getPosX() {
    521        return iPosX;
    522    }
    523
    524    /** Y-position of the building
    525     * @return Y-coordinate (longitude)
    526     **/
    527    public Double getPosY() {
    528        return iPosY;
    529    }
    530
    531    public boolean getIgnoreTooFar() {
    532        return iIgnoreTooFar;
    533    }
    534
    535    public boolean getConstraint() {
    536        return iConstraint;
    537    }
    538
    539    public Long getType() {
    540        return iType;
    541    }
    542
    543    public void setType(Long type) {
    544        iType = type;
    545    }
    546
    547    @Override
    548    public RoomConstraintContext createAssignmentContext(Assignment<Lecture, Placement> assignment) {
    549        return new RoomConstraintContext(assignment);
    550    }
    551
    552    public class RoomConstraintContext implements AssignmentConstraintContext<Lecture, Placement> {
    553        private List<Placement>[] iResource;
    554        private int iLastUselessHalfHours = 0;
    555        private double iLastBrokenTimePatterns = 0;
    556
    557        @SuppressWarnings("unchecked")
    558        public RoomConstraintContext(Assignment<Lecture, Placement> assignment) {
    559            iResource = new List[Constants.SLOTS_PER_DAY * Constants.NR_DAYS];
    560            for (int i = 0; i < iResource.length; i++)
    561                iResource[i] = new ArrayList<Placement>(3);
    562            for (Lecture lecture: variables()) {
    563                Placement placement = assignment.getValue(lecture);
    564                if (placement != null && placement.hasRoomLocation(getResourceId())) {
    565                    for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    566                        int slot = e.nextElement();
    567                        iResource[slot].add(placement);
    568                    }
    569                }
    570            }
    571            iLastUselessHalfHours = UselessHalfHours.countUselessSlotsHalfHours(this);
    572            getModel().getCriterion(UselessHalfHours.class).inc(assignment, iLastUselessHalfHours);
    573            iLastBrokenTimePatterns = BrokenTimePatterns.countUselessSlotsBrokenTimePatterns(this) / 6.0;
    574            getModel().getCriterion(BrokenTimePatterns.class).inc(assignment, iLastBrokenTimePatterns);
    575        }
    576
    577        @Override
    578        public void assigned(Assignment<Lecture, Placement> assignment, Placement placement) {
    579            if (!placement.hasRoomLocation(getResourceId()))
    580                return;
    581            for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    582                int slot = e.nextElement();
    583                iResource[slot].add(placement);
    584            }
    585            getModel().getCriterion(UselessHalfHours.class).inc(assignment, -iLastUselessHalfHours);
    586            iLastUselessHalfHours = UselessHalfHours.countUselessSlotsHalfHours(this);
    587            getModel().getCriterion(UselessHalfHours.class).inc(assignment, iLastUselessHalfHours);
    588            getModel().getCriterion(BrokenTimePatterns.class).inc(assignment, -iLastBrokenTimePatterns);
    589            iLastBrokenTimePatterns = BrokenTimePatterns.countUselessSlotsBrokenTimePatterns(this) / 6.0;
    590            getModel().getCriterion(BrokenTimePatterns.class).inc(assignment, iLastBrokenTimePatterns);
    591        }
    592
    593        @Override
    594        public void unassigned(Assignment<Lecture, Placement> assignment, Placement placement) {
    595            if (!placement.hasRoomLocation(getResourceId()))
    596                return;
    597            for (Enumeration<Integer> e = placement.getTimeLocation().getSlots(); e.hasMoreElements();) {
    598                int slot = e.nextElement();
    599                iResource[slot].remove(placement);
    600            }
    601            getModel().getCriterion(UselessHalfHours.class).inc(assignment, -iLastUselessHalfHours);
    602            iLastUselessHalfHours = UselessHalfHours.countUselessSlotsHalfHours(this);
    603            getModel().getCriterion(UselessHalfHours.class).inc(assignment, iLastUselessHalfHours);
    604            getModel().getCriterion(BrokenTimePatterns.class).inc(assignment, -iLastBrokenTimePatterns);
    605            iLastBrokenTimePatterns = BrokenTimePatterns.countUselessSlotsBrokenTimePatterns(this) / 6.0;
    606            getModel().getCriterion(BrokenTimePatterns.class).inc(assignment, iLastBrokenTimePatterns);
    607        }
    608
    609        public List<Placement> getPlacements(int slot) { return iResource[slot]; }
    610
    611        public Placement getPlacement(int slot, int day) {
    612            for (Placement p : iResource[slot]) {
    613                if (p.getTimeLocation().hasDay(day))
    614                    return p;
    615            }
    616            return null;
    617        }
    618
    619        public Placement[] getResourceOfWeek(int startDay) {
    620            Placement[] ret = new Placement[iResource.length];
    621            for (int i = 0; i < iResource.length; i++) {
    622                ret[i] = getPlacement(i, startDay + (i / Constants.SLOTS_PER_DAY));
    623            }
    624            return ret;
    625        }
    626
    627        public boolean inConflict(Lecture lecture, TimeLocation time) {
    628            for (Enumeration<Integer> e = time.getSlots(); e.hasMoreElements();) {
    629                int slot = e.nextElement();
    630                for (Placement confPlacement : getPlacements(slot)) {
    631                    if (!confPlacement.getTimeLocation().shareWeeks(time.getWeekCode())) continue;
    632                    if (confPlacement.variable().equals(lecture)) continue;
    633                    if (!confPlacement.variable().canShareRoom(lecture)) return true;
    634                }
    635            }
    636            return false;
    637        }
    638
    639    }
    640}