001 package net.sf.cpsolver.exam.model; 002 003 import java.util.Enumeration; 004 import java.util.HashSet; 005 import java.util.Set; 006 007 import net.sf.cpsolver.ifs.model.Constraint; 008 import net.sf.cpsolver.ifs.model.ConstraintListener; 009 import net.sf.cpsolver.ifs.model.Value; 010 011 /** 012 * A room. Only one exam can use a room at a time (period). 013 * <br><br> 014 * 015 * @version 016 * ExamTT 1.1 (Examination Timetabling)<br> 017 * Copyright (C) 2008 Tomáš Müller<br> 018 * <a href="mailto:muller@unitime.org">muller@unitime.org</a><br> 019 * Lazenska 391, 76314 Zlin, Czech Republic<br> 020 * <br> 021 * This library is free software; you can redistribute it and/or 022 * modify it under the terms of the GNU Lesser General Public 023 * License as published by the Free Software Foundation; either 024 * version 2.1 of the License, or (at your option) any later version. 025 * <br><br> 026 * This library is distributed in the hope that it will be useful, 027 * but WITHOUT ANY WARRANTY; without even the implied warranty of 028 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 029 * Lesser General Public License for more details. 030 * <br><br> 031 * You should have received a copy of the GNU Lesser General Public 032 * License along with this library; if not, write to the Free Software 033 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 034 */ 035 public class ExamRoom extends Constraint implements Comparable { 036 private ExamPlacement[] iTable; 037 private boolean[] iAvailable; 038 private int[] iPenalty; 039 private String iName; 040 private int iSize, iAltSize; 041 private int iCoordX, iCoordY; 042 043 /** 044 * Constructor 045 * @param model examination timetabling model 046 * @param id unique id 047 * @param size room (normal) seating capacity 048 * @param altSize room alternating seating capacity (to be used when {@link Exam#hasAltSeating()} is true) 049 * @param coordX x coordinate 050 * @param coordY y coordinate 051 */ 052 public ExamRoom(ExamModel model, long id, String name, int size, int altSize, int coordX, int coordY) { 053 super(); 054 iAssignedVariables = null; 055 iId = id; 056 iName = name; 057 iCoordX = coordX; iCoordY = coordY; 058 iSize = size; iAltSize = altSize; 059 iTable = new ExamPlacement[model.getNrPeriods()]; 060 iAvailable = new boolean[model.getNrPeriods()]; 061 iPenalty = new int[model.getNrPeriods()]; 062 for (int i=0;i<iTable.length;i++) { 063 iTable[i]=null; 064 iAvailable[i]=true; 065 iPenalty[i]=0; 066 } 067 } 068 069 /** 070 * Distance between two rooms. It is computed as Euclidean distance using the room coordinates, 071 * 1 unit equals to 10 meters. 072 * @param other another room 073 * @return distance between this and the given room 074 */ 075 public int getDistance(ExamRoom other) { 076 if (getCoordX()<0 || getCoordY()<0 || other.getCoordX()<0 || other.getCoordY()<0) return 10000; 077 int dx = getCoordX()-other.getCoordX(); 078 int dy = getCoordY()-other.getCoordY(); 079 return (int)Math.sqrt(dx*dx+dy*dy); 080 } 081 082 /** 083 * Normal seating capacity (to be used when {@link Exam#hasAltSeating()} is false) 084 */ 085 public int getSize() { return iSize; } 086 /** 087 * Alternating seating capacity (to be used when {@link Exam#hasAltSeating()} is true) 088 */ 089 public int getAltSize() { return iAltSize; } 090 /** 091 * X coordinate 092 */ 093 public int getCoordX() { return iCoordX; } 094 /** 095 * Y coordinate 096 */ 097 public int getCoordY() { return iCoordY; } 098 /** 099 * An exam placed at the given period 100 * @param period a period 101 * @return a placement of an exam in this room at the given period, null if unused 102 */ 103 public ExamPlacement getPlacement(ExamPeriod period) { return iTable[period.getIndex()]; } 104 /** 105 * True if the room is available (for examination timetabling) during the given period 106 * @param period a period 107 * @return true if an exam can be scheduled into this room at the given period, false if otherwise 108 */ 109 public boolean isAvailable(ExamPeriod period) { return iAvailable[period.getIndex()]; } 110 public boolean isAvailable(int period) { return iAvailable[period]; } 111 /** 112 * Set whether the room is available (for examination timetabling) during the given period 113 * @param period a period 114 * @param available true if an exam can be scheduled into this room at the given period, false if otherwise 115 */ 116 public void setAvailable(ExamPeriod period, boolean available) { iAvailable[period.getIndex()]=available; } 117 public void setAvailable(int period, boolean available) { iAvailable[period]=available; } 118 119 /** Return room penalty for given period */ 120 public int getPenalty(ExamPeriod period) { return iPenalty[period.getIndex()]; } 121 public int getPenalty(int period) { return iPenalty[period]; } 122 /** Set room penalty for given period */ 123 public void setPenalty(ExamPeriod period, int penalty) { iPenalty[period.getIndex()]=penalty; } 124 public void setPenalty(int period, int penalty) { iPenalty[period]=penalty; } 125 126 /** 127 * Compute conflicts between the given assignment of an exam and all the current assignments (of this room) 128 */ 129 public void computeConflicts(Value value, Set conflicts) { 130 ExamPlacement p = (ExamPlacement)value; 131 if (!p.contains(this)) return; 132 if (iTable[p.getPeriod().getIndex()]!=null && !iTable[p.getPeriod().getIndex()].variable().equals(value.variable())) 133 conflicts.add(iTable[p.getPeriod().getIndex()]); 134 } 135 136 /** 137 * Checks whether there is a conflict between the given assignment of an exam and all the current assignments (of this room) 138 */ 139 public boolean inConflict(Value value) { 140 ExamPlacement p = (ExamPlacement)value; 141 if (!p.contains(this)) return false; 142 return iTable[p.getPeriod().getIndex()]!=null && !iTable[p.getPeriod().getIndex()].variable().equals(value.variable()); 143 } 144 145 /** 146 * False if the given two assignments are using this room at the same period 147 */ 148 public boolean isConsistent(Value value1, Value value2) { 149 ExamPlacement p1 = (ExamPlacement)value1; 150 ExamPlacement p2 = (ExamPlacement)value2; 151 return (p1.getPeriod()!=p2.getPeriod() || !p1.contains(this) || !p2.contains(this)); 152 } 153 154 /** 155 * An exam was assigned, update room assignment table 156 */ 157 public void assigned(long iteration, Value value) { 158 ExamPlacement p = (ExamPlacement)value; 159 if (p.contains(this) && iTable[p.getPeriod().getIndex()]!=null) { 160 if (iConstraintListeners!=null) { 161 HashSet confs = new HashSet(); 162 confs.add(iTable[p.getPeriod().getIndex()]); 163 for (Enumeration e=iConstraintListeners.elements();e.hasMoreElements();) 164 ((ConstraintListener)e.nextElement()).constraintAfterAssigned(iteration, this, value, confs); 165 } 166 iTable[p.getPeriod().getIndex()].variable().unassign(iteration); 167 } 168 } 169 170 /** 171 * An exam was assigned, update room assignment table 172 */ 173 public void afterAssigned(long iteration, Value value) { 174 ExamPlacement p = (ExamPlacement)value; 175 if (p.contains(this)) 176 iTable[p.getPeriod().getIndex()] = p; 177 } 178 179 /** 180 * An exam was unassigned, update room assignment table 181 */ 182 public void unassigned(long iteration, Value value) { 183 //super.unassigned(iteration, value); 184 } 185 186 /** 187 * An exam was unassigned, update room assignment table 188 */ 189 public void afterUnassigned(long iteration, Value value) { 190 //super.unassigned(iteration, value); 191 ExamPlacement p = (ExamPlacement)value; 192 if (p.contains(this)) { 193 iTable[p.getPeriod().getIndex()] = null; 194 } 195 } 196 197 /** 198 * Checks two rooms for equality 199 */ 200 public boolean equals(Object o) { 201 if (o==null || !(o instanceof ExamRoom)) return false; 202 ExamRoom r = (ExamRoom)o; 203 return getId()==r.getId(); 204 } 205 206 /** 207 * Hash code 208 */ 209 public int hashCode() { 210 return (int)(getId() ^ (getId() >>> 32)); 211 } 212 213 /** 214 * Room name 215 */ 216 public String getName() { 217 return (hasName()?iName:String.valueOf(getId())); 218 } 219 220 /** 221 * Room name 222 */ 223 public boolean hasName() { 224 return (iName!=null && iName.length()>0); 225 } 226 227 /** 228 * Room unique id 229 */ 230 public String toString() { 231 return getName(); 232 } 233 234 /** 235 * Compare two rooms (by unique id) 236 */ 237 public int compareTo(Object o) { 238 return toString().compareTo(o.toString()); 239 } 240 }