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