diff --git a/res/stats.json b/res/stats.json index 9c1d825..005fcf1 100644 --- a/res/stats.json +++ b/res/stats.json @@ -47,5 +47,4 @@ "puzzle1": false, "puzzle2": false } -} - +} \ No newline at end of file diff --git a/src/lib/aoc.lua b/src/lib/aoc.lua index 80eb68b..73d8028 100644 --- a/src/lib/aoc.lua +++ b/src/lib/aoc.lua @@ -128,6 +128,7 @@ local function main() dayStats.puzzle2 ) day:show() + stats = loadStats("aoc/res/stats.json") end end end diff --git a/src/lib/days.lua b/src/lib/days.lua index 06dd9b6..f102b19 100644 --- a/src/lib/days.lua +++ b/src/lib/days.lua @@ -1,3 +1,4 @@ +local json = require("json") local utils = require("utils") local days = {} @@ -7,6 +8,7 @@ local CHOICES = { create = "Create files", example = "Run examples", real = "Run with real input", + star = "Mark solved", main = "Back to main menu" } @@ -150,6 +152,49 @@ function Day:choosePuzzle() return c end +function Day:menuStars() + local solvedTxt = function (b) + if b then + return "solved" + end + return "unsolved" + end + local c0 = 1 + while true do + self:printTitle() + local choices = { + puzzle1 = "Mark puzzle 1 as " .. solvedTxt(not self.puzzle1), + puzzle2 = "Mark puzzle 2 as " .. solvedTxt(not self.puzzle2), + back = "Back" + } + local c = utils.promptChoices({choices.puzzle1, choices.puzzle2, choices.back}, c0) + if c == choices.back then + return + end + if c == choices.puzzle1 then + self.puzzle1 = not self.puzzle1 + self:saveStats() + c0 = 1 + elseif c == choices.puzzle2 then + self.puzzle2 = not self.puzzle2 + self:saveStats() + c0 = 2 + end + end +end + +function Day:saveStats() + local path = RES_PATH .. "/stats.json" + local content = utils.readFile(path) or "{}" + local data = json.loads(content) or {} + data[("day%02d"):format(self.day)] = { + puzzle1=self.puzzle1, + puzzle2=self.puzzle2, + } + content = json.dumps(data, 4, true) + utils.writeFile(path, content, true) +end + function Day:printTitle() term.clear() term.setCursorPos(1, 1) @@ -163,22 +208,25 @@ function Day:show() while true do self:printTitle() if fs.exists(self:srcDir()) then - local c = utils.promptChoices({CHOICES.example, CHOICES.real, CHOICES.main}) + local c = utils.promptChoices({CHOICES.example, CHOICES.real, CHOICES.star, CHOICES.main}) if c == CHOICES.main then return - end - local puzzle = self:choosePuzzle() - if puzzle ~= "Back" then - local puzzleI = ({ - ["Puzzle 1"] = 1, - ["Puzzle 2"] = 2 - })[puzzle] - if c == CHOICES.example then - self:execExample(puzzleI) - elseif c == CHOICES.real then - self:execReal(puzzleI) + elseif c == CHOICES.star then + self:menuStars() + else + local puzzle = self:choosePuzzle() + if puzzle ~= "Back" then + local puzzleI = ({ + ["Puzzle 1"] = 1, + ["Puzzle 2"] = 2 + })[puzzle] + if c == CHOICES.example then + self:execExample(puzzleI) + elseif c == CHOICES.real then + self:execReal(puzzleI) + end + utils.waitForKey(keys.enter) end - utils.waitForKey(keys.enter) end else local c = utils.promptChoices({CHOICES.create, CHOICES.main}) diff --git a/src/lib/json.lua b/src/lib/json.lua index a1827ad..ad457bc 100644 --- a/src/lib/json.lua +++ b/src/lib/json.lua @@ -20,6 +20,13 @@ local function errFactory(prefix) end end +local function ifNil(test, ifNil, ifNotNil) + if test == nil then + return ifNil + end + return ifNotNil +end + local function parseObj(data) local printErr = errFactory("Error while parsing object") local obj = {} @@ -199,4 +206,86 @@ function json.loads(data) return res end +local function kind(obj) + if type(obj) ~= "table" then + return type(obj) + end + local i = 1 + for _ in pairs(obj) do + if obj[i] ~= nil then + i = i + 1 + else + return "table" + end + end + if i == 1 then + return "table" + end + return "array" +end + +local function escapeStr(str) + local in_char = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'} + local out_char = {'\\', '"', '/', 'b', 'f', 'n', 'r', 't'} + for i, c in ipairs(in_char) do + str = str:gsub(c, '\\' .. out_char[i]) + end + return str +end + +function json.dumps(data, indent, sortKeys, depth) + if data == json.null then + return "null" + end + + local t = kind(data) + if t == "string" then + return '"' .. escapeStr(data) .. '"' + elseif t == "number" or t == "boolean" then + return tostring(data) + end + + depth = depth or 0 + local spaces = "" + if indent ~= nil then + spaces = string.rep(" ", indent * depth) + end + local res = "" + + if t == "array" then + res = res .. "[" .. ifNil(indent, "", "\n") + for i, val in ipairs(data) do + if i > 1 then + res = res .. "," .. ifNil(indent, " ", "\n") + end + res = res .. spaces .. string.rep(" ", indent or 0) + res = res .. json.dumps(val, indent, sortKeys, depth + 1) + end + res = res .. ifNil(indent, "", "\n") .. spaces .. "]" + elseif t == "table" then + res = res .. "{" .. ifNil(indent, "", "\n") + local first = true + local keys = {} + for k, _ in pairs(data) do + table.insert(keys, k) + end + if sortKeys then + table.sort(keys) + end + for _, k in ipairs(keys) do + local v = data[k] + if not first then + res = res .. "," .. ifNil(indent, " ", "\n") + end + first = false + res = res .. spaces .. string.rep(" ", indent or 0) + res = res .. '"' .. escapeStr(k) .. '": ' + res = res .. json.dumps(v, indent, sortKeys, depth + 1) + end + res = res .. ifNil(indent, "", "\n") .. spaces .. "}" + end + + return res +end + return json \ No newline at end of file diff --git a/src/lib/utils.lua b/src/lib/utils.lua index ea363b1..d990232 100644 --- a/src/lib/utils.lua +++ b/src/lib/utils.lua @@ -1,7 +1,7 @@ local utils = {} -function utils.promptChoices(choices) - local c = 1 +function utils.promptChoices(choices, default) + local c = default or 1 local ox, oy = term.getCursorPos() while true do term.setCursorPos(ox, oy)