#!/usr/bin/env lua local function identity(x) return x end local function cup(x) if type(x) == "table" then return table.unpack(x) else return x end end local function ztable(x) -- Sergei Winitzki's 2003 approximation of erf local a = 0.140012 local function erf(x) return math.abs(x) / (x == 0 and 1 or x) * math.sqrt(1 - math.exp(-x^2 * (4 / math.pi + a * x^2) / (1 + a * x^2))) end local rev = erf(x / math.sqrt(2)) return (rev + 1) / 2 end local TYPES = { ln = { -- how to generate the problem (returns problem-object) gen = function() return math.exp(6.9 * math.random()) end, -- how to present the problem (for string.format) disp = "ln(%.2f)", -- produce correct answer-object from problem-object func = math.log, -- check quality of guess g for problem p score = function(p, g) return -(math.log(math.abs(math.log(p) - g), 10) + 1.5)^3 end, }, sin = { gen = function() return 1.5 * math.random() end, disp = "sin(%.3f)", func = math.sin, score = function(p, g) return -(math.log(math.abs(math.sin(p) - g), 10) + 1.5)^3 end }, normalcdf = { gen = function() return 5 * math.random() - 2.5 end, disp = "z = %.2f, percentile", func = ztable, score = function(p, g) return -(math.log(math.abs(ztable(p) - g), 10) + 1.5)^3 end }, } local TYPE = TYPES[arg[1]] if not TYPE then if arg[1] then io.write(string.format("unknown problem type %s\n", arg[1])) os.exit(false) else TYPE = TYPES.normalcdf end end local TIME = 30 local ts = 0 local st = os.time() local pc = 0 while os.time() - st < TIME do local rp = TYPE.gen() local ans = TYPE.func(rp) io.write(string.format(TYPE.disp .. " ? ", cup(rp))) io.flush() local inp = tonumber(io.read("l")) or 0 local sc = TYPE.score(rp, inp) if sc > 0 then io.write(string.format("✓ correct (%.3f)\n", ans)) else io.write(string.format("wrong (%.3f)\n", ans)) end ts = ts + sc pc = pc + 1 end io.write(string.format("score %.1f from %d problems in %.1f seconds\n", ts, pc, TIME))