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 }