package org.geogebra.common.util;
import java.util.HashMap;
import org.geogebra.common.kernel.Kernel;
/**
* @author Christoph
*
*/
/**
* @author Christoph
*
*/
public abstract class Assignment {
/**
* The Result of the Assignment
*/
public static enum Result {
/**
* The assignment is CORRECT
*/
CORRECT,
/**
* The assignment is WRONG and we can't tell why
*/
WRONG,
/**
* There are not enough input geos, so we cannot check
*/
NOT_ENOUGH_INPUTS,
/**
* We have enough input geos, but one or more are of the wrong type
*/
WRONG_INPUT_TYPES,
/**
* There is no output geo matching our macro
*/
WRONG_OUTPUT_TYPE,
/**
* The assignment was correct in the first place but wrong after
* randomization
*/
WRONG_AFTER_RANDOMIZE,
/**
* The assignment could not be checked
*/
UNKNOWN,
}
/**
* Possible values for fractions (sorted ascending!)
*/
public final static float[] FRACTIONS = { -1f, -0.9f, -0.875f, -(5f / 6),
-0.8f, -0.75f, -0.7f, -(2f / 3), -0.625f, -0.6f, -0.5f, -0.4f,
-0.375f, -(1f / 3), -0.3f, -0.25f, -0.2f, -(1f / 6), -0.125f, -0.1f,
0f, 0.1f, 0.125f, (1f / 6), 0.2f, 0.25f, 0.3f, (1f / 3), 0.375f,
0.4f, 0.5f, 0.6f, 0.625f, (2f / 3), 0.7f, 0.75f, 0.8f, (5f / 6),
0.875f, 0.9f, 1f };
/**
* The fractions for the Results. Each Result may have any fraction between
* -100 and 100 (i.e. -1 and 1)
*/
protected HashMap<Result, Double> fractionForResult;
/**
* The hints for the Results. There may or may not be a hint set for a
* particular result.
*/
protected HashMap<Result, String> hintForResult;
/**
* The current state of the Assignment (should only get updated when
* checkAssignment is called)
*/
protected Result res;
/**
* Kernel
*/
protected Kernel kernel;
/**
*
*
* @param kernel
* Kernel
*/
public Assignment(Kernel kernel) {
fractionForResult = new HashMap<Result, Double>();
hintForResult = new HashMap<Result, String>();
res = Result.UNKNOWN;
this.kernel = kernel;
}
/**
* Exhaustive Testing of the Assignment
*
* @return {@link Result} of the check
*/
public abstract Result checkAssignment();
/**
* Get the fraction for the current state of the assignment. Don't forget to
* call checkAssignment() or checkExercise() prior to getFraction() if you
* want to update the Result.
*
* @return the fraction for the current state of the assignment <br />
* if the user specified a fraction it will be returned otherwise 1
* for Result.CORRECT 0 else
*/
public double getFraction() {
double fraction = 0;
if (fractionForResult.containsKey(res)) {
fraction = fractionForResult.get(res);
} else if (res == Result.CORRECT) {
fraction = 1.0f;
}
return fraction;
}
/**
* Gives the hint for the actual state for this {@link GeoAssignment}
*
* @return the hint for current {@link Result}
*/
public String getHint() {
return hintForResult.get(res);
}
/**
* @return the actual state for this {@link GeoAssignment} as {@link Result}
*/
public Result getResult() {
return res;
}
/**
* @return true if user specified hints for any result in the assignment
*/
public boolean hasHint() {
return !hintForResult.isEmpty();
}
/**
* @return true if user specified fractions for any result result in the
* assignment
*/
public boolean hasFraction() {
return !fractionForResult.isEmpty();
}
/**
* @param result
* the result for which the fraction should be set
* @param f
* the fraction in the interval [-1,1] which should be used for
* the result (will do nothing if fraction is not in [-1,1])
*/
public void setFractionForResult(Result result, double f) {
if (-1 <= f && f <= 1) {
fractionForResult.put(result, f);
}
}
/**
* @param result
* the result for which the fraction should be returned
* @return the fraction corresponding to the result<br />
* if the user specified a fraction it will be returned otherwise 1
* for Result.CORRECT 0 else
*/
public double getFractionForResult(Result result) {
double frac = 0;
if (fractionForResult.containsKey(result)) {
frac = fractionForResult.get(result);
} else if (result == Result.CORRECT) {
frac = 1.0f;
}
return frac;
}
/**
* Sets the Hint for a particular Result.
*
* @param res
* the {@link Result}
* @param hint
* the hint which should be shown to the student in case of the
* {@link Result} res
*/
public void setHintForResult(Result res, String hint) {
this.hintForResult.put(res, hint);
}
/**
* @param result
* the Result for which the hint should be returned
* @return hint corresponding to result
*/
public String getHintForResult(Result result) {
String hint = "";
if (hintForResult.containsKey(result)) {
hint = hintForResult.get(result);
}
return hint;
}
/**
* Not all {@link Result}s might be suitable for a specific type of
* Assignment
*
* @return the the Results which are meaningful for the type of Assignment
*/
public abstract Result[] possibleResults();
/**
* @return XML describing the Exercise. Will be empty if no changes to the
* Exercise were made (i.e. if isStandardExercise).<br />
* Only Elements and Properties which are set or not standard will
* be included.
*
* <pre>
* {@code
* <assignment toolName="Tool2">
* <result name="CORRECT" hint="Great, that's correct!" />
* <result name="WRONG" hint="Try again!" />
* <result name="NOT_ENOUGH_INPUTS" hint="You should at least have {inputs} in your construction!" />
* <result name="WRONG_INPUT_TYPES" hint="We were not able to find {inputs}, although it seems you have drawn a triangle!" />
* <result name="WRONG_OUTPUT_TYPE" hint="We couldn't find a triangle in the construction!" />
* <result name="WRONG_AFTER_RANDOMIZE" hint="Should never happen in this construction! Contact your teacher!" fraction="0.5" />
* <result name="UNKNOWN" hint="Something went wrong - ask your teacher!" />
* </assignment>
* }
* </pre>
*/
public abstract String getAssignmentXML();
/**
* @param sb
* the StringBuilder to which to append the XML common to all
* Assignments
*
* @return XML including the mapping of possible Results to hints and
* fractions
*/
protected StringBuilder getAssignmentXML(StringBuilder sb) {
if (hasHint() || hasFraction()) {
for (Result res1 : Result.values()) {
String hint = hintForResult.get(res1);
Double fraction = fractionForResult.get(res1);
if (hint != null && !hint.isEmpty() || fraction != null) {
sb.append("\t\t<result name=\"");
StringUtil.encodeXML(sb, res1.toString());
sb.append("\" ");
if (hint != null && !hint.isEmpty()) {
sb.append("hint=\"");
StringUtil.encodeXML(sb, hint);
sb.append("\" ");
}
if (fraction != null) {
sb.append("fraction=\"");
sb.append(fraction.floatValue());
sb.append("\" ");
}
sb.append("/>\n");
}
}
}
sb.append("\t</assignment>\n");
return sb;
}
/**
* @return Filename or String indicating which icon should be used by GUI
* for this Assignment
*/
public abstract String getIconFileName();
/**
* @return A String describing the Assignment (eg. Boolean d for a
* BoolAssignment or the ToolName for a GeoAssignment)
*/
public abstract String getDisplayName();
/**
* If construction changes the assignment may become invalid
*
* @return true if the assignment is valid
*/
public abstract boolean isValid();
}