Skip to content

Commit ce612b0

Browse files
authored
Merge pull request #68 from elimu-ai/67-bug-related-to-sorting-order-in-the-word-assessment-activity
fix: reverse list iteration
2 parents fef00ef + 9375d13 commit ce612b0

File tree

2 files changed

+67
-62
lines changed

2 files changed

+67
-62
lines changed

app/src/main/java/ai/elimu/kukariri/logic/SpacedRepetitionHelper.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class SpacedRepetitionHelper {
2626
* @param wordLearningEventGson The _first_ time a {@link ai.elimu.model.v2.gson.content.WordGson} was learned. If
2727
* there are several {@link WordLearningEventGson}s for the same
2828
* {@link ai.elimu.model.v2.gson.content.WordGson}, the oldest one is used.
29-
* @param wordAssessmentEventGsons List of assessments in _ascending_ order, i.e. oldest events are first in the list.
29+
* @param wordAssessmentEventGsons List of assessments in _descending_ order, i.e. most recent events are first in the list.
3030
* @return {@code true} if the {@link ai.elimu.model.v2.gson.content.WordGson} has one or more pending reviews.
3131
*/
3232
public static boolean isReviewPending(WordLearningEventGson wordLearningEventGson, List<WordAssessmentEventGson> wordAssessmentEventGsons) {
@@ -44,7 +44,7 @@ public static boolean isReviewPending(WordLearningEventGson wordLearningEventGso
4444
// At least one review has already been performed
4545

4646
int numberOfCorrectReviewsInSequence = 0;
47-
for (int i = wordAssessmentEventGsons.size() - 1; i >= 0; i--) {
47+
for (int i = 0; i < wordAssessmentEventGsons.size(); i++) {
4848
WordAssessmentEventGson wordAssessmentEventGson = wordAssessmentEventGsons.get(i);
4949
if (wordAssessmentEventGson.getMasteryScore() == 1.00f) {
5050
numberOfCorrectReviewsInSequence++;
@@ -59,43 +59,43 @@ public static boolean isReviewPending(WordLearningEventGson wordLearningEventGso
5959
} else {
6060
// The most recent review was mastered
6161

62-
WordAssessmentEventGson previousWordAssessmentEventGson = wordAssessmentEventGsons.get(wordAssessmentEventGsons.size() - 1);
63-
long milliSecondsPassedSincePreviousAssessmentEvent = Calendar.getInstance().getTimeInMillis() - previousWordAssessmentEventGson.getTime().getTimeInMillis();
64-
Double minutesPassedSincePreviousAssessmentEvent = Double.valueOf(milliSecondsPassedSincePreviousAssessmentEvent / 1000 / 60);
62+
WordAssessmentEventGson mostRecentWordAssessmentEventGson = wordAssessmentEventGsons.get(0);
63+
long milliSecondsPassedSinceMostRecentAssessmentEvent = Calendar.getInstance().getTimeInMillis() - mostRecentWordAssessmentEventGson.getTime().getTimeInMillis();
64+
Double minutesPassedSinceMostRecentAssessmentEvent = Double.valueOf(milliSecondsPassedSinceMostRecentAssessmentEvent / 1000 / 60);
6565

6666
if (numberOfCorrectReviewsInSequence == 1) {
6767
// Check if it's time for the 2nd review
68-
if (minutesPassedSincePreviousAssessmentEvent >= 16) {
68+
if (minutesPassedSinceMostRecentAssessmentEvent >= 16) {
6969
isReviewPending = true;
7070
}
7171
} else if (numberOfCorrectReviewsInSequence == 2) {
7272
// Check if it's time for the 3rd review
73-
if (minutesPassedSincePreviousAssessmentEvent >= 64) {
73+
if (minutesPassedSinceMostRecentAssessmentEvent >= 64) {
7474
isReviewPending = true;
7575
}
7676
} else if (numberOfCorrectReviewsInSequence == 3) {
7777
// Check if it's time for the 4th review
78-
if (minutesPassedSincePreviousAssessmentEvent >= 256) {
78+
if (minutesPassedSinceMostRecentAssessmentEvent >= 256) {
7979
isReviewPending = true;
8080
}
8181
} else if (numberOfCorrectReviewsInSequence == 4) {
8282
// Check if it's time for the 5th review
83-
if (minutesPassedSincePreviousAssessmentEvent >= 1_024) {
83+
if (minutesPassedSinceMostRecentAssessmentEvent >= 1_024) {
8484
isReviewPending = true;
8585
}
8686
} else if (numberOfCorrectReviewsInSequence == 5) {
8787
// Check if it's time for the 6th review
88-
if (minutesPassedSincePreviousAssessmentEvent >= 4_096) {
88+
if (minutesPassedSinceMostRecentAssessmentEvent >= 4_096) {
8989
isReviewPending = true;
9090
}
9191
} else if (numberOfCorrectReviewsInSequence == 6) {
9292
// Check if it's time for the 7th review
93-
if (minutesPassedSincePreviousAssessmentEvent >= 16_384) {
93+
if (minutesPassedSinceMostRecentAssessmentEvent >= 16_384) {
9494
isReviewPending = true;
9595
}
9696
} else if (numberOfCorrectReviewsInSequence == 7) {
9797
// Check if it's time for the 8th review
98-
if (minutesPassedSincePreviousAssessmentEvent >= 65_536) {
98+
if (minutesPassedSinceMostRecentAssessmentEvent >= 65_536) {
9999
isReviewPending = true;
100100
}
101101
}

app/src/test/java/ai/elimu/kukariri/logic/SpacedRepetitionHelperTest.java

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ public void testIsReviewPending_5MinutesAfter_1stReviewNotMastered() {
5656
wordLearningEventGson.setWordId(1L);
5757
wordLearningEventGson.setTime(calendar5MinutesAgo);
5858

59-
List<WordAssessmentEventGson> wordAssessmentEventGsonList = new ArrayList<>();
60-
6159
Calendar calendarNow = Calendar.getInstance();
6260
WordAssessmentEventGson wordAssessmentEventGson = new WordAssessmentEventGson();
6361
wordAssessmentEventGson.setWordId(1L);
6462
wordAssessmentEventGson.setTime(calendarNow);
6563
wordAssessmentEventGson.setMasteryScore(0.00f);
64+
65+
List<WordAssessmentEventGson> wordAssessmentEventGsonList = new ArrayList<>();
6666
wordAssessmentEventGsonList.add(wordAssessmentEventGson);
6767

6868
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsonList), is(true));
@@ -79,13 +79,13 @@ public void testIsReviewPending_5MinutesAfter_1stReviewMastered() {
7979
wordLearningEventGson.setWordId(1L);
8080
wordLearningEventGson.setTime(calendar5MinutesAgo);
8181

82-
List<WordAssessmentEventGson> wordAssessmentEventGsonList = new ArrayList<>();
83-
8482
Calendar calendarNow = Calendar.getInstance();
8583
WordAssessmentEventGson wordAssessmentEventGson = new WordAssessmentEventGson();
8684
wordAssessmentEventGson.setWordId(1L);
8785
wordAssessmentEventGson.setTime(calendarNow);
8886
wordAssessmentEventGson.setMasteryScore(1.00f);
87+
88+
List<WordAssessmentEventGson> wordAssessmentEventGsonList = new ArrayList<>();
8989
wordAssessmentEventGsonList.add(wordAssessmentEventGson);
9090

9191
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsonList), is(false));
@@ -102,13 +102,13 @@ public void testIsReviewPending_17MinutesAfter_MasteryOnFirstTry() {
102102
wordLearningEventGson.setWordId(1L);
103103
wordLearningEventGson.setTime(calendar17MinutesAgo);
104104

105-
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
106-
107105
Calendar calendarNow = Calendar.getInstance();
108106
WordAssessmentEventGson wordAssessmentEventGson = new WordAssessmentEventGson();
109107
wordAssessmentEventGson.setWordId(1L);
110108
wordAssessmentEventGson.setTime(calendarNow);
111109
wordAssessmentEventGson.setMasteryScore(1.00f);
110+
111+
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
112112
wordAssessmentEventGsons.add(wordAssessmentEventGson);
113113

114114
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(false));
@@ -119,75 +119,73 @@ public void testIsReviewPending_17MinutesAfter_MasteryOnFirstTry() {
119119
*/
120120
@Test
121121
public void testIsReviewPending_17MinutesAfter_MasteryOnSecondTry() {
122-
Calendar calendar17MinutesAgo = Calendar.getInstance();
123-
calendar17MinutesAgo.add(Calendar.MINUTE, -17);
122+
Calendar calendar22MinutesAgo = Calendar.getInstance();
123+
calendar22MinutesAgo.add(Calendar.MINUTE, -22);
124124
WordLearningEventGson wordLearningEventGson = new WordLearningEventGson();
125125
wordLearningEventGson.setWordId(1L);
126-
wordLearningEventGson.setTime(calendar17MinutesAgo);
127-
128-
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
126+
wordLearningEventGson.setTime(calendar22MinutesAgo);
129127

130-
Calendar calendar1MinuteAgo = Calendar.getInstance();
131-
calendar1MinuteAgo.add(Calendar.MINUTE, -1);
128+
Calendar calendar18MinutesAgo = Calendar.getInstance();
129+
calendar18MinutesAgo.add(Calendar.MINUTE, -18);
132130
WordAssessmentEventGson wordAssessmentEventGsonFirst = new WordAssessmentEventGson();
133131
wordAssessmentEventGsonFirst.setWordId(1L);
134-
wordAssessmentEventGsonFirst.setTime(calendar1MinuteAgo);
132+
wordAssessmentEventGsonFirst.setTime(calendar18MinutesAgo);
135133
wordAssessmentEventGsonFirst.setMasteryScore(0.00f);
136-
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
137-
138-
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(true));
139134

140-
Calendar calendarNow = Calendar.getInstance();
135+
Calendar calendar17MinutesAgo = Calendar.getInstance();
136+
calendar17MinutesAgo.add(Calendar.MINUTE, -17);
141137
WordAssessmentEventGson wordAssessmentEventGsonSecond = new WordAssessmentEventGson();
142138
wordAssessmentEventGsonSecond.setWordId(1L);
143-
wordAssessmentEventGsonSecond.setTime(calendarNow);
139+
wordAssessmentEventGsonSecond.setTime(calendar17MinutesAgo);
144140
wordAssessmentEventGsonSecond.setMasteryScore(1.00f);
141+
142+
// Store assessment events in _descending_ order
143+
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
145144
wordAssessmentEventGsons.add(wordAssessmentEventGsonSecond);
145+
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
146146

147-
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(false));
147+
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(true));
148148
}
149149

150150
/**
151151
* Test a time _after_ the time of the 2nd review (16 minutes).
152152
*/
153153
@Test
154154
public void testIsReviewPending_17MinutesAfter_MasteryOnThirdTry() {
155-
Calendar calendar17MinutesAgo = Calendar.getInstance();
156-
calendar17MinutesAgo.add(Calendar.MINUTE, -17);
155+
Calendar calendar23MinutesAgo = Calendar.getInstance();
156+
calendar23MinutesAgo.add(Calendar.MINUTE, -23);
157157
WordLearningEventGson wordLearningEventGson = new WordLearningEventGson();
158158
wordLearningEventGson.setWordId(1L);
159-
wordLearningEventGson.setTime(calendar17MinutesAgo);
160-
161-
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
159+
wordLearningEventGson.setTime(calendar23MinutesAgo);
162160

163-
Calendar calendar2MinutesAgo = Calendar.getInstance();
164-
calendar2MinutesAgo.add(Calendar.MINUTE, -2);
161+
Calendar calendar19MinutesAgo = Calendar.getInstance();
162+
calendar19MinutesAgo.add(Calendar.MINUTE, -19);
165163
WordAssessmentEventGson wordAssessmentEventGsonFirst = new WordAssessmentEventGson();
166164
wordAssessmentEventGsonFirst.setWordId(1L);
167-
wordAssessmentEventGsonFirst.setTime(calendar2MinutesAgo);
165+
wordAssessmentEventGsonFirst.setTime(calendar19MinutesAgo);
168166
wordAssessmentEventGsonFirst.setMasteryScore(0.00f);
169-
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
170167

171-
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(true));
172-
173-
Calendar calendar1MinuteAgo = Calendar.getInstance();
174-
calendar1MinuteAgo.add(Calendar.MINUTE, -1);
168+
Calendar calendar18MinutesAgo = Calendar.getInstance();
169+
calendar18MinutesAgo.add(Calendar.MINUTE, -18);
175170
WordAssessmentEventGson wordAssessmentEventGsonSecond = new WordAssessmentEventGson();
176171
wordAssessmentEventGsonSecond.setWordId(1L);
177-
wordAssessmentEventGsonSecond.setTime(calendar1MinuteAgo);
172+
wordAssessmentEventGsonSecond.setTime(calendar18MinutesAgo);
178173
wordAssessmentEventGsonSecond.setMasteryScore(0.00f);
179-
wordAssessmentEventGsons.add(wordAssessmentEventGsonSecond);
180-
181-
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(true));
182174

183-
Calendar calendarNow = Calendar.getInstance();
175+
Calendar calendar17MinutesAgo = Calendar.getInstance();
176+
calendar17MinutesAgo.add(Calendar.MINUTE, -17);
184177
WordAssessmentEventGson wordAssessmentEventGsonThird = new WordAssessmentEventGson();
185178
wordAssessmentEventGsonThird.setWordId(1L);
186-
wordAssessmentEventGsonThird.setTime(calendarNow);
179+
wordAssessmentEventGsonThird.setTime(calendar17MinutesAgo);
187180
wordAssessmentEventGsonThird.setMasteryScore(1.00f);
181+
182+
// Store assessment events in _descending_ order
183+
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
188184
wordAssessmentEventGsons.add(wordAssessmentEventGsonThird);
185+
wordAssessmentEventGsons.add(wordAssessmentEventGsonSecond);
186+
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
189187

190-
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(false));
188+
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(true));
191189
}
192190

193191
/**
@@ -201,14 +199,14 @@ public void testIsReviewPending_false_15MinutesAfterFirstMastery() {
201199
wordLearningEventGson.setWordId(1L);
202200
wordLearningEventGson.setTime(calendar60MinutesAgo);
203201

204-
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
205-
206202
Calendar calendar15MinutesAgo = Calendar.getInstance();
207203
calendar15MinutesAgo.add(Calendar.MINUTE, -15);
208204
WordAssessmentEventGson wordAssessmentEventGsonFirst = new WordAssessmentEventGson();
209205
wordAssessmentEventGsonFirst.setWordId(1L);
210206
wordAssessmentEventGsonFirst.setTime(calendar15MinutesAgo);
211207
wordAssessmentEventGsonFirst.setMasteryScore(1.00f);
208+
209+
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
212210
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
213211

214212
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(false));
@@ -225,14 +223,14 @@ public void testIsReviewPending_true_17MinutesAfterFirstMastery() {
225223
wordLearningEventGson.setWordId(1L);
226224
wordLearningEventGson.setTime(calendar60MinutesAgo);
227225

228-
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
229-
230226
Calendar calendar17MinutesAgo = Calendar.getInstance();
231227
calendar17MinutesAgo.add(Calendar.MINUTE, -17);
232228
WordAssessmentEventGson wordAssessmentEventGsonFirst = new WordAssessmentEventGson();
233229
wordAssessmentEventGsonFirst.setWordId(1L);
234230
wordAssessmentEventGsonFirst.setTime(calendar17MinutesAgo);
235231
wordAssessmentEventGsonFirst.setMasteryScore(1.00f);
232+
233+
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
236234
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
237235

238236
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(true));
@@ -249,24 +247,30 @@ public void testIsReviewPending_false_63MinutesAfterSecondMastery() {
249247
wordLearningEventGson.setWordId(1L);
250248
wordLearningEventGson.setTime(calendar180MinutesAgo);
251249

252-
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
253-
250+
// 1st review (>=4 minutes after learning event)
251+
// 180 minutes ago - 120 minutes ago = 60 minutes passed
254252
Calendar calendar120MinutesAgo = Calendar.getInstance();
255253
calendar120MinutesAgo.add(Calendar.MINUTE, -120);
256254
WordAssessmentEventGson wordAssessmentEventGsonFirst = new WordAssessmentEventGson();
257255
wordAssessmentEventGsonFirst.setWordId(1L);
258256
wordAssessmentEventGsonFirst.setTime(calendar120MinutesAgo);
259257
wordAssessmentEventGsonFirst.setMasteryScore(1.00f);
260-
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
261258

259+
// 2nd review (>=16 minutes after the 1st mastery)
260+
// 120 minutes ago - 63 minutes ago = 57
262261
Calendar calendar63MinutesAgo = Calendar.getInstance();
263262
calendar63MinutesAgo.add(Calendar.MINUTE, -63);
264263
WordAssessmentEventGson wordAssessmentEventGsonSecond = new WordAssessmentEventGson();
265264
wordAssessmentEventGsonSecond.setWordId(1L);
266265
wordAssessmentEventGsonSecond.setTime(calendar63MinutesAgo);
267266
wordAssessmentEventGsonSecond.setMasteryScore(1.00f);
267+
268+
// Store assessment events in _descending_ order
269+
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
268270
wordAssessmentEventGsons.add(wordAssessmentEventGsonSecond);
271+
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
269272

273+
// 3rd review (>=64 minutes after the 2nd mastery)
270274
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(false));
271275
}
272276

@@ -281,23 +285,24 @@ public void testIsReviewPending_true_65MinutesAfterSecondMastery() {
281285
wordLearningEventGson.setWordId(1L);
282286
wordLearningEventGson.setTime(calendar180MinutesAgo);
283287

284-
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
285-
286288
Calendar calendar120MinutesAgo = Calendar.getInstance();
287289
calendar120MinutesAgo.add(Calendar.MINUTE, -120);
288290
WordAssessmentEventGson wordAssessmentEventGsonFirst = new WordAssessmentEventGson();
289291
wordAssessmentEventGsonFirst.setWordId(1L);
290292
wordAssessmentEventGsonFirst.setTime(calendar120MinutesAgo);
291293
wordAssessmentEventGsonFirst.setMasteryScore(1.00f);
292-
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
293294

294295
Calendar calendar65MinutesAgo = Calendar.getInstance();
295296
calendar65MinutesAgo.add(Calendar.MINUTE, -65);
296297
WordAssessmentEventGson wordAssessmentEventGsonSecond = new WordAssessmentEventGson();
297298
wordAssessmentEventGsonSecond.setWordId(1L);
298299
wordAssessmentEventGsonSecond.setTime(calendar65MinutesAgo);
299300
wordAssessmentEventGsonSecond.setMasteryScore(1.00f);
301+
302+
// Store assessment events in _descending_ order
303+
List<WordAssessmentEventGson> wordAssessmentEventGsons = new ArrayList<>();
300304
wordAssessmentEventGsons.add(wordAssessmentEventGsonSecond);
305+
wordAssessmentEventGsons.add(wordAssessmentEventGsonFirst);
301306

302307
assertThat(SpacedRepetitionHelper.isReviewPending(wordLearningEventGson, wordAssessmentEventGsons), is(true));
303308
}

0 commit comments

Comments
 (0)