예제 #1
0
        public override Card GetNextCard(TrialPerformance trialPerformance)
        {
            InitCardDataIfNeeded();

            if (_previousCardIntervalData != null)
            {
                RecordPreviousTrial(trialPerformance);
            }

            if (_activeCards.Count <= 0 && _inactiveCards.Count <= 0)
            {
                return(null);
            }

            if (ShouldActivateNewCard()) // TODO Should this really happen if the user fails? Should we have a staleness metric like back in the good old days?
            {
                ActivateNewCard();
            }

            Card nextCard = _activeCards[0].card;

            _previousCardIntervalData = _activeCards[0];
            _activeCards.Remove(_previousCardIntervalData); // TODO slow?
            return(nextCard);
        }
예제 #2
0
        private void RecordPreviousTrial(TrialPerformance trialPerformance)
        {
            if (_previousCardIntervalData == null)
            {
                throw new InvalidOperationException("Tried to record trial data without first getting a card. GetNextCard first!");
            }

            _previousCardIntervalData = CalculateCardIntervalData(_previousCardIntervalData.card); // HACK HACK FIXME TODO does this even work?

            int insertAt = 0;

            for (int i = 0; i < _activeCards.Count; i++)
            {
                insertAt = i + 1; // TODO FIXME This is a bug that nicely allows us to not see failed cards twice in a row but schedules things off by one
                if (_previousCardIntervalData.interval >= _activeCards[i].interval)
                {
                    continue;
                }
                else
                {
                    break;
                }
            }

            _activeCards.Insert(insertAt, _previousCardIntervalData);

            _database.AddHistoryEntry(_previousCardIntervalData.card, trialPerformance);
        }
예제 #3
0
        private void InitCardDataIfNeeded()
        {
            if (_inactiveCards != null && _activeCards != null)
            {
                return;
            }

            List <AnkiCardIntervalData> cardsWithIntervals = new List <AnkiCardIntervalData>();

            foreach (Card c in _cards)
            {
                AnkiCardIntervalData cardIntervalData = CalculateCardIntervalData(c);
                cardsWithIntervals.Add(cardIntervalData);
            }
            cardsWithIntervals.Sort((cardA, cardB) => cardB.interval.CompareTo(cardA.interval));
            _inactiveCards = cardsWithIntervals;
            _activeCards   = new List <AnkiCardIntervalData>();

            for (int i = _inactiveCards.Count - 1; i >= 0; i--)
            {
                if (_inactiveCards[i].interval > 0)
                {
                    _activeCards.Add(_inactiveCards[i]);
                    _inactiveCards.RemoveAt(i);
                }
            }
        }
예제 #4
0
        private AnkiCardIntervalData CalculateCardIntervalData(Card c)
        {
            IEnumerable <CardHistoryEntry> history = c.HistoryEntries;

            history = history.OrderBy(x => x.EntryTime);
            double           uf               = 0;
            double           interval         = 0;
            CardHistoryEntry lastHistoryEntry = null;

            foreach (CardHistoryEntry historyEntry in history)
            {
                if (lastHistoryEntry == null)
                {
                    interval         = newInterval;
                    lastHistoryEntry = historyEntry;
                }

                switch (historyEntry.TrialPerformance)
                {
                case TrialPerformance.Fail:
                    uf       = CalculateFailFactor(uf);
                    interval = interval * newInterval;
                    break;

                case TrialPerformance.Easy:
                    uf       = CalculateEasyFactor(uf);
                    interval = CalculateEasyInterval(lastHistoryEntry, historyEntry, interval, uf);
                    break;

                case TrialPerformance.Normal:
                    uf       = CalculateNormalFactor(uf);
                    interval = CalculateNormalInterval(lastHistoryEntry, historyEntry, interval, uf);
                    break;

                case TrialPerformance.Hard:
                    uf       = CalculateHardFactor(uf);
                    interval = CalculateHardInterval(lastHistoryEntry, historyEntry, interval);
                    break;

                default:
                    throw new InvalidDataBaseOperationException(String.Format("Unsupported TrialPerformance value in card history: {0}", historyEntry.TrialPerformance));
                }

                lastHistoryEntry = historyEntry;
            }

            var cardIntervalData = new AnkiCardIntervalData()
            {
                lastReview          = lastHistoryEntry?.EntryTime,
                card                = c,
                interval            = interval,
                understandingFactor = uf
            };

            return(cardIntervalData);
        }