1
2
3
4 package sk.stuba.fiit.foo07.genex.generator;
5
6 import java.sql.Connection;
7 import java.sql.SQLException;
8 import java.util.ArrayList;
9 import java.util.Collections;
10 import java.util.Random;
11
12 import sk.stuba.fiit.foo07.genex.beans.Question;
13 import sk.stuba.fiit.foo07.genex.beans.QuestionPoints;
14 import sk.stuba.fiit.foo07.genex.beans.Test;
15 import sk.stuba.fiit.foo07.genex.dao.QuestionDao;
16 import sk.stuba.fiit.foo07.genex.dao.QuestionDaoDerby;
17 import sk.stuba.fiit.foo07.genex.exceptions.NotEnoughQuestionsException;
18
19
20
21
22
23
24
25 public class TestGenerator {
26
27
28 private QuestionDao questionDao;
29 private ArrayList<Question> possibleQuestions;
30 private ArrayList<ArrayList<Question>> possibleQuestionsByDifficulty;
31 private ArrayList<Question> selectedQuestions;
32 private float difficultyAchieved;
33 private Random rand;
34
35
36 private ArrayList<Integer> questionCategoryIDs;
37 private ArrayList<Integer> keywordIDs;
38 private ArrayList<Integer> questionTypeIDs;
39 private int difficultyDesired;
40 private int questionCount;
41 private int pointsSummDesired;
42 private boolean containsPictures;
43 private ArrayList<Integer> difficultiesCount;
44
45
46 private Test generatedTest;
47
48
49
50
51 public Test getGeneratedTest() {
52 return generatedTest;
53 }
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76 public TestGenerator(Connection con,
77 ArrayList<Integer> questionCategoryIDs,
78 ArrayList<Integer> keywordIDs, ArrayList<Integer> questionTypeIDs,
79 int difficultyDesired, int questionCount, int pointsSummDesired,
80 boolean containsPictures) {
81 super();
82 this.rand = new Random();
83 this.questionCategoryIDs = questionCategoryIDs;
84 this.keywordIDs = keywordIDs;
85 this.questionTypeIDs = questionTypeIDs;
86 this.difficultyDesired = difficultyDesired;
87 this.questionCount = questionCount;
88 this.pointsSummDesired = pointsSummDesired;
89 this.containsPictures = containsPictures;
90 this.questionDao = new QuestionDaoDerby(con);
91 }
92
93 public TestGenerator(Connection con,
94 ArrayList<Integer> questionCategoryIDs,
95 ArrayList<Integer> keywordIDs, ArrayList<Integer> questionTypeIDs,
96 int questionCount, int pointsSummDesired, boolean containsPictures,
97 ArrayList<Integer> difficultiesCount) {
98 super();
99 this.rand = new Random();
100 this.questionCategoryIDs = questionCategoryIDs;
101 this.keywordIDs = keywordIDs;
102 this.questionTypeIDs = questionTypeIDs;
103 this.questionCount = questionCount;
104 this.pointsSummDesired = pointsSummDesired;
105 this.containsPictures = containsPictures;
106 this.questionDao = new QuestionDaoDerby(con);
107 this.difficultiesCount = difficultiesCount;
108 }
109
110 private float countProbability(float mean, float stdDeviation, float x) {
111 if (difficultyDesired == 0) {
112 return 1.0f;
113 } else {
114 return (float) ((1 / (Math.sqrt(2 * Math.PI) * stdDeviation)) * Math
115 .exp(-(1 / (2 * stdDeviation * stdDeviation))
116 * Math.pow(x - mean, 2)));
117 }
118 }
119
120 private float getStdDeviation() {
121 if ((difficultyDesired == 1) || (difficultyDesired == 5)) {
122 return 0.8f;
123 } else if ((difficultyDesired == 2) || (difficultyDesired == 4)) {
124 return 1.0f;
125 } else
126 return 1.25f;
127 }
128
129 private int getDeterministicSelection() {
130 int oneFifth = (possibleQuestions.size() / 5);
131 float reminder = (possibleQuestions.size() % 5) / 2;
132 if (difficultyDesired < 3) {
133 return (oneFifth * (difficultyDesired - 1)) + myRandom(oneFifth);
134 } else if (difficultyDesired == 3) {
135 return (oneFifth * (difficultyDesired - 1) + (int) (reminder) + myRandom(oneFifth
136 + Math.round(reminder))) - 1;
137 } else
138 return possibleQuestions.size() - 1
139 - ((6 - difficultyDesired) * oneFifth) + myRandom(oneFifth);
140 }
141
142 private int myRandom(int i) {
143 if (i == 0)
144 return 0;
145 else
146 return rand.nextInt(i);
147 }
148
149 private void selectQuestions() {
150
151 boolean wasSelected = false;
152 float actualTestDifficulty = 3.0f;
153 float stdDeviation = 0.0f;
154 float randomQuestionProbability;
155 int randomSellection = 0;
156 int deterministicSelection = 0;
157 Question toAdd = null;
158
159 int hit = 0;
160
161 selectedQuestions = new ArrayList<Question>(questionCount);
162
163 for (int i = 0; i < questionCount; i++) {
164 stdDeviation = getStdDeviation();
165 wasSelected = false;
166
167 for (int j = 0; j < possibleQuestions.size(); j++) {
168 randomSellection = rand.nextInt(possibleQuestions.size());
169 toAdd = possibleQuestions.get(randomSellection);
170 if (Math.abs(toAdd.getDifficulty() - difficultyDesired) > 2) {
171 continue;
172 }
173 randomQuestionProbability = countProbability(difficultyDesired,
174 stdDeviation, toAdd.getDifficulty());
175
176 if (rand.nextFloat() < randomQuestionProbability) {
177 selectedQuestions.add(i, toAdd);
178 possibleQuestions.remove(randomSellection);
179 wasSelected = true;
180 System.out.println("Selested question: "
181 + toAdd.getDifficulty() + " " + difficultyDesired);
182 break;
183 }
184 }
185
186 if (!wasSelected) {
187 deterministicSelection = getDeterministicSelection();
188 if (deterministicSelection >= possibleQuestions.size()
189 || deterministicSelection == -1) {
190 deterministicSelection = possibleQuestions.size() - 1;
191 }
192 if (possibleQuestions.size() == 0) {
193 return;
194 }
195 toAdd = possibleQuestions.get(deterministicSelection);
196 selectedQuestions.add(i, toAdd);
197 possibleQuestions.remove(deterministicSelection);
198 hit++;
199 }
200 actualTestDifficulty = (actualTestDifficulty * i + toAdd
201 .getDifficulty())
202 / (i + 1);
203 }
204 difficultyAchieved = actualTestDifficulty;
205 System.out.println("hits: " + hit);
206 }
207
208 private float round(float f) {
209 return Math.round(f * 2) / 2f;
210 }
211
212 private void countPoints() {
213 ArrayList<QuestionPoints> points = new ArrayList<QuestionPoints>(
214 questionCount);
215 float point = 0.0f;
216
217 if (pointsSummDesired == 0) {
218 for (Question q : selectedQuestions) {
219 point = q.getDifficulty();
220 points.add(new QuestionPoints(q.getQuestionID(), point));
221 }
222 } else {
223 float pointsDifficultyKoeficient = pointsSummDesired
224 / (difficultyAchieved * questionCount);
225
226 for (Question q : selectedQuestions) {
227 point = this.round(pointsDifficultyKoeficient
228 * q.getDifficulty());
229 points.add(new QuestionPoints(q.getQuestionID(), point));
230 }
231 }
232
233 generatedTest = new Test(null, null, null, null, null, null, points);
234
235 }
236
237
238
239
240
241
242
243
244
245 public void generateTest() throws NotEnoughQuestionsException, SQLException {
246 possibleQuestions = questionDao.getQuestionsByIDs(questionDao
247 .getQuestionsForTestGenerator(questionCategoryIDs, keywordIDs,
248 questionTypeIDs, containsPictures, null));
249 if (possibleQuestions.size() < questionCount) {
250 throw new NotEnoughQuestionsException();
251 }
252 Collections.shuffle(possibleQuestions);
253 Collections.sort(possibleQuestions);
254
255 selectQuestions();
256 System.out.println("Size after: " + possibleQuestions.size());
257 countPoints();
258
259 }
260
261 public void assembleTest() throws NotEnoughQuestionsException, SQLException {
262 int possibleQuestionCount = 0;
263 possibleQuestionsByDifficulty = new ArrayList<ArrayList<Question>>(5);
264 for (int i = 0; i < 5; i++) {
265 possibleQuestions = questionDao.getQuestionsByIDs(questionDao
266 .getQuestionsForTestGenerator(questionCategoryIDs,
267 keywordIDs, questionTypeIDs, containsPictures,
268 i + 1));
269 possibleQuestionsByDifficulty.add(i, possibleQuestions);
270
271 if (possibleQuestions.size() < difficultiesCount.get(i)) {
272 throw new NotEnoughQuestionsException(
273 "Not enough questions of difficulty " + (i + 1)
274 + " to generate Test.");
275 }
276 possibleQuestionCount += possibleQuestions.size();
277 }
278
279 if (possibleQuestionCount < questionCount) {
280 throw new NotEnoughQuestionsException(
281 "Not enough questions to generate Test.");
282 }
283
284 Question toAdd = null;
285 selectedQuestions = new ArrayList<Question>(questionCount);
286 int randomIndex;
287 int difficultyCount;
288 int numberOfQuestionsSelected = 0;
289 difficultyAchieved = 0;
290
291 for (int j = 0; j < 5; j++) {
292 difficultyCount = difficultiesCount.get(j);
293 possibleQuestions = possibleQuestionsByDifficulty.get(j);
294 for (int i = 0; i < difficultyCount; i++) {
295 randomIndex = rand.nextInt(possibleQuestions.size());
296 toAdd = possibleQuestions.get(randomIndex);
297 selectedQuestions.add(toAdd);
298 possibleQuestions.remove(randomIndex);
299 difficultyAchieved = difficultyAchieved + toAdd.getDifficulty();
300 numberOfQuestionsSelected++;
301 }
302 }
303 for (int i = numberOfQuestionsSelected; i < questionCount; i++) {
304 do {
305 randomIndex = rand.nextInt(5);
306 possibleQuestions = possibleQuestionsByDifficulty
307 .get(randomIndex);
308 } while (possibleQuestions.size() <= 0);
309 randomIndex = rand.nextInt(possibleQuestions.size());
310 toAdd = possibleQuestions.get(randomIndex);
311 selectedQuestions.add(toAdd);
312 possibleQuestions.remove(randomIndex);
313 difficultyAchieved = difficultyAchieved + toAdd.getDifficulty();
314
315 }
316 difficultyAchieved = difficultyAchieved / questionCount;
317 countPoints();
318 }
319 }