[Lua] IT技术熟练度生成器 | 根据活动记录生成md表格 | 自创 ...

打印 上一主题 下一主题

主题 856|帖子 856|积分 2568

IT技术熟练度 v1.0

为衡量个人能力水平自创的一套评分机制,根据时间、代码行数、基础理论三个变量生成。最近在学lua,正好练下基本功。效果可见 个人介绍 | 代码统计 - 小能日记 - 博客园 (cnblogs.com)
life.lua 记录自己每日的IT活动,main.lua 程序根据life.lua生成文件 output.md
具体规则


  • 某一条目为A对象实例(如Lua),初始化40分,范围 (0,100]

    • [0,20) 遗忘、[20,40) 生疏、[40,60) 了解、[60,80) 熟悉、[80,100] 熟练

  • 时间:每隔1天,进行如下模拟遗忘操作,从熟练到遗忘需要90天不敲代码

    • 小于等于80分的条目减1分
    • 小于等于100分的条目减2分

  • 代码行数:根据每天敲的代码有效行数(不含空行)对熟练度增减。

    • 动态计算每个条目平均有效行AVG(4天敲800行得200),不足4天默认按500行计算
    • 当天有效行数处于 [AVG * 1.25,∞] ,加4分
    • 当天有效行数处于 [AVG * 0.75,AVG * 1.25] ,加3分
    • 当天有效行数处于 [AVG * 0.25,AVG * 0.75) ,加2分
    • 当天有效行数处于 [AVG * 0.10,AVG * 0.25) ,加1分
    • 当天有效行数处于 [AVG * 0.00,AVG * 0.10) ,加0分
    • 从50分到80分需要连续敲15天,从80分到100分需要连续敲20天。
    • 越熟练代码越精简,行数逐渐变少,这是量变到质变的过程,故 AVG * 0.75

  • 基础理论:当天涉及基础理论(如网络、算法、设计模式、架构技巧等)

    • 集合元素个数 * 2,如["算法"]:{"马尔科夫链","迪杰斯特拉"},共2个元素,加4分

  • 状态:状态根据当天敲的所有行数比较 AVG = (一生敲的总行数) // (总天数),不足4天默认按500行计算

    • 加班狂魔:[1.25 * AVG,∞]、正常上班:[AVG * 0.50,AVG * 1.25]、天天摸鱼:[AVG * 10,AVG * 0.50 ]
    • 其他与没敲代码的日子均统计到"摆烂"中。学了理论不敲等于没学

IT活动记录 life.lua
  1. -- 文件 life.lua 格式如下
  2. life = {{
  3.     ["date"] = "2023年8月16日", -- 日期
  4.     ["lua"] = {484, 52}, -- 敲的有效行/注释行
  5.     ["c#"] = {123, 4}, -- 敲的有效行/注释行
  6.     ["算法"] = {"马尔科夫链", "迪杰斯特拉", "位图法"}, -- 涉及的概念
  7.     ["设计模式"] = {"单例模式"} -- 涉及的概念
  8. }, {
  9.     ["date"] = "2023年8月15日",
  10.     ["lua"] = {477, 18}
  11. }, {
  12.     ["date"] = "2023年8月14日",
  13.     ["lua"] = {519, 29}
  14. }, {
  15.     ["date"] = "2023年8月13日",
  16.     ["lua"] = {628, 71}
  17. }}
复制代码
输出熟练度 output.md
  1. (如果有前置head.md则会在这拼接)
  2. Time : 2023/8/13 ~ 2023/8/16
  3. |技术|学习天数|熟练度 (0~100)|程度|评级|
  4. |------|----|----|----|----|
  5. |lua|4|50|了解|⭐⭐⭐|
  6. |算法|1|46|了解|⭐⭐⭐|
  7. |c#|1|42|了解|⭐⭐⭐|
  8. |设计模式|1|42|了解|⭐⭐⭐|
  9. |我的一生|总共行数|天数|平均行数
  10. |------|----|----|----|
  11. |lua|2278|4|569|
  12. |c#|127|1|127|
  13. |我的状态|天数|
  14. |------|----|
  15. |加班狂魔|1|
  16. |正常上班|3|
  17. |天天摸鱼|0|
  18. |开摆去咯|0|
复制代码
部分实现

初始化
  1. local scores = {} -- 条目的熟练度,键=条目,值=分数
  2. local levelDays = {0, 0, 0, 0} -- 迄今为止效率,键=状态{摆烂,摸鱼,正常,高强度},值=天数
  3. local studyDays = {} -- 每个条目各自学习了几天
  4. local linesCount = {} -- 每个条目各自敲了几开始行,键=条目,值=行数
  5. local startDay = nil -- 从什么时候开始
  6. local endDay = nil -- 从什么时候结束
  7. local tmpDay = nil -- 当前记录前一个记录的日子
