Search in sources :

Example 16 with INTERVAL

use of com.ichi2.anki.CardBrowser.Column.INTERVAL in project Anki-Android by ankidroid.

the class SchedV2Test method test_moveVersions.

@Test
public void test_moveVersions() throws Exception {
    Collection col = getColV2();
    col.changeSchedulerVer(1);
    Note n = col.newNote();
    n.setItem("Front", "one");
    col.addNote(n);
    // make it a learning card
    col.reset();
    Card c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    // the move to v2 should reset it to new
    col.changeSchedulerVer(2);
    c.load();
    assertEquals(QUEUE_TYPE_NEW, c.getQueue());
    assertEquals(CARD_TYPE_NEW, c.getType());
    // fail it again, and manually bury it
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    col.getSched().buryCards(new long[] { c.getId() });
    c.load();
    assertEquals(QUEUE_TYPE_MANUALLY_BURIED, c.getQueue());
    // revert to version 1
    col.changeSchedulerVer(1);
    // card should have moved queues
    c.load();
    assertEquals(QUEUE_TYPE_SIBLING_BURIED, c.getQueue());
    // and it should be new again when unburied
    col.getSched().unburyCards();
    c.load();
    assertEquals(CARD_TYPE_NEW, c.getQueue());
    assertEquals(QUEUE_TYPE_NEW, c.getType());
    // make sure relearning cards transition correctly to v1
    col.changeSchedulerVer(2);
    // card with 100 day interval, answering again
    col.getSched().reschedCards(Collections.singletonList(c.getId()), 100, 100);
    c.load();
    c.setDue(0);
    c.flush();
    DeckConfig conf = col.getSched()._cardConf(c);
    conf.getJSONObject("lapse").put("mult", 0.5);
    col.getDecks().save(conf);
    col.reset();
    c = getCard();
    col.getSched().answerCard(c, BUTTON_ONE);
    c.load();
    assertEquals(50, c.getIvl());
    // due should be correctly set when removed from learning early
    col.changeSchedulerVer(1);
    c.load();
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    assertEquals(CARD_TYPE_REV, c.getType());
    assertEquals(50, c.getDue());
}
Also used : Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 17 with INTERVAL

use of com.ichi2.anki.CardBrowser.Column.INTERVAL in project Anki-Android by ankidroid.

the class SchedV2Test method test_reviewsV2.

@Test
public void test_reviewsV2() throws Exception {
    Collection col = getColV2();
    // add a note
    Note note = col.newNote();
    note.setItem("Front", "one");
    note.setItem("Back", "two");
    col.addNote(note);
    // set the card up as a review card, due 8 days ago
    Card c = note.cards().get(0);
    c.setType(CARD_TYPE_REV);
    c.setQueue(QUEUE_TYPE_REV);
    c.setDue(col.getSched().getToday() - 8);
    c.setFactor(STARTING_FACTOR);
    c.setReps(3);
    c.setLapses(1);
    c.setIvl(100);
    c.startTimer();
    c.flush();
    // save it for later use as well
    Card cardcopy = c.clone();
    // try with an ease of 2
    // //////////////////////////////////////////////////////////////////////////////////////////////////
    c = cardcopy.clone();
    c.flush();
    col.reset();
    col.getSched().answerCard(c, BUTTON_TWO);
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    // the new interval should be (100) * 1.2 = 120
    assertTrue(checkRevIvl(col, c, 120));
    assertEquals(col.getSched().getToday() + c.getIvl(), c.getDue());
    // factor should have been decremented
    assertEquals(2350, c.getFactor());
    // check counters
    assertEquals(1, c.getLapses());
    assertEquals(4, c.getReps());
    // ease 3
    // //////////////////////////////////////////////////////////////////////////////////////////////////
    c = cardcopy.clone();
    c.flush();
    col.getSched().answerCard(c, BUTTON_THREE);
    // the new interval should be (100 + 8/2) * 2.5 = 260
    assertTrue(checkRevIvl(col, c, 260));
    assertEquals(col.getSched().getToday() + c.getIvl(), c.getDue());
    // factor should have been left alone
    assertEquals(STARTING_FACTOR, c.getFactor());
    // ease 4
    // //////////////////////////////////////////////////////////////////////////////////////////////////
    c = cardcopy.clone();
    c.flush();
    col.getSched().answerCard(c, BUTTON_FOUR);
    // the new interval should be (100 + 8) * 2.5 * 1.3 = 351
    assertTrue(checkRevIvl(col, c, 351));
    assertEquals(col.getSched().getToday() + c.getIvl(), c.getDue());
    // factor should have been increased
    assertEquals(2650, c.getFactor());
    // leech handling
    // //////////////////////////////////////////////////////////////////////////////////////////////////
    DeckConfig conf = col.getDecks().getConf(1);
    conf.getJSONObject("lapse").put("leechAction", LEECH_SUSPEND);
    col.getDecks().save(conf);
    c = cardcopy.clone();
    c.setLapses(7);
    c.flush();
/* todo hook
        // steup hook
        hooked = new [] {};

        def onLeech(card):
        hooked.append(1);

        hooks.card_did_leech.append(onLeech);
        col.getSched().answerCard(c, BUTTON_ONE);
        assertTrue(hooked);
        assertEquals(QUEUE_TYPE_SUSPENDED, c.getQueue());
        c.load();
        assertEquals(QUEUE_TYPE_SUSPENDED, c.getQueue());
        */
}
Also used : Note(com.ichi2.libanki.Note) Collection(com.ichi2.libanki.Collection) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 18 with INTERVAL

