shithub: sm2

ref: a35484265f9fb32d9faa2064ad24d8dec99ba919
dir: /bin/sr3/

View raw version
#!/bin/awk -f
# tweaked version of supermemo 2 algorithm
# usage: sr3 deck > newdeck
# deck contains only card metadata.
# new cards are initialized with the values: 2.5 0 0 0 filepath.
# the script evaluates due cards, shuffles them, and shows them until all
# responses are graded >= 4, then writes a new deck db to stdout.
# card format is up to the user.
# tweaks:
# - new due date takes into account missed days
function setef(n, q){
	ef = c[n,"ef"] + (0.1 - (5 - q) * (0.08 + (5 - q) * 0.02))
	if(ef < 1.3)
		ef = 1.3
	else if(ef > 2.5)
		ef = 2.5
	c[n,"ef"] = ef
}
function setdue(n,    t, dt, day){
	dt = time - c[n,"due"]
	day = 60 * 60 * 24
	if(c[n,"nrep"] == 1)
		dt = 1 * day
	else if(c[n,"nrep"] == 2)
		dt = 6 * day - dt
	else
		dt = int((c[n,"due"] - c[n,"mtime"] - dt) / day * ef + 0.5) * day
	if(dt < 0)
		dt = 1 * day
	t = time + dt
	c[n,"mtime"] = time
	c[n,"due"] = t
}
function swap(X, a, b,    t){
	t = X[a]
	X[a] = X[b]
	X[b] = t
}
function qsort(X, l, r,    i, e){
	if(l >= r)
		return
	swap(X, l, l + int((r - l + 1) * rand()))
	e = l
	for(i=l+1; i<=r; i++)
		if(X[i] < X[l])
			swap(X, ++e, i)
	swap(X, l, e)
	qsort(X, l, e-1)
	qsort(X, e+1, r)
}
function shuffle(    r, nr){
	for(i in dues){
		nr++
		do
			r[nr] = rand()
		while(r[r[nr]] != 0)
		r[r[nr]] = dues[i]
	}
	delete dues
	qsort(r, 1, nr)
	for(i=1; i<=nr; i++)
		dues[i] = r[r[i]]
}
BEGIN{
	srand()
	"date -n" | getline time
}
NF != 5{
	exit (exits = "invalid db record " NR)
}
{
	c[NR,"ef"] = $1
	c[NR,"nrep"] = $2
	c[NR,"mtime"] = $3
	c[NR,"due"] = $4
	c[NR,"path"] = $5
	if(time >= $4)
		dues[++dc] = NR
}
END{
	if(exits != ""){
		print exits
		exit exits
	}
	while(length(dues) > 0){
		shuffle()
		for(i in dues){
			n = dues[i]
			#system("proof -m 1 " c[n,"path"])
			system("page " c[n,"path"])
			do
				getline q < "-"
			while(q !~ /^[0-9]$/ || q > 5)
			setef(n, int(q))
			if(q >= 4){
				delete dues[i]
				c[n,"nrep"]++
				setdue(n)
			}else if(q < 3)
				c[n,"nrep"] = 0
		}
	}
	for(i=1; i<=NR; i++)
		print c[i,"ef"], c[i,"nrep"], c[i,"mtime"], c[i,"due"], c[i,"path"]
}