复制代码
读取记录

主要用了一个有状态的迭代器,配合泛型for循环使用。没有用到不可变状态和控制变量,但是个人习惯所以留着形参s、c。
  1. -- 记录迭代器,逐条返回记录
  2. function getRecords()
  3.     local i = #life
  4.     return function(s, c)
  5.         if i > 0 then
  6.             i = i - 1
  7.             return life[i + 1]
  8.         end
  9.         return nil
  10.     end, nil, nil
  11. end
复制代码
时间计算

用模式匹配捕获年月日,并保存最早的时间和最晚的时间。另外计算两个时间之间的间隔sep,根据间隔大小更新scores。
  1. -- 根据每条记录更新 startDay 跟 endDay
  2. -- 计算前一条记录与后一条记录的间隔天数,统计至levelDays并进行scores每日遗忘操作
  3. function updateTime(date)
  4.     local y, m, d = string.match(date, "(%d+)年(%d+)月(%d+)")
  5.     if not startDay then
  6.         startDay = {
  7.             year = y,
  8.             month = m,
  9.             day = d
  10.         }
  11.     end
  12.     tmpDay = tmpDay or startDay
  13.     endDay = {
  14.         year = y,
  15.         month = m,
  16.         day = d
  17.     }
  18.     -- 计算前一条记录与后一条记录的间隔天数 sep
  19.     local sep = os.difftime(os.time(endDay), os.time(tmpDay)) // 3600 // 24
  20.     -- 间隔大于 1 天,将sep - 1的天数归入摆烂,并进行每日遗忘操作
  21.     if sep > 1 then
  22.         updateLevelDays(1, sep - 1)
  23.         dailyScores(sep)
  24.     else
  25.         dailyScores(1)
  26.     end
  27.     tmpDay = endDay
  28. end
复制代码
遗忘操作