use of com.ichi2.anki.CardBrowser.Column.INTERVAL in project Anki-Android by ankidroid.

the class SchedTest method test_learnV1.

@Test
public void test_learnV1() throws Exception {
    Collection col = getColV1();
    // add a note
    Note note = col.newNote();
    note.setItem("Front", "one");
    note.setItem("Back", "two");
    col.addNote(note);
    // set as a learn card and rebuild queues
    col.getDb().execute("update cards set queue=0, type=0");
    col.reset();
    // sched.getCard should return it, since it's due in the past
    Card c = getCard();
    assertNotNull(c);
    DeckConfig conf = col.getSched()._cardConf(c);
    conf.getJSONObject("new").put("delays", new JSONArray(new double[] { 0.5, 3, 10 }));
    col.getDecks().save(conf);
    // fail it
    col.getSched().answerCard(c, BUTTON_ONE);
    // it should have three reps left to graduation
    assertEquals(3, c.getLeft() % 1000);
    assertEquals(3, c.getLeft() / 1000);
    // it should be due in 30 seconds
    long t = Math.round(c.getDue() - col.getTime().intTime());
    assertThat(t, is(greaterThanOrEqualTo(25L)));
    assertThat(t, is(lessThanOrEqualTo(40L)));
    // pass it once
    col.getSched().answerCard(c, BUTTON_TWO);
    // it should be due in 3 minutes
    assertEquals(Math.round(c.getDue() - col.getTime().intTime()), 179, 1);
    assertEquals(2, c.getLeft() % 1000);
    assertEquals(2, c.getLeft() / 1000);
    // check log is accurate
    Cursor log = col.getDb().getDatabase().query("select * from revlog order by id desc");
    assertTrue(log.moveToFirst());
    assertEquals(2, log.getInt(3));
    assertEquals(-180, log.getInt(4));
    assertEquals(-30, log.getInt(5));
    // pass again
    col.getSched().answerCard(c, BUTTON_TWO);
    // it should be due in 10 minutes
    assertEquals(c.getDue() - col.getTime().intTime(), 599, 1);
    assertEquals(1, c.getLeft() % 1000);
    assertEquals(1, c.getLeft() / 1000);
    // the next pass should graduate the card
    assertEquals(QUEUE_TYPE_LRN, c.getQueue());
    assertEquals(CARD_TYPE_LRN, c.getType());
    col.getSched().answerCard(c, BUTTON_TWO);
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    assertEquals(CARD_TYPE_REV, c.getType());
    // should be due tomorrow, with an interval of 1
    assertEquals(col.getSched().getToday() + 1, c.getDue());
    assertEquals(1, c.getIvl());
    // or normal removal
    c.setType(CARD_TYPE_NEW);
    c.setQueue(QUEUE_TYPE_LRN);
    col.getSched().answerCard(c, BUTTON_THREE);
    assertEquals(CARD_TYPE_REV, c.getType());
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    assertTrue(checkRevIvl(col, c, 4));
    // revlog should have been updated each time
    assertEquals(5, col.getDb().queryScalar("select count() from revlog where type = 0"));
    // now failed card handling
    c.setType(CARD_TYPE_REV);
    c.setQueue(QUEUE_TYPE_LRN);
    c.setODue(123);
    col.getSched().answerCard(c, BUTTON_THREE);
    assertEquals(123, c.getDue());
    assertEquals(CARD_TYPE_REV, c.getType());
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    // we should be able to remove manually, too
    c.setType(CARD_TYPE_REV);
    c.setQueue(QUEUE_TYPE_LRN);
    c.setODue(321);
    c.flush();
    ((Sched) col.getSched()).removeLrn();
    c.load();
    assertEquals(QUEUE_TYPE_REV, c.getQueue());
    assertEquals(321, c.getDue());
}
Also used : Note(com.ichi2.libanki.Note) JSONArray(com.ichi2.utils.JSONArray) Collection(com.ichi2.libanki.Collection) Cursor(android.database.Cursor) DeckConfig(com.ichi2.libanki.DeckConfig) Card(com.ichi2.libanki.Card) RobolectricTest(com.ichi2.anki.RobolectricTest) Test(org.junit.Test)

