Software developer and artist.

  • 4 Posts
  • 94 Comments
Joined 1 year ago
cake
Cake day: June 5th, 2023

help-circle




  • Nice and easy.

    Lua
    -- SPDX-FileCopyrightText: 2023 Jummit
    --
    -- SPDX-License-Identifier: GPL-3.0-or-later
    
    local function nums(str)
    	local res = {}
    	for num in str:gmatch("%d+") do
    		res[num] = true
    	end
    	return res
    end
    
    local cards = {}
    local points = 0
    for line in io.open("4.input"):lines() do
    	local winning, have = line:match("Card%s*%d+: (.*) | (.*)")
    	winning = nums(winning)
    	have = nums(have)
    	local first = true
    	local score = 0
    	local matching = 0
    	for num in pairs(have) do
    		if winning[num] then
    			matching = matching + 1
    			if first then
    				first = false
    				score = score + 1
    			else
    				score = score * 2
    			end
    		end
    	end
    	points = points + score
    	table.insert(cards, {have=have, wins=matching, count=1})
    end
    print(points)
    
    local cardSum = 0
    for i, card in ipairs(cards) do
    	cardSum = cardSum + card.count
    	for n = i + 1, i + card.wins do
    		cards[n].count = cards[n].count + card.count
    	end
    end
    print(cardSum)
    

  • Input parsing AGAIN?

    Lua
    -- SPDX-FileCopyrightText: 2023 Jummit
    --
    -- SPDX-License-Identifier: GPL-3.0-or-later
    
    local lines = {}
    for line in io.open("3.input"):lines() do
    	table.insert(lines, "."..line..".")
    end
    local width = #lines[1]
    local height = #lines
    local function at(x, y, w)
    	if y < 1 or y > height then return nil end
    	return lines[y]:sub(x, x + w - 1)
    end
    local sum = 0
    local gears = {}
    for y, line in ipairs(lines) do
    	local start = 1
    	local outLine = line
    	while true do
    		local newStart, numEnd = line:find("%d+", start)
    		if not newStart then break end
    		local symbol = false
    		local num = tonumber(line:sub(newStart, numEnd))
    		for y = y - 1, y + 1 do
    			local surrounding = at(newStart - 1, y, numEnd - newStart + 3)
    			if surrounding then
    				if surrounding and surrounding:match("[^.%d]") then
    					symbol = true
    				end
    				for i = 1, #surrounding do
    					local gear = surrounding:sub(i, i) == "*"
    					if gear then
    						if not gears[y] then
    							gears[y] = {}
    						end
    						local x = i + newStart - 2
    						if not gears[y][x] then
    							gears[y][i + newStart - 2] = {}
    						end
    						table.insert(gears[y][x], num)
    					end
    				end
    			end
    		end
    		if symbol then
    			sum = sum + num
    		end
    		start = numEnd + 1
    	end
    end
    print(sum)
    local ratio = 0
    for _, line in pairs(gears) do
    	for _, gears in pairs(line) do
    		if #gears == 2 then
    			ratio = ratio + gears[1] * gears[2]
    		end
    	end
    end
    print(ratio)
    
    Hare (Part one only)
    // SPDX-FileCopyrightText: 2023 Jummit
    //
    // SPDX-License-Identifier: GPL-3.0-or-later
    
    use strings;
    use regex;
    use fmt;
    use os;
    use bufio;
    use io;
    use strconv;
    use types;
    
    fn star_in(lines: []str, x: uint, y: uint, w: uint) bool = {
    	let start = y;
    	if (start > 0) start -= 1;
    	let end = y + 1;
    	if (end >= len(lines)) end -= 1;
    	const re = regex::compile(`[^.0-9]`)!;
    	for (let h = start; h <= end; h += 1) {
    		fmt::println(strings::sub(lines[h], x, x + w))!;
    		if (regex::test(&re, strings::sub(lines[h], x, x + w))) {
    			fmt::println("")!;
    			return true;
    		};
    	};
    	fmt::println("")!;
    	return false;
    };
    
    export fn main() void = {
    	const file = os::open("3.input")!;
    	defer io::close(file)!;
    	const buf = bufio::newscanner(file, types::SIZE_MAX);
    	let lines: []str = [];
    	defer strings::freeall(lines);
    	for (true) {
    		match (bufio::scan_line(&buf)!) {
    		case io::EOF =>
    			break;
    		case let line: const str =>
    			append(lines, strings::dup(line));
    		};
    	};
    	const height = len(lines);
    	const width = len(lines[0]);
    	let sum: uint = 0;
    	let gears: [](uint, uint) = [];
    	const num_re = regex::compile(`[0-9]+`)!;
    	for (let y = 0u; y < len(lines); y += 1) {
    		let nums = regex::findall(&num_re, lines[y]);
    		defer regex::result_freeall(nums);
    		for (let i = 0z; i < len(nums); i += 1) {
    			for (let j = 0z; j < len(nums[i]); j += 1) {
    				const find = nums[i][j];
    				const num = strconv::stou(find.content)!;
    				let start = find.start: uint;
    				let w = len(find.content): uint + 2;
    				if (start > 0) {
    					start -= 1;
    				} else {
    					w -= 1;
    				};
    				if (star_in(lines, start, y, w)) {
    					sum += num;
    				};
    			};
    		};
    	};
    	fmt::printfln("{}", sum)!;
    };
    

  • Mostly an input parsing problem this time, but it was fun to use Hares tokenizer functions:

    lua
    -- SPDX-FileCopyrightText: 2023 Jummit
    --
    -- SPDX-License-Identifier: GPL-3.0-or-later
    
    local colors = {"blue", "red", "green"}
    local available = {red = 12, blue = 14, green = 13}
    local possible = 0
    local id = 0
    local min = 0
    
    for game in io.open("2.input"):lines() do
      id = id + 1
      game = game:gsub("Game %d+: ", "").."; "
      local max = {red = 0, blue = 0, green = 0}
      for show in game:gmatch(".-; ") do
        for _, color in ipairs(colors) do
          local num = tonumber(show:match("(%d+) "..color))
          if num then
            max[color] = math.max(max[color], num)
          end
        end
      end
      min = min + max.red * max.blue * max.green
      local thisPossible = true
      for _, color in ipairs(colors) do
        if max[color] > available[color] then
          thisPossible = false
          break
        end
      end
      if thisPossible then
        possible = possible + id
      end
    end
    
    print(possible)
    print(min)
    
    hare
    // SPDX-FileCopyrightText: 2023 Jummit
    //
    // SPDX-License-Identifier: GPL-3.0-or-later
    
    use strconv;
    use types;
    use strings;
    use io;
    use bufio;
    use os;
    use fmt;
    
    const available: []uint = [12, 13, 14];
    
    fn color_id(color: str) const uint = {
    	switch (color) {
    	case "red" => return 0;
    	case "green" => return 1;
    	case "blue" => return 2;
    	case => abort();
    	};
    };
    
    export fn main() void = {
    	const file = os::open("2.input")!;
    	defer io::close(file)!;
    	const scan = bufio::newscanner(file, types::SIZE_MAX);
    	let possible: uint = 0;
    	let min: uint = 0;
    
    	for (let id = 1u; true; id += 1) {
    		const line = match(bufio::scan_line(&scan)!) {
    		case io::EOF =>
    			break;
    		case let line: const str =>
    			yield strings::sub(
    					line,
    					strings::index(line, ": ") as size + 2,
    					strings::end);
    		};
    		let max: []uint = [0, 0, 0];
    		let tok = strings::rtokenize(line, "; ");
    		for (true) {
    			const show = match(strings::next_token(&tok)) {
    			case void =>
    				break;
    			case let show: str =>
    				yield show;
    			};
    			const pairs = strings::tokenize(show, ", ");
    			for (true) {
    				const pair: (str, str) = match(strings::next_token(&pairs)) {
    				case void =>
    					break;
    				case let pair: str =>
    					let tok = strings::tokenize(pair, " ");
    					yield (
    						strings::next_token(&tok) as str,
    						strings::next_token(&tok) as str
    					);
    				};
    				let color = color_id(pair.1);
    				let amount = strconv::stou(pair.0)!;
    				if (amount > max[color]) max[color] = amount;
    			};
    		};
    		if (max[0] <= available[0] && max[1] <= available[1] && max[2] <= available[2]) {
    			fmt::printfln("{}", id)!;
    			possible += id;
    		};
    		min += max[0] * max[1] * max[2];
    	};
    	
    	fmt::printfln("{}", possible)!;
    	fmt::printfln("{}", min)!;
    };
    

  • Trickier than expected! I ran into an issue with Lua patterns, so I had to revert to a more verbose solution, which I then used in Hare as well.

    Lua:

    lua
    -- SPDX-FileCopyrightText: 2023 Jummit
    --
    -- SPDX-License-Identifier: GPL-3.0-or-later
    
    local sum = 0
    for line in io.open("1.input"):lines() do
      local a, b = line:match("^.-(%d).*(%d).-$")
      if not a then
        a = line:match("%d+")
        b = a
      end
      if a and b then
        sum = sum + tonumber(a..b)
      end
    end
    print(sum)
    
    local names = {
      ["one"] = 1,
      ["two"] = 2,
      ["three"] = 3,
      ["four"] = 4,
      ["five"] = 5,
      ["six"] = 6,
      ["seven"] = 7,
      ["eight"] = 8,
      ["nine"] = 9,
      ["1"] = 1,
      ["2"] = 2,
      ["3"] = 3,
      ["4"] = 4,
      ["5"] = 5,
      ["6"] = 6,
      ["7"] = 7,
      ["8"] = 8,
      ["9"] = 9,
    }
    sum = 0
    for line in io.open("1.input"):lines() do
      local firstPos = math.huge
      local first
      for name, num in pairs(names) do
        local left = line:find(name)
        if left and left < firstPos then
          firstPos = left
          first = num
        end
      end
      local last
      for i = #line, 1, -1 do
        for name, num in pairs(names) do
          local right = line:find(name, i)
          if right then
            last = num
            goto found
          end
        end
      end
      ::found::
      sum = sum + tonumber(first * 10 + last)
    end
    print(sum)
    
    

    Hare:

    hare
    // SPDX-FileCopyrightText: 2023 Jummit
    //
    // SPDX-License-Identifier: GPL-3.0-or-later
    
    use fmt;
    use types;
    use bufio;
    use strings;
    use io;
    use os;
    
    const numbers: [](str, int) = [
    	("one", 1),
    	("two", 2),
    	("three", 3),
    	("four", 4),
    	("five", 5),
    	("six", 6),
    	("seven", 7),
    	("eight", 8),
    	("nine", 9),
    	("1", 1),
    	("2", 2),
    	("3", 3),
    	("4", 4),
    	("5", 5),
    	("6", 6),
    	("7", 7),
    	("8", 8),
    	("9", 9),
    ];
    
    fn solve(start: size) void = {
    	const file = os::open("1.input")!;
    	defer io::close(file)!;
    	const scan = bufio::newscanner(file, types::SIZE_MAX);
    	let sum = 0;
    	for (let i = 1u; true; i += 1) {
    		const line = match (bufio::scan_line(&scan)!) {
    		case io::EOF =>
    			break;
    		case let line: const str =>
    			yield line;
    		};
    		let first: (void | int) = void;
    		let last: (void | int) = void;
    		for (let i = 0z; i < len(line); i += 1) :found {
    			for (let num = start; num < len(numbers); num += 1) {
    				const start = strings::sub(line, i, strings::end);
    				if (first is void && strings::hasprefix(start, numbers[num].0)) {
    					first = numbers[num].1;
    				};
    				const end = strings::sub(line, len(line) - 1 - i, strings::end);
    				if (last is void && strings::hasprefix(end, numbers[num].0)) {
    					last = numbers[num].1;
    				};
    				if (first is int && last is int) {
    					break :found;
    				};
    			};
    		};
    		sum += first as int * 10 + last as int;
    	};
    	fmt::printfln("{}", sum)!;
    };
    
    export fn main() void = {
    	solve(9);
    	solve(0);
    };