根据规则对scores进行减少
  1. -- 每日遗忘function dailyScores(n)    for k, v in pairs(scores) do        if v  0 then            i = i - 1            return life[i + 1]        end        return nil    end, nil, nilend-- 根据每条记录更新 startDay 跟 endDay
  2. -- 计算前一条记录与后一条记录的间隔天数,统计至levelDays并进行scores每日遗忘操作
  3. function updateTime(date)
  4.     local y, m, d = string.match(date, "(%d+)年(%d+)月(%d+)")
  5.     if not startDay then
  6.         startDay = {
  7.             year = y,
  8.             month = m,
  9.             day = d
  10.         }
  11.     end
  12.     tmpDay = tmpDay or startDay
  13.     endDay = {
  14.         year = y,
  15.         month = m,
  16.         day = d
  17.     }
  18.     -- 计算前一条记录与后一条记录的间隔天数 sep
  19.     local sep = os.difftime(os.time(endDay), os.time(tmpDay)) // 3600 // 24
  20.     -- 间隔大于 1 天,将sep - 1的天数归入摆烂,并进行每日遗忘操作
  21.     if sep > 1 then
  22.         updateLevelDays(1, sep - 1)
  23.         dailyScores(sep)
  24.     else
  25.         dailyScores(1)
  26.     end
  27.     tmpDay = endDay
  28. end-- 更新 linesCountfunction updateLinesCount(item, count)    linesCount[item] = (linesCount[item] or 0) + countend-- 更新 studyDaysfunction updateStudyDays(item)    studyDays[item] = (studyDays[item] or 0) + 1end-- 每日遗忘function dailyScores(n)    for k, v in pairs(scores) do        if v = avg * 0.25 then        return 2    elseif count >= avg * 0.1 then        return 1    else        return 0    endend-- 更新 levelDays, level = 1~4function updateLevelDays(level, sep)    levelDays[level] = (levelDays[level] or 0) + (sep or 1)end-- 根据当天写的代码更新 levelDaysfunction updateLevelDaysByCountLines(countLines)    local totalLines = 0    local totalDays = 0    for _, v in pairs(linesCount) do        totalLines = v + totalLines    end    for _, v in pairs(studyDays) do        totalDays = v + totalDays    end    local avgLines = totalLines // totalDays    if totalDays < 4 then -- 总天数不足4天按500行算        avgLines = 500    end    if countLines > 1.25 * avgLines then        updateLevelDays(4)    elseif countLines > 0.5 * avgLines then        updateLevelDays(3)    elseif countLines > 0.1 * avgLines then        updateLevelDays(2)    else        updateLevelDays(1)    endend-- 根据条目键值对加分,并更新linesCountfunction updateScores(item, count, level)    scores[item] = scores[item] or 40    if level then        if level == 4 then            scores[item] = scores[item] + 4        elseif level == 3 then            scores[item] = scores[item] + 3        elseif level == 2 then            scores[item] = scores[item] + 2        elseif level == 1 then            scores[item] = scores[item] + 1        else            -- do nothing        end        scores[item] = scores[item] > 100 and 100 or scores[item]    else        scores[item] = scores[item] + count * 2        scores[item] = scores[item] > 100 and 100 or scores[item]    endend-- 根据每条记录更新 scores levelDays linesCountfunction update(record)    local countLines = 0 -- 当天写过的代码行数总和    for item, v in pairs(record) do        -- 判断是编程语言还是基础理论        if type(v[1]) == "number" then            local total = v[1] + (v[2] or 0)            countLines = countLines + total            updateLinesCount(item, total)            updateStudyDays(item)            local level = level(item, total)            updateScores(item, total, level)        elseif type(v[1]) == "string" then            updateScores(item, #v)            updateStudyDays(item)        else            error("条目格式有错", 2)        end    end    -- 更新 levelDays , 保存当天状态 {摆烂,摸鱼,正常,高强度}    updateLevelDaysByCountLines(countLines)end-- 主程序for r in getRecords() do    -- 更新 startDay 跟 endDay    updateTime(r["date"])    -- 删除"date"减少多余的判断    r["date"] = nil    -- 更新 scores levelDays linesCount    update(r)end-- 根据系统时间更新一次时间updateTime(os.date("%Y年%m月%d日"))-- 排个序 scores,linesCountscoresSort = {}for k, v in pairs(scores) do    scoresSort[#scoresSort + 1] = {k, v}endlinesCountSort = {}for k, v in pairs(linesCount) do    linesCountSort[#linesCountSort + 1] = {k, v}endtable.sort(scoresSort, function(a, b)    return a[2] > b[2] -- 熟练度分数对比end)table.sort(linesCount, function(a, b)    return a[2] > b[2] -- 总行数对比end)-- 输出结果io.output(io.open("output.md", "w"))-- 做前置拼接,一般是个人介绍的内容pcall(function()    f = io.open("head.md", "r")    if f then        io.write(f:read("a"))        io.write "\n"        f:close()    endend)-- 输出各个表格io.write("# IT技术熟练度\n")io.write(string.format("**Time : %d/%d/%d ~ %d/%d/%d**\n", startDay.year, startDay.month, startDay.day, endDay.year,    endDay.month, endDay.day))io.write("|技术|学习天数|熟练度 (0~100)|程度|评级|\n")io.write("|------|----|----|----|----|\n")local cd = {"遗忘", "生疏", "了解", "熟悉", "熟练"}for i, v in ipairs(scoresSort) do    local stars = ""    for i = 1, v[2] // 20 + 1, 1 do        stars = stars .. "⭐"    end    io.write(string.format("\z    |%s|%s|%d|%s|%s|\n\z    \z", v[1], studyDays[v[1]], v[2], cd[v[2] // 20 + 1], stars))endio.write "\n"io.write("# 这一生写过的代码\n")io.write("|我的一生|总共行数|天数|平均行数\n")io.write("|------|----|----|----|\n")for i, v in ipairs(linesCountSort) do    io.write(string.format("|%s|%d|%d|%d|\n", v[1], v[2], studyDays[v[1]], v[2] // studyDays[v[1]]))endio.write "\n"io.write("# 这一生所处的状态\n")io.write("|我的状态|天数|\n")io.write("|------|----|\n")io.write(string.format("|加班狂魔|%d|\n", levelDays[4]))io.write(string.format("|正常上班|%d|\n", levelDays[3]))io.write(string.format("|天天摸鱼|%d|\n", levelDays[2]))io.write(string.format("|开摆去咯|%d|\n", levelDays[1]))io.write("\n")io.write("# 这一生活动的统计\n")io.write("使用插件 `VS Code Counter` 进行每日统计,仅统计有效行,不含空行\n")io.write("```lua\n")f = io.open("life.lua")io.write(f:read("a"))f:close()io.write("```\n")io.output():close()
复制代码
示例效果

Time : 2023/8/13 ~ 2023/8/16
技术学习天数熟练度 (0~100)程度评级lua450了解⭐⭐⭐算法146了解⭐⭐⭐c#142了解⭐⭐⭐设计模式142了解⭐⭐⭐我的一生总共行数天数平均行数lua22784569c#1271127我的状态天数加班狂魔1正常上班3天天摸鱼0开摆去咯0如何获取行数



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

曹旭辉

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表