Example 19 with INTERVAL

use of com.ichi2.anki.CardBrowser.Column.INTERVAL in project Anki-Android by ankidroid.

the class SchedV2 method _earlyReviewIvl.

/**
 * next interval for card when answered early+correctly
 */
private int _earlyReviewIvl(@NonNull Card card, @Consts.BUTTON_TYPE int ease) {
    if (!card.isInDynamicDeck() || card.getType() != Consts.CARD_TYPE_REV || card.getFactor() == 0) {
        throw new RuntimeException("Unexpected card parameters");
    }
    if (ease <= 1) {
        throw new RuntimeException("Ease must be greater than 1");
    }
    long elapsed = card.getIvl() - (card.getODue() - mToday);
    @NonNull JSONObject conf = _revConf(card);
    double easyBonus = 1;
    // early 3/4 reviews shouldn't decrease previous interval
    double minNewIvl = 1;
    double factor;
    if (ease == Consts.BUTTON_TWO) {
        factor = conf.optDouble("hardFactor", 1.2);
        // hard cards shouldn't have their interval decreased by more than 50%
        // of the normal factor
        minNewIvl = factor / 2;
    } else if (ease == 3) {
        factor = card.getFactor() / 1000.0;
    } else {
        // ease == 4
        factor = card.getFactor() / 1000.0;
        double ease4 = conf.getDouble("ease4");
        // 1.3 -> 1.15
        easyBonus = ease4 - (ease4 - 1) / 2;
    }
    double ivl = Math.max(elapsed * factor, 1);
    // cap interval decreases
    ivl = Math.max(card.getIvl() * minNewIvl, ivl) * easyBonus;
    return _constrainedIvl(ivl, conf, 0, false);
}
Also used : JSONObject(com.ichi2.utils.JSONObject) NonNull(androidx.annotation.NonNull)

Example 20 with INTERVAL

use of com.ichi2.anki.CardBrowser.Column.INTERVAL in project Anki-Android by ankidroid.

the class SchedV2 method _nextRevIvl.

/*
      Interval management ******************************************************
      *****************************************
     */
/**
 * Next interval for CARD, given EASE.
 */
protected int _nextRevIvl(@NonNull Card card, @Consts.BUTTON_TYPE int ease, boolean fuzz) {
    long delay = _daysLate(card);
    JSONObject conf = _revConf(card);
    double fct = card.getFactor() / 1000.0;
    double hardFactor = conf.optDouble("hardFactor", 1.2);
    int hardMin;
    if (hardFactor > 1) {
        hardMin = card.getIvl();
    } else {
        hardMin = 0;
    }
    int ivl2 = _constrainedIvl(card.getIvl() * hardFactor, conf, hardMin, fuzz);
    if (ease == Consts.BUTTON_TWO) {
        return ivl2;
    }
    int ivl3 = _constrainedIvl((card.getIvl() + delay / 2) * fct, conf, ivl2, fuzz);
    if (ease == Consts.BUTTON_THREE) {
        return ivl3;
    }
    return _constrainedIvl(((card.getIvl() + delay) * fct * conf.getDouble("ease4")), conf, ivl3, fuzz);
}
Also used : JSONObject(com.ichi2.utils.JSONObject)

Aggregations

RobolectricTest (com.ichi2.anki.RobolectricTest)15 Test (org.junit.Test)15 Card (com.ichi2.libanki.Card)12 Collection (com.ichi2.libanki.Collection)12 DeckConfig (com.ichi2.libanki.DeckConfig)12 Note (com.ichi2.libanki.Note)12 JSONArray (com.ichi2.utils.JSONArray)8 JSONObject (com.ichi2.utils.JSONObject)8 Cursor (android.database.Cursor)4 WebView (android.webkit.WebView)3 Config (org.robolectric.annotation.Config)3 NonNull (androidx.annotation.NonNull)2 SQLException (android.database.SQLException)1 AnkiDb (com.ichi2.anki.AnkiDb)1