diff --git a/README.md b/README.md new file mode 100644 index 0000000..b8a2aad --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +# Advent of Code + +This repo contains my attempt at this year's Advent of Code (2025) + +I will solve this AoC using Lua in the context of the ComputerCraft Minecraft mod.\ +This project can also be run using the amazing [CraftOS-PC emulator](https://github.com/MCJack123/craftos2) + +## Progress + + +#### Stars: 0/24 + +|Mon|Tue|Wed|Thu|Fri|Sat|Sun| +|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +|1
|2
|3
|4
|5
|6
|7
| +|8
|9
|10
|11
|12
||| + diff --git a/src/calendar.lua b/src/calendar.lua new file mode 100644 index 0000000..ab5f7f5 --- /dev/null +++ b/src/calendar.lua @@ -0,0 +1,125 @@ +package.path = "/aoc/src/lib/?.lua;" .. package.path +require("aoc") +local json = require("json") +local utils = require("utils") +local buffer = require("buffer") +local stats = json.loads(utils.readFile(RES_PATH .. "/stats.json")) or {} +local readmePath = ROOT_PATH .. "/README.md" +local outBuf = buffer.Buffer.new() + +local function insertInReadme() + local body = utils.readFile(readmePath) or "" + local tagStart = "" + local tagEnd = "" + body = body:gsub( + tagStart:gsub("%-", "%%-") .. ".-" .. tagEnd:gsub("%-", "%%-"), + tagStart .. "\n" .. outBuf:tostring() .. tagEnd + ) + utils.writeFile(readmePath, body, true) +end + +local totalStars = 0 +for _, s in pairs(stats) do + if s.puzzle1 then totalStars = totalStars + 1 end + if s.puzzle2 then totalStars = totalStars + 1 end +end + +local startTS = 1764543600 + +local startDate = os.date("*t", startTS) +local firstWeekday = (startDate.wday + 5) % 7 +local padding = {x=3, y=1} + +local dayNames = { + "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" +} + +local day = -firstWeekday + 1 + +local rowSep = "+" +local padRow = "|" +for _ = 1, 7 do + rowSep = rowSep .. string.rep("-", padding.x * 2 + 3) .. "+" + padRow = padRow .. string.rep(" ", padding.x * 2 + 3) .. "|" +end + +local function printRow(cells, cellWidth, padding) + local xPad = string.rep(" ", padding.x) + local height = 0 + for _, cell in ipairs(cells) do + height = math.max(height, type(cell) == "string" and 1 or #cell) + end + + for i = -padding.y + 1, height + padding.y do + write("|") + for _, cell in ipairs(cells) do + local text = cell[i] or "" + if type(cell) == "string" and i == 1 then + text = cell + end + local pad = cellWidth - #text + local lPad = math.ceil(pad / 2) + local rPad = pad - lPad + write(xPad .. string.rep(" ", lPad)) + if i > 1 and i <= height then + term.setTextColor(colors.orange) + end + write(text) + term.setTextColor(colors.white) + write(string.rep(" ", rPad) .. xPad .. "|") + end + print() + end + print(rowSep) +end + +term.clear() +term.setCursorPos(1, 1) +term.setTextColor(colors.white) + +print(("Stars: %d/24"):format(totalStars, 24)) +outBuf:print(("#### Stars: %d/24\n"):format(totalStars, 24)) + +print(rowSep) +printRow(dayNames, 3, padding) + +outBuf:print("|" .. table.concat(dayNames, "|") .. "|") +for _ = 1, 7 do + outBuf:write("|:-:") +end +outBuf:print("|") + +while day < 12 do + local row = {} + local outRow = {} + for _ = 1, 7 do + if day < 1 or day > 12 then + table.insert(row, "") + table.insert(outRow, "") + else + local dayStats = stats[("day%02d"):format(day)] + local stars = 0 + if dayStats.puzzle1 then stars = stars + 1 end + if dayStats.puzzle2 then stars = stars + 1 end + local cell = { + tostring(day), + string.rep("\x04", stars, " ") + } + table.insert(row, cell) + cell = { + tostring(day), + string.rep(":star:", stars, "") + } + table.insert(outRow, table.concat(cell, "
")) + end + day = day + 1 + end + printRow(row, 3, padding) + outBuf:print("|" .. table.concat(outRow, "|") .. "|") +end + +insertInReadme() + +---@diagnostic disable-next-line: undefined-field +term.screenshot() +os.sleep(2) \ No newline at end of file diff --git a/src/lib/aoc.lua b/src/lib/aoc.lua index 713029e..5c1b7d5 100644 --- a/src/lib/aoc.lua +++ b/src/lib/aoc.lua @@ -1,5 +1,6 @@ -SRC_PATH = "/aoc/src" -RES_PATH = "/aoc/res" +ROOT_PATH = "/aoc" +SRC_PATH = ROOT_PATH .. "/src" +RES_PATH = ROOT_PATH .. "/res" CACHE_PATH = "/.cache/aoc" package.path = SRC_PATH .. "/lib/?.lua;" .. package.path @@ -12,8 +13,9 @@ local dates = require("dates") local days = require("days") local progress = require "progress" local today = os.date("*t") +local aoc = {} -local function loadStats(path) +function aoc.loadStats(path) path = shell.resolve(path) if not fs.exists(path) then printError("Stats file not found (" .. path .. ")") @@ -29,7 +31,7 @@ local function loadStats(path) return data end -local function printDateInfo() +function aoc.printDateInfo() if dates.isBefore(START_DATE, today) then print("AoC 2025 has not started yet") return @@ -42,7 +44,7 @@ local function printDateInfo() print("Day " .. day .. "/" .. END_DATE.day) end -local function printStats(stats, selected) +function aoc.printStats(stats, selected) local keys = {} for k in pairs(stats) do table.insert(keys, k) @@ -100,7 +102,7 @@ local function printStats(stats, selected) print("Press END to quit") end -local function printBanner() +function aoc.printBanner() term.setTextColor(colors.green) print("+--------------------------------------+") print("| Welcome to the Advent of Code 2025 |") @@ -108,8 +110,8 @@ local function printBanner() term.setTextColor(colors.white) end -local function main() - local stats = loadStats("aoc/res/stats.json") or {} +function aoc.main() + local stats = aoc.loadStats("aoc/res/stats.json") or {} local selectedDay = math.max(1, math.min(END_DATE.day, today.day)) if not dates.isInDateRange(START_DATE, today, END_DATE) then selectedDay = 1 @@ -118,9 +120,9 @@ local function main() while true do term.clear() term.setCursorPos(1, 1) - printBanner() - printDateInfo() - printStats(stats, selectedDay) + aoc.printBanner() + aoc.printDateInfo() + aoc.printStats(stats, selectedDay) local event, key, is_held = os.pullEvent("key") if key == keys.up then @@ -137,9 +139,9 @@ local function main() dayStats.puzzle2 ) day:show() - stats = loadStats("aoc/res/stats.json") or {} + stats = aoc.loadStats("aoc/res/stats.json") or {} end end end -main() \ No newline at end of file +return aoc diff --git a/src/lib/buffer.lua b/src/lib/buffer.lua new file mode 100644 index 0000000..b0409ed --- /dev/null +++ b/src/lib/buffer.lua @@ -0,0 +1,35 @@ +local buffer = {} + +---@class Buffer +local Buffer = {_buf=""} +Buffer.__index = Buffer + +---Creates a new buffer +---@param str string? +---@return Buffer +function Buffer.new(str) + local buf = {} + buf._buf = str or "" + setmetatable(buf, Buffer) + return buf +end + +function Buffer:tostring() + return self._buf +end + +function Buffer:clear() + self._buf = "" +end + +function Buffer:write(text) + self._buf = self._buf .. (text or "") +end + +function Buffer:print(text) + self:write((text or "") .. "\n") +end + +buffer.Buffer = Buffer + +return buffer \ No newline at end of file