--[[ a prompt consists of prompt text (with an answer-insertion point), a correct answer, the review timestamp, the review delay, and counts of successful and failde reviews timestamps are seconds from the Unix epoch review delay is in seconds ]] local Prompt = {} Prompt.__index = Prompt --[[ the answer-insertion point is indicated with a "%A" in the prompt text ]] function Prompt:new(pt, ca, rts, rd, sc, fc) local o = {} setmetatable(o, self) o.text = pt o.ans = ca o.time = tonumber(rts) o.delay = tonumber(rd) n.succ = sc n.fail = fc return o end function Prompt:__tostring() return string.format("\"%s\" (\"%s\") %d+%d %d/%d", self.text, self.ans, self.time, self.delay, self.succ, self.fail) end --[[ derive the `PromptText` used to create this `Prompt` ]] function Prompt:spt() return self.text:gsub("%%A", "{" .. self.ans .. "}") end --[[ extracts `Prompt`s from a record-based deck returns a table of tables of `Prompt`s ]] function Prompt:fromrecs(recs) local ret = {} for i, rec in ipairs(recs) do -- only bother with records with `PromptText` if rec.PromptText then ret[i] = {} local opt = rec.PromptText[1] local m, n = opt:find "%{[^%}]+%}" local ctr = 1 while m do local mpt = opt:sub(1, m - 1) .. "%A" .. opt:sub(n + 1) table.insert(ret[i], Prompt:new( mpt, opt:sub(m + 1, n - 1), (rec.LastReview or {})[ctr], (rec.LastDelay or {})[ctr], (rec.Successes or {})[ctr], (rec.Failures or {})[ctr] )) m, n = opt:find("%{[^%}]+%}", n) ctr = ctr + 1 end end end return ret end --[[ serialises an ordered table of `Prompt`s derived from the same `PromptText` to a record returns (on success) a table mapping labels to value-lists returns (on failure) nil ]] function Prompt:torec(prompts) local fspt = prompts[1]:spt() local ret = { PromptText = { fspt }, LastReview = {}, LastDelay = {} } for i, pr in ipairs(prompts) do if pr:spt() ~= fspt then -- not from the same `PromptText` return nil end ret.LastReview[i] = pr.time ret.LastDelay[i] = pr.delay ret.Successes[i] = pr.succ ret.Failures[i] = pr.fail end return ret end return Prompt