001    /*
002     * SimuCS - Simulator to use with Classifier Systems 
003     * MSc project - Oxford University 
004     * by Benoit Isaac - Summer 2005
005     */
006    
007    package simuLCS;
008    
009    /**
010     * A Classifier is a rule: if CONDITION then ACTION.
011     * @author Benoit
012     * 
013     */
014    public class Classifier {
015    
016            public static final int PART_CONDITION = 0;
017            public static final int PART_ACTION = 1;
018            protected String condition;
019            protected String action;
020            protected String name;
021    
022            public static final int COND_ALL = 0;
023            public static final int COND_MATCH = 1;
024            public static final int COND_EXACT = 2;
025            
026            public static final int ACT_ALL = 0;
027            public static final int ACT_EXACT = 2;
028    
029            public Classifier() {
030                    name = "";
031            }
032    
033            /**
034             * Creates a Classifier with the given condition and action.
035             * @param c
036             * @param a
037             */
038            public Classifier(String c, String a) {
039                    condition = c;
040                    action = a;
041                    name = "";
042            }
043    
044            public Classifier(String c, String a, String n) {
045                    this(c, a);
046                    setName(n);
047            }
048    
049            /**
050             * Create a unique instance of a classifier shared by several Agents
051             * so that the user has to modify only this classifier to affect the 
052             * behaviour of all the Agents
053             * @param c
054             * @param ag
055             * @return
056             */
057            public static int createSharedClassifier(Classifier c, Agent[] ag) {
058                    if (c != null) {
059                            for (int i = 0; i < ag.length; i++) {
060                                    if (ag[i].getBehaviour() != null) // agent using Classifiers
061                                            ag[i].getBehaviour().addClassifier(c);
062                            }
063                            return 0;
064                    } else {
065                            System.out.println("No classifier given.");
066                            return -1;
067                    }
068            }
069    
070            public static int removeSharedClassifier(Classifier c, Agent[] ag) {
071                    if (c != null) {
072                            for (int i = 0; i < ag.length; i++) {
073                                    if (ag[i].getBehaviour() != null) // agent using Classifiers
074                                            ag[i].getBehaviour().removeClassifier(c);
075                            }
076                            return 0;
077                    } else {
078                            System.out.println("No classifier given.");
079                            return -1;
080                    }
081            }
082    
083            /**
084             * Returns a Classifier object from a string "XXX->YYYY [cccc]"
085             * where X,Y = {0,1,#} 
086             * XXX is the condition part, YYYY is the action part
087             * cccc is the name to put between square brackets (optional)
088             * @param s the String describing the classifier
089             * @param t the Template which describes the number of bits for cond/action
090             * @return a Classifier if the String is correct, null otherwise
091             */
092            public static Classifier fromString(String s, Template t) {
093                    Classifier result;
094                    // first bits : the condition part (XXX)
095                    System.out.println("String:" + s + " | Template:" + t);
096                    String condFromString = s.substring(0, t.getNbBitsCondition());
097                    System.out.println("Condition:" + condFromString);
098                    condFromString = getBits(condFromString);
099                    if (condFromString == Config.PROBLEM) {
100                            return null;
101                    }
102                    // after the symbols "->", there is the Action part (YYYY)
103                    String actionFromString =
104                            s.substring(
105                                    t.getNbBitsCondition() + 2,
106                                    t.getNbBitsCondition() + 2 + t.getNbBitsAction());
107                    System.out.println("Action:" + condFromString);
108                    actionFromString = getBits(actionFromString);
109                    if (actionFromString == Config.PROBLEM) {
110                            return null;
111                    }
112                    // TODO get the name between [ and ]
113    
114                    return (new Classifier(condFromString, actionFromString));
115            }
116    
117            /**
118             * If a String contains only 0s and 1s, returns that string.
119             * Otherwise return a String indicating an Error 
120             * @param s
121             * @see Config#PROBLEM
122             * @return
123             */
124            public static String getBits(String s) {
125                    boolean isOK = true;
126                    String toCheck;
127                    for (int i = 0; i < s.length(); i++) {
128                            toCheck = s.substring(i, i + 1);
129                            //                      System.out.println("To Check:"+toCheck);
130                            if (!toCheck.equals("1")
131                                    && !toCheck.equals("0")
132                                    && !toCheck.equals(String.valueOf(ZCSConfig.dontCare))) {
133                                    isOK = false;
134                                    //                              System.out.println("Incorrect bit.");
135                            }
136                    }
137                    if (isOK) {
138                            return s;
139                    } else {
140                            return Config.PROBLEM;
141                    }
142            }
143    
144                    public String getAction() {
145                    return action;
146            }
147    
148            public String getBitsAction(int position, int length) {
149                    return action.substring(position, position + length);
150            }
151    
152                    public String getCondition() {
153                    return condition;
154            }
155    
156            public String getBitsCondition(int position, int length) {
157                    return condition.substring(position, position + length);
158            }
159    
160            /**
161             * Get the bits from position <code>position</code> to <code>position + length</code>
162             * for the either the Condition or the Action, depending on <code>whichpart</code>
163             * @param position
164             * @param length
165             * @param whichpart @see Classifier#PART_ACTION @see Classifier#PART_CONDITION
166             * @return
167             */
168            public String getBits(int position, int length, int whichpart) {
169                    switch (whichpart) {
170                            case PART_CONDITION : // for the condition part  (0)
171                                    return getBitsCondition(position, length);
172                            case PART_ACTION : // for the action part (1)
173                                    return getBitsAction(position, length);
174                            default : // do nothing
175                                    System.out.println(
176                                            whichpart + "->part unknown. Should be 0 or 1");
177                                    return "";
178                    }
179            }
180    
181                    public void setAction(String string) {
182                    action = string;
183            }
184    
185            public void setCondition(String string) {
186                    condition = string;
187            }
188    
189            public void setBitsAction(String s, int position) {
190                    //System.out.println("Action before : " + action);
191                    StringBuffer newCond = new StringBuffer("");
192                    // beginning of the action is the same
193                    newCond.append(action.substring(0, position));
194                    // changing the specified bit(s)
195                    newCond.append(s);
196                    // end of the action is the same, if there are still some bits
197                    if (action.length() != newCond.length()) {
198                            newCond.append(
199                                    action.substring(position + s.length(), action.length()));
200                    }
201                    action = newCond.toString();
202                    //System.out.println("Action after : " + action);
203            }
204    
205            public void setBitsCondition(String s, int position) {
206                    //System.out.println("Condition before : " + condition);
207                    StringBuffer newCond = new StringBuffer("");
208                    // beginning of the condition is the same
209                    newCond.append(condition.substring(0, position));
210                    // changing the specified bit(s)
211                    newCond.append(s);
212                    // end of the condition is the same, if there are still some bits
213                    if (condition.length() != newCond.length()) {
214                            newCond.append(
215                                    condition.substring(position + s.length(), condition.length()));
216                    }
217                    condition = newCond.toString();
218                    //System.out.println("Condition after : " + condition);
219            }
220    
221            public void setBits(String s, int position, int whichpart) {
222                    //              System.out.println("Set bits from "+position+" with["+s+"] in "+whichpart);
223                    switch (whichpart) {
224                            case PART_CONDITION : // for the condition part 
225                                    setBitsCondition(s, position);
226                                    break;
227                            case PART_ACTION : // for the action part
228                                    setBitsAction(s, position);
229                                    break;
230                            default : // do nothing
231                                    System.out.println("Part unknown. Should be 0 or 1");
232                    }
233            }
234    
235            /**
236             * Returns a string representing the classifier (ie.  "Condition->Action")
237             */
238            public String toString() {
239                    return (condition + "->" + action + " [" + name + "]");
240            }
241            
242            public String getName() {
243                    return name;
244            }
245    
246            public void setName(String string) {
247                    name = string;
248            }
249    
250            /**
251             * Returns true if the classifier matches in the current situation.
252             *
253             * @param state The current situation which is the description of an external 
254             * agent by a bit of strings.
255             */
256            public boolean match(String state) {
257                    if (condition.length() != state.length())
258                            return false;
259                    for (int i = 0; i < condition.length(); i++) {
260                            if (condition.charAt(i) != ZCSConfig.dontCare  // not a #, check value
261                                    && condition.charAt(i) != state.charAt(i))
262                                    return false;
263                    }
264                    return true;
265            }
266            
267            /**
268             * Returns true if the classifier satisfies the properties described by
269             * <code>CondMatch</code> and <code>ActMatch</code>
270             * @param c
271             * @param CondMatch
272             * @param ActMatch
273             * @return
274             */
275            
276            public boolean match(Classifier c, int CondMatch, int ActMatch)
277            {
278                    if(CondMatch == COND_MATCH && !this.match(c.getCondition()))
279                            return false;
280                    if(CondMatch == COND_EXACT && !this.getCondition().equals(c.getCondition()))
281                            return false;
282                    if(ActMatch == ACT_EXACT && !this.getAction().equals(c.getAction()))
283                            return false;
284    //              System.out.println("match : cond-"+CondMatch+" - act "+ActMatch);
285                    return true;
286            }
287            
288            /**
289             * Gives the "value" of this classifier to be plotted.
290             * Should be overriden by subclasses, depending on their implementation of the
291             * Classifiers (it could be strength, accuracy, fitness,...)
292             * @return A value of the Classifier
293             */
294            public double getValue()
295            {
296                    return 0.;
297            }
298    
299    }