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] → 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}