Created
July 9, 2018 19:20
-
-
Save doctorpangloss/928cf677fbe8de34ae80cd539c65fce9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using System.Linq; | |
using UnityEngine; | |
namespace ProjectHolste | |
{ | |
public class RepetitionAlgorithm<T> : IEnumerator<T> | |
{ | |
public Func<T, string> Keyer { get; private set; } | |
private readonly TimeSpan m_TimeSinceLastSession; | |
private readonly List<T> m_Problems = new List<T>(); | |
private bool m_Answered = false; | |
public RepetitionAlgorithm(TimeSpan timeSinceLastSession, Func<T, string> keyer, List<T> problems) | |
{ | |
Keyer = keyer; | |
m_TimeSinceLastSession = timeSinceLastSession; | |
// Choose N number of items for review minimum, ordered by descending PercentageOverdue | |
m_Problems.AddRange(problems.OrderByDescending(SortScore)); | |
// Discard items reviewed in the past 8 hours | |
} | |
private float SortScore(T arg) | |
{ | |
var record = this[Keyer(arg)]; | |
if (DateTime.Now - new DateTime(record.DateLateReviewed) > TimeSpan.FromHours(8)) | |
{ | |
return PercentOverdue(record); | |
} | |
return 0f; | |
} | |
public RepetitionAlgorithmRecord this[string id] | |
{ | |
get | |
{ | |
var json = PlayerPrefs.GetString(id, null); | |
if (json == null) | |
{ | |
return new RepetitionAlgorithmRecord() | |
{ | |
Key = id, | |
DateLateReviewed = DateTime.Now.Ticks, | |
Difficulty = 0.5f | |
}; | |
} | |
return JsonUtility.FromJson<RepetitionAlgorithmRecord>(json); | |
} | |
set | |
{ | |
PlayerPrefs.SetString(id, JsonUtility.ToJson(value)); | |
PlayerPrefs.Save(); | |
} | |
} | |
public void Answer(TimeSpan timeSpent, bool choseCorrectly) | |
{ | |
var impliedDifficulty = 1f / (1f + Mathf.Exp(-0.4f * (float) timeSpent.TotalSeconds + 2f)); | |
if (choseCorrectly) | |
{ | |
impliedDifficulty = Mathf.Max(0.6f, impliedDifficulty); | |
} | |
if (Current == null) | |
{ | |
throw new System.NotImplementedException(); | |
} | |
var record = this[Keyer(Current)]; | |
var percentOverdue = PercentOverdue(record, choseCorrectly); | |
var difficulty = | |
Mathf.Clamp01(record.Difficulty + percentOverdue * (1f / 17f) * (8f - 9f * impliedDifficulty)); | |
var difficultyWeighting = 3f - 1.7f * difficulty; | |
var daysBetweenReviews = 1f / (difficultyWeighting * difficultyWeighting); | |
if (choseCorrectly) | |
{ | |
daysBetweenReviews = 1 + (difficultyWeighting - 1f) * percentOverdue; | |
} | |
// Save record | |
record.DateLateReviewed = DateTime.Now.Ticks; | |
record.DaysBetweenReviews = daysBetweenReviews; | |
record.Difficulty = difficulty; | |
this[record.Key] = record; | |
} | |
private float PercentOverdue(RepetitionAlgorithmRecord record) | |
{ | |
return PercentOverdue(record, record.LastChoseCorrectly); | |
} | |
private float PercentOverdue(RepetitionAlgorithmRecord record, bool choseCorrectly) | |
{ | |
var percentOverdue = 1.0f; | |
if (choseCorrectly) | |
{ | |
var totalDays = (float) (DateTime.Now - new DateTime(record.DateLateReviewed)).TotalDays; | |
percentOverdue = Mathf.Min(2.0f, totalDays / (float) m_TimeSinceLastSession.TotalDays); | |
} | |
return percentOverdue; | |
} | |
public bool MoveNext() | |
{ | |
if (!m_Answered) | |
{ | |
throw new UnityException("m_Answers == false"); | |
} | |
m_Answered = false; | |
} | |
public void Reset() | |
{ | |
throw new System.NotImplementedException(); | |
} | |
public T Current { get; private set; } | |
object IEnumerator.Current | |
{ | |
get { return Current; } | |
} | |
public void Dispose() | |
{ | |
throw new System.NotImplementedException(); | |
} | |
} | |
[Serializable] | |
public class RepetitionAlgorithmRecord | |
{ | |
public long DateLateReviewed; | |
public float Difficulty; | |
public float DaysBetweenReviews; | |
public bool LastChoseCorrectly; | |
public string Key; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment