summaryrefslogtreecommitdiff
path: root/src/com/p4square/grow/model
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/p4square/grow/model')
-rw-r--r--src/com/p4square/grow/model/Answer.java135
-rw-r--r--src/com/p4square/grow/model/CircleQuestion.java89
-rw-r--r--src/com/p4square/grow/model/ImageQuestion.java24
-rw-r--r--src/com/p4square/grow/model/Point.java79
-rw-r--r--src/com/p4square/grow/model/QuadQuestion.java89
-rw-r--r--src/com/p4square/grow/model/QuadScoringEngine.java49
-rw-r--r--src/com/p4square/grow/model/Question.java134
-rw-r--r--src/com/p4square/grow/model/RecordedAnswer.java34
-rw-r--r--src/com/p4square/grow/model/Score.java70
-rw-r--r--src/com/p4square/grow/model/ScoringEngine.java26
-rw-r--r--src/com/p4square/grow/model/SimpleScoringEngine.java26
-rw-r--r--src/com/p4square/grow/model/SliderQuestion.java24
-rw-r--r--src/com/p4square/grow/model/SliderScoringEngine.java29
-rw-r--r--src/com/p4square/grow/model/TextQuestion.java24
14 files changed, 769 insertions, 63 deletions
diff --git a/src/com/p4square/grow/model/Answer.java b/src/com/p4square/grow/model/Answer.java
index 4c84060..57a1e5d 100644
--- a/src/com/p4square/grow/model/Answer.java
+++ b/src/com/p4square/grow/model/Answer.java
@@ -4,7 +4,7 @@
package com.p4square.grow.model;
-import java.util.Map;
+import org.apache.log4j.Logger;
/**
* This is the model of an assessment question's answer.
@@ -12,52 +12,131 @@ import java.util.Map;
* @author Jesse Morgan <jesse@jesterpm.net>
*/
public class Answer {
+ private static final Logger LOG = Logger.getLogger(Answer.class);
+
+ /**
+ * ScoreType determines how the answer will be scored.
+ *
+ */
public static enum ScoreType {
- NONE, AVERAGE, TRUMP;
- }
-
- private final String mAnswerId;
- private final String mAnswerText;
- private final ScoreType mType;
- private final float mScoreFactor;
- private final String mNextQuestionId;
-
- public Answer(final String id, final Map<String, Object> answer) {
- mAnswerId = id;
- mAnswerText = (String) answer.get("text");
- final String typeStr = (String) answer.get("type");
- if (typeStr == null) {
- mType = ScoreType.AVERAGE;
- } else {
- mType = ScoreType.valueOf(typeStr.toUpperCase());
- }
+ /**
+ * This question has no effect on the score.
+ */
+ NONE,
- if (mType != ScoreType.NONE) {
- mScoreFactor = Float.valueOf((String) answer.get("score"));
- } else {
- mScoreFactor = 0;
- }
+ /**
+ * The score of this question is part of the average.
+ */
+ AVERAGE,
- mNextQuestionId = (String) answer.get("nextQuestion");
+ /**
+ * The score of this question is the total score, no other questions
+ * matter after this point.
+ */
+ TRUMP;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
}
- public String getId() {
- return mAnswerId;
+ private String mAnswerText;
+ private ScoreType mType;
+ private float mScoreFactor;
+ private String mNextQuestionId;
+
+ public Answer() {
+ mType = ScoreType.AVERAGE;
}
+ /**
+ * @return The text associated with the answer.
+ */
public String getText() {
return mAnswerText;
}
+ /**
+ * Set the text associated with the answer.
+ * @param text The new text.
+ */
+ public void setText(String text) {
+ mAnswerText = text;
+ }
+
+ /**
+ * @return the ScoreType for the Answer.
+ */
public ScoreType getType() {
return mType;
}
- public float getScoreFactor() {
+ /**
+ * Set the ScoreType for the answer.
+ * @param type The new ScoreType.
+ */
+ public void setType(ScoreType type) {
+ mType = type;
+ }
+
+ /**
+ * @return the delta of the score if this answer is selected.
+ */
+ public float getScore() {
+ if (mType == ScoreType.NONE) {
+ return 0;
+ }
+
return mScoreFactor;
}
+ /**
+ * Set the score delta for this answer.
+ * @param score The new delta.
+ */
+ public void setScore(float score) {
+ mScoreFactor = score;
+ }
+
+ /**
+ * @return the id of the next question if this answer is selected, or null
+ * if selecting this answer has no effect.
+ */
public String getNextQuestion() {
return mNextQuestionId;
}
+
+ /**
+ * Set the id of the next question when this answer is selected.
+ * @param id The next question id or null to proceed as usual.
+ */
+ public void setNextQuestion(String id) {
+ mNextQuestionId = id;
+ }
+
+ /**
+ * Adjust the running score for the selection of this answer.
+ * @param score The running score to adjust.
+ * @return true if scoring should continue, false if this answer trumps all.
+ */
+ public boolean score(final Score score) {
+ switch (getType()) {
+ case TRUMP:
+ score.sum = getScore();
+ score.count = 1;
+ return false; // Quit scoring.
+
+ case AVERAGE:
+ LOG.error("ScoreType.AVERAGE: { delta: \"" + getScore() + "\" }");
+ score.sum += getScore();
+ score.count++;
+ break;
+
+ case NONE:
+ break;
+ }
+
+ return true; // Continue scoring
+ }
}
diff --git a/src/com/p4square/grow/model/CircleQuestion.java b/src/com/p4square/grow/model/CircleQuestion.java
new file mode 100644
index 0000000..71acc14
--- /dev/null
+++ b/src/com/p4square/grow/model/CircleQuestion.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Circle Question.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class CircleQuestion extends Question {
+ private static final ScoringEngine ENGINE = new QuadScoringEngine();
+
+ private String mTopLeft;
+ private String mTopRight;
+ private String mBottomLeft;
+ private String mBottomRight;
+
+ /**
+ * @return the Top Left label.
+ */
+ public String getTopLeft() {
+ return mTopLeft;
+ }
+
+ /**
+ * Set the Top Left label.
+ * @param s The new top left label.
+ */
+ public void setTopLeft(String s) {
+ mTopLeft = s;
+ }
+
+ /**
+ * @return the Top Right label.
+ */
+ public String getTopRight() {
+ return mTopRight;
+ }
+
+ /**
+ * Set the Top Right label.
+ * @param s The new top left label.
+ */
+ public void setTopRight(String s) {
+ mTopRight = s;
+ }
+
+ /**
+ * @return the Bottom Left label.
+ */
+ public String getBottomLeft() {
+ return mBottomLeft;
+ }
+
+ /**
+ * Set the Bottom Left label.
+ * @param s The new top left label.
+ */
+ public void setBottomLeft(String s) {
+ mBottomLeft = s;
+ }
+
+ /**
+ * @return the Bottom Right label.
+ */
+ public String getBottomRight() {
+ return mBottomRight;
+ }
+
+ /**
+ * Set the Bottom Right label.
+ * @param s The new top left label.
+ */
+ public void setBottomRight(String s) {
+ mBottomRight = s;
+ }
+
+ @Override
+ public boolean scoreAnswer(Score score, RecordedAnswer answer) {
+ return ENGINE.scoreAnswer(score, this, answer);
+ }
+
+ @Override
+ public QuestionType getType() {
+ return QuestionType.CIRCLE;
+ }
+}
diff --git a/src/com/p4square/grow/model/ImageQuestion.java b/src/com/p4square/grow/model/ImageQuestion.java
new file mode 100644
index 0000000..d94c32c
--- /dev/null
+++ b/src/com/p4square/grow/model/ImageQuestion.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Image Question.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class ImageQuestion extends Question {
+ private static final ScoringEngine ENGINE = new SimpleScoringEngine();
+
+ @Override
+ public boolean scoreAnswer(Score score, RecordedAnswer answer) {
+ return ENGINE.scoreAnswer(score, this, answer);
+ }
+
+ @Override
+ public QuestionType getType() {
+ return QuestionType.IMAGE;
+ }
+}
diff --git a/src/com/p4square/grow/model/Point.java b/src/com/p4square/grow/model/Point.java
new file mode 100644
index 0000000..e9fc0ca
--- /dev/null
+++ b/src/com/p4square/grow/model/Point.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Simple double based point class.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class Point {
+ /**
+ * Parse a comma separated x,y pair into a point.
+ *
+ * @return The point represented by the string.
+ * @throws IllegalArgumentException if the input is malformed.
+ */
+ public static Point valueOf(String str) {
+ final int comma = str.indexOf(',');
+ if (comma == -1 || comma == 0 || comma == str.length() - 1) {
+ throw new IllegalArgumentException("Malformed point string");
+ }
+
+ final String sX = str.substring(0, comma);
+ final String sY = str.substring(comma + 1);
+
+ return new Point(Double.valueOf(sX), Double.valueOf(sY));
+ }
+
+ private final double mX;
+ private final double mY;
+
+ /**
+ * Create a new point with the given coordinates.
+ *
+ * @param x The x coordinate.
+ * @param y The y coordinate.
+ */
+ public Point(double x, double y) {
+ mX = x;
+ mY = y;
+ }
+
+ /**
+ * Compute the distance between this point and another.
+ *
+ * @param other The other point.
+ * @return The distance between this point and other.
+ */
+ public double distance(Point other) {
+ final double dx = mX - other.mX;
+ final double dy = mY - other.mY;
+
+ return Math.sqrt(dx*dx + dy*dy);
+ }
+
+ /**
+ * @return The x coordinate.
+ */
+ public double getX() {
+ return mX;
+ }
+
+ /**
+ * @return The y coordinate.
+ */
+ public double getY() {
+ return mY;
+ }
+
+ /**
+ * @return The point represented as a comma separated pair.
+ */
+ @Override
+ public String toString() {
+ return String.format("%.2f,%.2f", mX, mY);
+ }
+}
diff --git a/src/com/p4square/grow/model/QuadQuestion.java b/src/com/p4square/grow/model/QuadQuestion.java
new file mode 100644
index 0000000..a7b4179
--- /dev/null
+++ b/src/com/p4square/grow/model/QuadQuestion.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Two-dimensional Question.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class QuadQuestion extends Question {
+ private static final ScoringEngine ENGINE = new QuadScoringEngine();
+
+ private String mTop;
+ private String mRight;
+ private String mBottom;
+ private String mLeft;
+
+ /**
+ * @return the top label.
+ */
+ public String getTop() {
+ return mTop;
+ }
+
+ /**
+ * Set the top label.
+ * @param s The new top label.
+ */
+ public void setTop(String s) {
+ mTop = s;
+ }
+
+ /**
+ * @return the right label.
+ */
+ public String getRight() {
+ return mRight;
+ }
+
+ /**
+ * Set the right label.
+ * @param s The new right label.
+ */
+ public void setRight(String s) {
+ mRight = s;
+ }
+
+ /**
+ * @return the bottom label.
+ */
+ public String getBottom() {
+ return mBottom;
+ }
+
+ /**
+ * Set the bottom label.
+ * @param s The new bottom label.
+ */
+ public void setBottom(String s) {
+ mBottom = s;
+ }
+
+ /**
+ * @return the left label.
+ */
+ public String getLeft() {
+ return mLeft;
+ }
+
+ /**
+ * Set the left label.
+ * @param s The new left label.
+ */
+ public void setLeft(String s) {
+ mLeft = s;
+ }
+
+ @Override
+ public boolean scoreAnswer(Score score, RecordedAnswer answer) {
+ return ENGINE.scoreAnswer(score, this, answer);
+ }
+
+ @Override
+ public QuestionType getType() {
+ return QuestionType.QUAD;
+ }
+}
diff --git a/src/com/p4square/grow/model/QuadScoringEngine.java b/src/com/p4square/grow/model/QuadScoringEngine.java
new file mode 100644
index 0000000..33403b5
--- /dev/null
+++ b/src/com/p4square/grow/model/QuadScoringEngine.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+import com.p4square.grow.model.Point;
+
+/**
+ * QuadScoringEngine expects the user's answer to be a Point string. We find
+ * the closest answer Point to the user's answer and treat that as the answer.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class QuadScoringEngine extends ScoringEngine {
+
+ @Override
+ public boolean scoreAnswer(Score score, Question question, RecordedAnswer userAnswer) {
+ // Find all of the answer points.
+ Point[] answers = new Point[question.getAnswers().size()];
+ {
+ int i = 0;
+ for (String answerStr : question.getAnswers().keySet()) {
+ answers[i++] = Point.valueOf(answerStr);
+ }
+ }
+
+ // Parse the user's answer.
+ Point userPoint = Point.valueOf(userAnswer.getAnswerId());
+
+ // Find the closest answer point to the user's answer.
+ double minDistance = Double.MAX_VALUE;
+ int answerIndex = 0;
+ for (int i = 0; i < answers.length; i++) {
+ final double distance = userPoint.distance(answers[i]);
+ if (distance < minDistance) {
+ minDistance = distance;
+ answerIndex = i;
+ }
+ }
+
+ LOG.debug("Quad " + question.getId() + ": Got answer "
+ + answers[answerIndex].toString() + " for user point " + userAnswer);
+
+ // Get the answer and update the score.
+ final Answer answer = question.getAnswers().get(answers[answerIndex].toString());
+ return answer.score(score);
+ }
+}
diff --git a/src/com/p4square/grow/model/Question.java b/src/com/p4square/grow/model/Question.java
index 387d723..37deffa 100644
--- a/src/com/p4square/grow/model/Question.java
+++ b/src/com/p4square/grow/model/Question.java
@@ -4,76 +4,125 @@
package com.p4square.grow.model;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
+import org.codehaus.jackson.annotate.JsonSubTypes;
+import org.codehaus.jackson.annotate.JsonSubTypes.Type;
+import org.codehaus.jackson.annotate.JsonTypeInfo;
+
/**
* Model of an assessment question.
*
* @author Jesse Morgan <jesse@jesterpm.net>
*/
-public class Question {
- public static enum QuestionType {
- TEXT, IMAGE, SLIDER, QUAD, CIRCLE;
+@JsonTypeInfo(
+ use = JsonTypeInfo.Id.NAME,
+ include = JsonTypeInfo.As.PROPERTY,
+ property = "type")
+@JsonSubTypes({
+ @Type(value = TextQuestion.class, name = "text"),
+ @Type(value = ImageQuestion.class, name = "image"),
+ @Type(value = SliderQuestion.class, name = "slider"),
+ @Type(value = QuadQuestion.class, name = "quad"),
+ @Type(value = CircleQuestion.class, name = "circle"),
+})
+public abstract class Question {
+ /**
+ * QuestionType indicates the type of Question.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+ public enum QuestionType {
+ TEXT,
+ IMAGE,
+ SLIDER,
+ QUAD,
+ CIRCLE;
+
+ @Override
+ public String toString() {
+ return name().toLowerCase();
+ }
}
- private final Map<String, Object> mMap;
- private final String mQuestionId;
- private final QuestionType mType;
- private final String mQuestionText;
+ private String mQuestionId;
+ private QuestionType mType;
+ private String mQuestionText;
private Map<String, Answer> mAnswers;
- private final String mPreviousQuestionId;
- private final String mNextQuestionId;
-
- public Question(final Map<String, Object> map) {
- mMap = map;
- mQuestionId = (String) map.get("id");
- mType = QuestionType.valueOf(((String) map.get("type")).toUpperCase());
-
- mQuestionText = (String) map.get("text");
-
- mPreviousQuestionId = (String) map.get("previousQuestion");
- mNextQuestionId = (String) map.get("nextQuestion");
+ private String mPreviousQuestionId;
+ private String mNextQuestionId;
+ public Question() {
mAnswers = new HashMap<String, Answer>();
- for (Map.Entry<String, Object> answer :
- ((Map<String, Object>) map.get("answers")).entrySet()) {
-
- final String id = answer.getKey();
- final Map<String, Object> answerMap = (Map<String, Object>) answer.getValue();
- final Answer answerObj = new Answer(id, answerMap);
- mAnswers.put(id, answerObj);
- }
}
+ /**
+ * @return the id String for this question.
+ */
public String getId() {
return mQuestionId;
}
- public QuestionType getType() {
- return mType;
+ /**
+ * Set the id String for this question.
+ * @param id New id
+ */
+ public void setId(String id) {
+ mQuestionId = id;
}
- public String getText() {
+ /**
+ * @return The Question text.
+ */
+ public String getQuestion() {
return mQuestionText;
}
+ /**
+ * Set the question text.
+ * @param value The new question text.
+ */
+ public void setQuestion(String value) {
+ mQuestionText = value;
+ }
+
+ /**
+ * @return The id String of the previous question or null if no previous question exists.
+ */
public String getPreviousQuestion() {
return mPreviousQuestionId;
}
+ /**
+ * Set the id string of the previous question.
+ * @param id Previous question id or null if there is no previous question.
+ */
+ public void setPreviousQuestion(String id) {
+ mPreviousQuestionId = id;
+ }
+
+ /**
+ * @return The id String of the next question or null if no next question exists.
+ */
public String getNextQuestion() {
return mNextQuestionId;
}
- public Map<String, Answer> getAnswers() {
- return Collections.unmodifiableMap(mAnswers);
+ /**
+ * Set the id string of the next question.
+ * @param id next question id or null if there is no next question.
+ */
+ public void setNextQuestion(String id) {
+ mNextQuestionId = id;
}
- public Map<String, Object> getMap() {
- return Collections.unmodifiableMap(mMap);
+ /**
+ * @return a map of Answer id Strings to Answer objects.
+ */
+ public Map<String, Answer> getAnswers() {
+ return mAnswers;
}
/**
@@ -98,4 +147,19 @@ public class Question {
return nextQuestion;
}
+
+ /**
+ * Update the score based on the answer to this question.
+ *
+ * @param score The running score to update.
+ * @param answer The answer give to this question.
+ * @return true if scoring should continue, false if this answer trumps everything else.
+ */
+ public abstract boolean scoreAnswer(Score score, RecordedAnswer answer);
+
+ /**
+ * @return the QuestionType of this question.
+ */
+ public abstract QuestionType getType();
+
}
diff --git a/src/com/p4square/grow/model/RecordedAnswer.java b/src/com/p4square/grow/model/RecordedAnswer.java
new file mode 100644
index 0000000..7d9905d
--- /dev/null
+++ b/src/com/p4square/grow/model/RecordedAnswer.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Simple model for a user's assessment answer.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class RecordedAnswer {
+ private String mAnswerId;
+
+ /**
+ * @return The user's answer.
+ */
+ public String getAnswerId() {
+ return mAnswerId;
+ }
+
+ /**
+ * Set the answer id field.
+ * @param id The new id.
+ */
+ public void setAnswerId(String id) {
+ mAnswerId = id;
+ }
+
+ @Override
+ public String toString() {
+ return mAnswerId;
+ }
+}
diff --git a/src/com/p4square/grow/model/Score.java b/src/com/p4square/grow/model/Score.java
new file mode 100644
index 0000000..b6deda2
--- /dev/null
+++ b/src/com/p4square/grow/model/Score.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Simple structure containing a score's sum and count.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class Score {
+ /**
+ * Return the integer value for the given Score String.
+ */
+ public static int numericScore(String score) {
+ if ("teacher".equals(score)) {
+ return 4;
+ } else if ("disciple".equals(score)) {
+ return 3;
+ } else if ("believer".equals(score)) {
+ return 2;
+ } else {
+ return 1;
+ }
+ }
+
+ double sum;
+ int count;
+
+ /**
+ * @return The sum of all the points.
+ */
+ public double getSum() {
+ return sum;
+ }
+
+ /**
+ * @return The number of questions included in the score.
+ */
+ public int getCount() {
+ return count;
+ }
+
+ /**
+ * @return The final score.
+ */
+ public double getScore() {
+ return sum / count;
+ }
+
+ @Override
+ public String toString() {
+ final double score = getScore();
+
+ if (score >= 4) {
+ return "teacher";
+
+ } else if (score >= 3) {
+ return "disciple";
+
+ } else if (score >= 2) {
+ return "believer";
+
+ } else {
+ return "seeker";
+ }
+ }
+
+}
diff --git a/src/com/p4square/grow/model/ScoringEngine.java b/src/com/p4square/grow/model/ScoringEngine.java
new file mode 100644
index 0000000..8ff18b3
--- /dev/null
+++ b/src/com/p4square/grow/model/ScoringEngine.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+import org.apache.log4j.Logger;
+
+/**
+ * ScoringEngine computes the score for a question and a given answer.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public abstract class ScoringEngine {
+ protected static final Logger LOG = Logger.getLogger(ScoringEngine.class);
+
+ /**
+ * Update the score based on the given question and answer.
+ *
+ * @param score The running score to update.
+ * @param question The question to compute the score for.
+ * @param answer The answer give to this question.
+ * @return true if scoring should continue, false if this answer trumps everything else.
+ */
+ public abstract boolean scoreAnswer(Score score, Question question, RecordedAnswer answer);
+}
diff --git a/src/com/p4square/grow/model/SimpleScoringEngine.java b/src/com/p4square/grow/model/SimpleScoringEngine.java
new file mode 100644
index 0000000..6ef2dbb
--- /dev/null
+++ b/src/com/p4square/grow/model/SimpleScoringEngine.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * SimpleScoringEngine expects the user's answer to a valid answer id and
+ * scores accordingly.
+ *
+ * If the answer id is not valid an Exception is thrown.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class SimpleScoringEngine extends ScoringEngine {
+
+ @Override
+ public boolean scoreAnswer(Score score, Question question, RecordedAnswer userAnswer) {
+ final Answer answer = question.getAnswers().get(userAnswer.getAnswerId());
+ if (answer == null) {
+ throw new IllegalArgumentException("Not a valid answer.");
+ }
+
+ return answer.score(score);
+ }
+}
diff --git a/src/com/p4square/grow/model/SliderQuestion.java b/src/com/p4square/grow/model/SliderQuestion.java
new file mode 100644
index 0000000..f0861e3
--- /dev/null
+++ b/src/com/p4square/grow/model/SliderQuestion.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Slider Question.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class SliderQuestion extends Question {
+ private static final ScoringEngine ENGINE = new SliderScoringEngine();
+
+ @Override
+ public boolean scoreAnswer(Score score, RecordedAnswer answer) {
+ return ENGINE.scoreAnswer(score, this, answer);
+ }
+
+ @Override
+ public QuestionType getType() {
+ return QuestionType.SLIDER;
+ }
+}
diff --git a/src/com/p4square/grow/model/SliderScoringEngine.java b/src/com/p4square/grow/model/SliderScoringEngine.java
new file mode 100644
index 0000000..76811b3
--- /dev/null
+++ b/src/com/p4square/grow/model/SliderScoringEngine.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * SliderScoringEngine expects the user's answer to be a decimal value in the
+ * range [0, 1]. The value is scaled to the range [1, 4] and added to the
+ * score.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class SliderScoringEngine extends ScoringEngine {
+
+ @Override
+ public boolean scoreAnswer(Score score, Question question, RecordedAnswer userAnswer) {
+ float delta = Float.valueOf(userAnswer.getAnswerId()) * 3 + 1;
+
+ if (delta < 0 || delta > 4) {
+ throw new IllegalArgumentException("Answer out of bounds.");
+ }
+
+ score.sum += delta;
+ score.count++;
+
+ return true;
+ }
+}
diff --git a/src/com/p4square/grow/model/TextQuestion.java b/src/com/p4square/grow/model/TextQuestion.java
new file mode 100644
index 0000000..88c2a34
--- /dev/null
+++ b/src/com/p4square/grow/model/TextQuestion.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2013 Jesse Morgan
+ */
+
+package com.p4square.grow.model;
+
+/**
+ * Text Question.
+ *
+ * @author Jesse Morgan <jesse@jesterpm.net>
+ */
+public class TextQuestion extends Question {
+ private static final ScoringEngine ENGINE = new SimpleScoringEngine();
+
+ @Override
+ public boolean scoreAnswer(Score score, RecordedAnswer answer) {
+ return ENGINE.scoreAnswer(score, this, answer);
+ }
+
+ @Override
+ public QuestionType getType() {
+ return QuestionType.TEXT;
+ }
+}