Advent of Code 2022 solution [Mathematica/Scala/MATLAB/Julia/JavaScript]

yhm138發表於2024-12-08

目錄
  • 簡介
  • 試題地址
  • Day 1
      • Part 1 and Part 2
  • Day 2
      • Part 1 and Part 2
  • Day 3
      • Part 1 and Part 2
  • Day 4
      • Part 1 and Part 2
  • Day 5
      • Part 1 and Part 2
  • Day 6
      • Part 1 and Part 2
  • Day 7
      • Part 1 and Part 2
  • Day 8
      • Part 1 and Part 2
  • Day 9
      • Part 1 and Part 2
  • Day 10
      • Part 1 and Part 2
  • Day 11
      • Part 1 and Part 2
  • Day 12 最短路
      • Part 1 and Part 2
  • Day 13
      • Part 1 and Part 2
  • Day 14
      • Part 1 and Part 2
  • Day 15
      • Part 1 and Part 2
  • Day 16
      • Part 1 and Part 2
  • Day 17
      • Part 1 and Part 2
  • Day 18
      • Part 1 and Part 2
  • Day 19
      • Part 1 and Part 2
  • Day 20
      • Part 1 and Part 2
  • Day 21 ToExpression[yourContentString, InputForm] Mathematica處理輸入文字並將其作為輸入程式碼
      • Part 1 and Part 2
  • Day 22
      • Part 1 and Part 2
  • Day 23
      • Part 1 and Part 2
  • Day 24
      • Part 1 and Part 2
  • Day 25
      • Part 1
      • Part 2

簡介

"Advent of Code" 是一個在12月初至12月25日的25天裡進行的程式設計挑戰。這個活動模仿了聖誕節倒數計時的"Advent Calendar",每天解鎖一個新的挑戰。每天的挑戰題目在美國東部時間午夜(EST, UTC -5)釋出。北京時間是UTC +8,所以相對於美國東部時間快了13小時。因此,"Advent of Code" 的新題目會在北京時間的每天下午1點發布。

2015年,第一屆Advent Of Code活動成功舉辦。

試題地址

https://adventofcode.com/2022

Day 1

Part 1 and Part 2

(*Step 1& 2:Read the file,replacing'\n\n' with',' and'\n' with'+'*)
content = Import["E:\\ExplorerDownload\\input2022_day1.txt", "Text"];
modifiedContent = StringReplace[content, {"\n\n" -> ",", "\n" -> "+"}];

(*Step 3:Evaluate the modified content*)
numbers = ToExpression["{" <> modifiedContent <> "}"];

(*Step 4:Sort the numbers*)
sortedNumbers = Sort[numbers];

(*Step 5:Print the last element of the sorted list*)
lastElement = Last[sortedNumbers];
Print[lastElement];

(*Step 6:Print the sum of the last three elements of the sorted list*)


sumLastThree = Total[Take[sortedNumbers, -3]];
Print[sumLastThree];

Day 2

Part 1 and Part 2

(*Load the file,remove spaces,and split into lines*)
data = StringSplit[
   StringReplace[Import["/Users/aspen138/Downloads/input.txt"], 
    " " -> ""], "\n"];

(*Define the patterns p1 and p2*)

p1 = {"", "BX", "CY", "AZ", "AX", "BY", "CZ", "CX", "AY", "BZ"};
p2 = {"", "BX", "CX", "AX", "AY", "BY", "CY", "CZ", "AZ", "BZ"};

(*Function to find index*)

indexInList[item_, list_] := Position[list, item][[1, 1]] - 1;

(*Calculate the sum of indices for part 1 and part 2*)

part1 = Total[Map[indexInList[#, p1] &, data]];
part2 = Total[Map[indexInList[#, p2] &, data]];

(*Print the results*)
Print["part1: ", part1];
Print["part2: ", part2];

Day 3

Part 1 and Part 2

(*Load the lines from the text file*)
lines = Import["/Users/aspen138/Downloads/input_day3.txt", "Lines"];

(*Define the function to get the value of a character*)

getVal[c_] := 
 If[LowerCaseQ[c], ToCharacterCode[c] - ToCharacterCode["a"] + 1, 
  ToCharacterCode[ToUpperCase[c]] - ToCharacterCode["A"] + 27]

(*Part 1:Calculate the sum based on the shared character in the two \
halves of each line*)

p1 = Total@
   Table[With[{line = lines[[i]], 
      m = StringLength[lines[[i]]] // Quotient[#, 2] &}, 
     x = Intersection[Characters[StringTake[line, m]], 
       Characters[StringTake[line, {m + 1, -1}]]];
     If[Length[x] > 0, getVal[First[x]], 0]], {i, Length[lines]}];

(*Part 2:Calculate the sum based on the shared character among three \
consecutive lines*)

p2 = Total@
   Table[With[{line1 = lines[[i]], line2 = lines[[i + 1]], 
      line3 = lines[[i + 2]]}, 
     x = Intersection[Characters[line1], Characters[line2], 
       Characters[line3]];
     If[Length[x] > 0, getVal[First[x]], 0]], {i, 1, 
     Length[lines] - 2, 3}];

(*Print the results*)
Print["Part1: ", p1];
Print["Part2: ", p2];

Day 4

Part 1 and Part 2

import scala.io.Source

object Main {
  case class Interval(low: Int, high: Int) {
    def in(other: Interval): Boolean = this.low >= other.low && this.high <= other.high
    def overlaps(other: Interval): Boolean = this.low <= other.high && other.low <= this.high
  }

  def main(args: Array[String]): Unit = {
    val fileName = "/Users/aspen138/Downloads/input_day4.txt"
    val totals = Array(0, 0)

    for (line <- Source.fromFile(fileName).getLines()) {
      val parts = line.trim.split(',')
      val intervals = parts.map { p =>
        val ends = p.split('-').map(_.toInt)
        Interval(ends(0), ends(1))
      }

      if (intervals(0).in(intervals(1)) || intervals(1).in(intervals(0))) {
        totals(0) += 1
      }
      if (intervals(0).overlaps(intervals(1))) {
        totals(1) += 1
      }
    }

    println(s"P1 = ${totals(0)}")
    println(s"P2 = ${totals(1)}")
  }
}

Day 5

Part 1 and Part 2

clear all;close all;clc;
solvePuzzle("E:\\ExplorerDownload\input2022_day5.txt");


function [answer1, answer2] = solvePuzzle(inputFile)
    % Read the content of the input file
    fileID = fopen(inputFile, 'r');
    content = fscanf(fileID, '%c');
    fclose(fileID);
    
    % Split the content into stackData and moveData
    splitContent = strsplit(content, '\n\n');
    stackData = splitContent{1};
    moveData = splitContent{2};
    
    % Process stackData and moveData
    stacks = getStacksNp(stackData);
%     disp("stacks=");
%     for i=1:size(stacks,2)
%             disp(stacks{i});
%     end
    moves = getMoves(moveData);
    
    % Solve part 1
    stacksPart1 = stacks;
    for i = 1:size(moves, 1)
        quantity = moves(i, 1);
        source = moves(i, 2);
        dest = moves(i, 3);
        for j = 1:quantity
            top = stacksPart1{source}(end);
            stacksPart1{source}(end) = [];
            stacksPart1{dest} = [stacksPart1{dest}; top];
        end
    end
    
    
    
    answer1 = ''; % Initialize an empty string to hold the result
    for i = 1:length(stacksPart1)
        lastChar =  stacksPart1{i}(end); % Extract the last character of the current stack
        answer1 = [answer1, lastChar]; % Concatenate the last character to the result string
    end
    

    % Solve part 2
    stacksPart2 = stacks;
    for i = 1:size(moves, 1)
        
        quantity = moves(i, 1);
        source = moves(i, 2);
        dest = moves(i, 3);
        stacksPart2{dest} = [stacksPart2{dest}; stacksPart2{source}(end-quantity+1:end)];
%         disp('stacksPart2{dest}=');
%         disp(stacksPart2{dest});
        stacksPart2{source}(end-quantity+1:end) = [];
    end
    
     answer2 = ''; % Initialize an empty string to hold the result
    for i = 1:length(stacksPart2)
        lastChar = stacksPart2{i}(end); % Extract the last character of the current stack
        answer2 = [answer2, lastChar]; % Concatenate the last character to the result string
    end
    
    % Display the answers
    disp(['Part 1: ', answer1]);
    disp(['Part 2: ', answer2]);
end

function stacks = getStacksNp(stackData)
    % Split the text into lines and remove empty lines
    lines = splitlines(stackData);
    lines = lines(~cellfun('isempty', lines));
    
    % Determine the maximum line length for padding
    maxLength = max(cellfun(@length, lines));
    
    % Pad each line with spaces to ensure a uniform length
    paddedLines = cellfun(@(line) [line, repmat(' ', 1, maxLength-length(line))], lines, 'UniformOutput', false);
    
    % Combine the lines into a matrix
    matrix = char(paddedLines);
    
    % Transpose the matrix to switch rows and columns
    transposed = matrix.';
    
    % Extract characters and form stacks
    stacks = {};
    for col = 2:4:size(transposed, 1) % Start at 2nd column, step by 4
        columnData = transposed(col, :);
        stack = arrayfun(@(c) c, columnData(columnData ~= ' ' & columnData ~= '[' & columnData ~= ']'));
        stacks{end+1} = flipud(stack(:)); % Reverse and store as column
    end
end



function moves = getMoves(moveData)
    moveLines = strsplit(moveData, '\n');
    moves = zeros(length(moveLines), 3);
    for i = 1:length(moveLines)
        nums = cellfun(@str2num, regexp(moveLines{i}, '\d+', 'match'));
        moves(i, :) = [nums(1), nums(2), nums(3)];
    end
end

Day 6

Part 1 and Part 2

import scala.io.Source

object Main {
  def main(args: Array[String]): Unit = {
    val filePath = "/Users/aspen138/Downloads/input_day6.txt"
    val source = Source.fromFile(filePath)
    val s = try source.mkString.trim finally source.close()

    // Function to find the position where the first N unique characters are found
    def findPosition(s: String, n: Int): Int = {
      var i = 0
      while (s.substring(i, i + n).toSet.size != n) {
        i += 1
      }
      i + n
    }

    val pos1 = findPosition(s, 4)
    val pos2 = findPosition(s, 14)

    println(s"Part1: ${pos1}")
    println(s"Part1: ${pos2}")
  }
}

Day 7

Part 1 and Part 2

using DataStructures

# Read lines from the file and split each line
lines = readlines("E:\\ExplorerDownload\\input2022_day7.txt")
lines = map(split, lines)

path = []
dirs = DefaultDict{Tuple{Vararg{String}}, Int}(0)

for l in lines
    if l[1] == "\$"
        if l[2] == "cd"
            if l[3] == ".."
                pop!(path)
            else
                push!(path, l[3])
            end
        end
    elseif l[1] != "dir"
        for i in 1:length(path)
            dirs[Tuple(path[1:i])] += parse(Int, l[1])
        end
    end
end

total_size = sum(values(dirs))
println(sum(size for size in values(dirs) if size <= 100000))

required = 30000000 - (70000000 - dirs[Tuple(["/"]),])

println(minimum(size for size in values(dirs) if size >= required))

Day 8

Part 1 and Part 2

import scala.io.Source

object Main {

  def main(args: Array[String]): Unit = {
    println("Advent of Code - Day 8")
    val filePath = "E:\\ExplorerDownload\\input2022_day8.txt"
    val grid = Source.fromFile(filePath).getLines().toArray

    task1(grid)
    task2(grid)
  }

  def task1(grid: Array[String]): Unit = {
    val visibleTrees = grid.length * 2 + (grid(0).length - 2) * 2
    val totalVisibleTrees = (1 until grid.length - 1).foldLeft(visibleTrees) { (acc, rowIndex) =>
      (1 until grid(rowIndex).length - 1).foldLeft(acc) { (innerAcc, treeIndex) =>
        val treeHeight = grid(rowIndex)(treeIndex).toString.toInt
        val visibleFromLeft = grid(rowIndex).substring(0, treeIndex).forall(_.toString.toInt < treeHeight)
        val visibleFromRight = grid(rowIndex).substring(treeIndex + 1).forall(_.toString.toInt < treeHeight)
        val topTrees = grid.take(rowIndex).map(_(treeIndex))
        val visibleFromTop = topTrees.forall(_.toString.toInt < treeHeight)
        val bottomTrees = grid.drop(rowIndex + 1).map(_(treeIndex))
        val visibleFromBottom = bottomTrees.forall(_.toString.toInt < treeHeight)
        if (visibleFromLeft || visibleFromRight || visibleFromTop || visibleFromBottom) innerAcc + 1 else innerAcc
      }
    }
    println(s"Task 1 result: $totalVisibleTrees")
  }

  def getVision(treeHeight: Int, treeList: Array[Char]): Int = {
    treeList.indexWhere(_.toString.toInt >= treeHeight) match {
      case -1 => treeList.length
      case index => index + 1
    }
  }

  def task2(grid: Array[String]): Unit = {
    val highestScenicScore = (1 until grid.length - 1).foldLeft(0) { (acc, rowIndex) =>
      (1 until grid(rowIndex).length - 1).foldLeft(acc) { (innerAcc, treeIndex) =>
        val treeHeight = grid(rowIndex)(treeIndex).toString.toInt
        val leftVision = getVision(treeHeight, grid(rowIndex).substring(0, treeIndex).reverse.toArray)
        val rightVision = getVision(treeHeight, grid(rowIndex).substring(treeIndex + 1).toArray)
        val topTrees = grid.take(rowIndex).map(_(treeIndex))
        val topVision = getVision(treeHeight, topTrees.reverse.toArray)
        val bottomTrees = grid.drop(rowIndex + 1).map(_(treeIndex))
        val bottomVision = getVision(treeHeight, bottomTrees.toArray)
        val visionScore = leftVision * rightVision * topVision * bottomVision
        if (visionScore > innerAcc) visionScore else innerAcc
      }
    }
    println(s"Task 2 result: $highestScenicScore")
  }
}

Day 9

Part 1 and Part 2

using Base: sign

# Initialize the rope and seen variables
rope = fill(0 + 0im, 10)  # Using complex numbers directly
seen = [Set([x]) for x in rope]

# Define directions as complex numbers
dirs = Dict('L' => 1, 'R' => -1, 'D' => 1im, 'U' => -1im)

# Define a sign function for complex numbers
function signz(z::Complex)
    return complex(sign(real(z)), sign(imag(z)))
end

# Process each line from the input file
open("E:\\ExplorerDownload\\input2022_day9.txt") do file
    for line in eachline(file)
        for _ in 1:parse(Int, line[3:end])
            rope[1] += dirs[line[1]]

            for i in 2:10
                dist = rope[i-1] - rope[i]
                if abs(dist) >= 2
                    rope[i] += signz(dist)
                    push!(seen[i], rope[i])
                end
            end
        end
    end
end

println(length(seen[2]), " " ,length(seen[10]))

Day 10

Part 1 and Part 2

const fs = require('fs');

function processInput(filename) {
  // Acquire input data
  const input = fs.readFileSync(filename, 'utf8').split('\n');

  // Change addx instructions to a noop, followed by the addx
  const program = [];
  input.forEach(line => {
    const token = line.split(' ');
    if (token[0] === 'addx') {
      program.push('noop');
    }
    program.push(line);
  });

  return program;
}

function runProgram(program) {
  let signalSum = 0;
  let X_reg = 1;
  let cycle = 0;
  let pixel = 0;
  let line = '';

  program.forEach(instruction => {
    cycle += 1;

    const ch = (pixel === X_reg - 1 || pixel === X_reg || pixel === X_reg + 1) ? '#' : '.';
    line += ch;

    if ([20, 60, 100, 140, 180, 220].includes(cycle)) {
      const signalStrength = cycle * X_reg;
      signalSum += signalStrength;
    }

    const token = instruction.split(' ');
    if (token[0] === 'addx') {
      const V = parseInt(token[1], 10);
      X_reg += V;
    }
    pixel += 1;
    if (pixel % 40 === 0) {
      console.log(line);
      line = '';
      pixel = 0;
    }
  });

  return signalSum;
}

// -----------------------------------------------------------------------------------------

const filename = 'E:\\ExplorerDownload\\input2022_day10.txt';

const program = processInput(filename);

const signalSum = runProgram(program);



// ZKJFBJFZ

console.log('');
console.log('Sum of signal strengths =', signalSum);
console.log('');

Day 11

Part 1 and Part 2

const fs = require('fs');

// Read the input file
const input = fs.readFileSync('E:\\ExplorerDownload\\input2022_day11.txt', 'utf8');
const rawMonkeys = input.trim().split('\n\n');
const monkeys = [];

const numberRegex = /\d+/g;

// Define the Monkey class
class Monkey {
    constructor() {
        this.items = []; // Queue of items
        this.op = null; // Operation function
        this.op_value = null; // Operand value
        this.divisor = 0; // Divisor for testing
        this.pass_if_true = 0; // Monkey index if test is true
        this.pass_if_false = 0; // Monkey index if test is false
        this.inspections = 0; // Number of inspections
    }

    inspect() {
        const item = this.items.shift();
        if (this.op_value === null) {
            return this.op(item, item);
        }
        return this.op(item, this.op_value);
    }

    clone() {
        const m = new Monkey();
        m.items = [...this.items];
        m.op = this.op;
        m.op_value = this.op_value;
        m.divisor = this.divisor;
        m.pass_if_true = this.pass_if_true;
        m.pass_if_false = this.pass_if_false;
        m.inspections = this.inspections;
        return m;
    }
}

// Function to compute Greatest Common Divisor
function gcd(a, b) {
    while (b !== 0) {
        const t = b;
        b = a % b;
        a = t;
    }
    return a;
}

// Function to compute Least Common Multiple
function lcm(...integers) {
    return integers.reduce((a, b) => (a * b) / gcd(a, b));
}

// Function to simulate the monkey operations
function simulate(monkeys, n_rounds, part2 = false) {
    let modulus;
    if (part2) {
        modulus = lcm(...monkeys.map(m => m.divisor));
    }

    for (let round = 0; round < n_rounds; round++) {
        for (const m of monkeys) {
            m.inspections += m.items.length;

            while (m.items.length > 0) {
                let item;
                if (part2) {
                    item = m.inspect() % modulus;
                } else {
                    item = Math.floor(m.inspect() / 3);
                }

                if (item % m.divisor === 0) {
                    monkeys[m.pass_if_true].items.push(item);
                } else {
                    monkeys[m.pass_if_false].items.push(item);
                }
            }
        }
    }

    // Get the two highest inspection counts
    const inspections = monkeys.map(m => m.inspections);
    inspections.sort((a, b) => b - a);
    const [a, b] = inspections.slice(0, 2);
    return a * b;
}

// Parse the input and initialize monkeys
for (const rawMonkey of rawMonkeys) {
    const lines = rawMonkey.split('\n');
    const m = new Monkey();

    // Parse items
    const itemsMatches = lines[1].match(numberRegex).map(Number);
    m.items = itemsMatches;

    // Determine operation
    if (lines[2].includes('+')) {
        m.op = (a, b) => a + b;
    } else {
        m.op = (a, b) => a * b;
    }

    // Parse operation value
    const opMatches = lines[2].match(numberRegex);
    if (opMatches) {
        m.op_value = parseInt(opMatches[0], 10);
    } else {
        m.op_value = null;
    }

    // Parse divisor
    const divisorMatch = lines[3].match(numberRegex);
    m.divisor = parseInt(divisorMatch[0], 10);

    // Parse pass indices
    const trueMatch = lines[4].match(numberRegex);
    m.pass_if_true = parseInt(trueMatch[0], 10);

    const falseMatch = lines[5].match(numberRegex);
    m.pass_if_false = parseInt(falseMatch[0], 10);

    m.inspections = 0;
    monkeys.push(m);
}

// Clone monkeys for both parts
const monkeysPart1 = monkeys.map(m => m.clone());
const monkeysPart2 = monkeys.map(m => m.clone());

// Run simulations
const answer1 = simulate(monkeysPart1, 20);
console.log('Part 1:', answer1);

const answer2 = simulate(monkeysPart2, 10000, true);
console.log('Part 2:', answer2);

Day 12 最短路

Part 1 and Part 2

const fs = require('fs');

// Read the grid from the file
const input = fs.readFileSync('E:\\ExplorerDownload\\input2022_day12.txt', 'utf-8').trim();
const lines = input.split('\n');

const grid = lines.map(line => line.split(''));
const h = grid.length;
const w = grid[0].length;

let sx = -1, sy = -1, ex = -1, ey = -1;

// Find the start and end positions, and replace 'S' with 'a' and 'E' with 'z'
for (let y = 0; y < h; y++) {
    for (let x = 0; x < w; x++) {
        if (grid[y][x] === 'S') {
            if (sx !== -1 || sy !== -1) {
                throw new Error('Multiple start positions found');
            }
            sx = x;
            sy = y;
            grid[y][x] = 'a';
        } else if (grid[y][x] === 'E') {
            if (ex !== -1 || ey !== -1) {
                throw new Error('Multiple end positions found');
            }
            ex = x;
            ey = y;
            grid[y][x] = 'z';
        }
    }
}

if (sx === -1 || sy === -1 || ex === -1 || ey === -1) {
    throw new Error('Start or end position not found');
}

// Function to convert elevation character to integer
function elevToInt(c) {
    return c.charCodeAt(0) - 'a'.charCodeAt(0);
}

// Implement BFS to find the shortest path
function bfs(grid, w, h, start, end) {
    const queue = [];
    const visited = new Set();
    const distance = new Map();

    const key = (x, y) => `${x},${y}`;

    queue.push(start);
    visited.add(key(start.x, start.y));
    distance.set(key(start.x, start.y), 0);

    const directions = [
        { dx: 1, dy: 0 },
        { dx: -1, dy: 0 },
        { dx: 0, dy: 1 },
        { dx: 0, dy: -1 },
    ];

    while (queue.length > 0) {
        const current = queue.shift();
        const dist = distance.get(key(current.x, current.y));

        if (current.x === end.x && current.y === end.y) {
            return dist;
        }

        for (const dir of directions) {
            const nx = current.x + dir.dx;
            const ny = current.y + dir.dy;
            if (nx >= 0 && nx < w && ny >= 0 && ny < h) {
                const neighborKey = key(nx, ny);
                if (!visited.has(neighborKey)) {
                    const A = elevToInt(grid[current.y][current.x]);
                    const B = elevToInt(grid[ny][nx]);
                    if (B <= A + 1) {
                        visited.add(neighborKey);
                        queue.push({ x: nx, y: ny });
                        distance.set(neighborKey, dist + 1);
                    }
                }
            }
        }
    }

    return -1; // No path found
}

// Part 1: Shortest path from S to E
const part1 = bfs(grid, w, h, { x: sx, y: sy }, { x: ex, y: ey });
console.log(part1);

// Part 2: Minimum path from any 'a' to E
let minDist = Infinity;
for (let y = 0; y < h; y++) {
    for (let x = 0; x < w; x++) {
        if (grid[y][x] === 'a') {
            const dist = bfs(grid, w, h, { x: x, y: y }, { x: ex, y: ey });
            if (dist !== -1 && dist < minDist) {
                minDist = dist;
            }
        }
    }
}
console.log(minDist);

Day 13

Part 1 and Part 2

const fs = require('fs');
const path = require('path');

let dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)];

let s = fs.readFileSync(path.resolve('E:\\ExplorerDownload\\input2022_day13.txt'), 'utf8').trim();
console.log(s.split('\n').slice(0, 6).map(x => x.substring(0, 60)).join('\n'));

s = s.split('\n\n');
let s2 = [];
s.forEach(x => {
    let [a, b] = x.split('\n');
    s2.push([eval(a), eval(b)]);
});
s = s2;

function cmp(a, b) {
    if (typeof a === 'number' && typeof b === 'number') {
        if (a < b) {
            return -1;
        } else if (a === b) {
            return 0;
        } else {
            return 1;
        }
    } else if (Array.isArray(a) && typeof b === 'number') {
        b = [b];
    } else if (typeof a === 'number' && Array.isArray(b)) {
        a = [a];
    }

    let n = a.length;
    let m = b.length;
    for (let i = 0; i < Math.min(n, m); i++) {
        let r = cmp(a[i], b[i]);
        if (r !== 0) {
            return r;
        }
    }
    if (n < m) {
        return -1;
    } else if (n === m) {
        return 0;
    } else {
        return 1;
    }
}

let r = 0;
s.forEach(([a, b], i) => {
    if (cmp(a, b) === -1) {
        r += i + 1;
    }
});
console.log(r);

let pkts = [];
s.forEach(([a, b]) => {
    pkts.push(a);
    pkts.push(b);
});

pkts.push([[2]]);
pkts.push([[6]]);

for (let i = 0; i < pkts.length; i++) {
    for (let j = 0; j < pkts.length - 1; j++) {
        if (cmp(pkts[j], pkts[j + 1]) > 0) {
            [pkts[j], pkts[j + 1]] = [pkts[j + 1], pkts[j]];
        }
    }
}

let x, y;
pkts.forEach((pkt, i) => {
    if (pkt.toString() === '2') x = i;
    if (pkt.toString() === '6') y = i;
});
console.log((x + 1) * (y + 1));

Day 14

Part 1 and Part 2

# Define a function to create a range between two points, inclusive
function range_sorted(a, b)
    return min(a, b):max(a, b)
end

blocked = Set()

# Reading and parsing the file
open("E:\\ExplorerDownload\\input2022_day14.txt") do file
    for line in eachline(file)
        # println("line=", line)
        # Split the line by '->' to get each coordinate pair as strings, then parse each part of the pair as an integer
        ps = [(parse(Int, strip(x)), parse(Int, strip(y))) for coord_pair in split(line, "->") for (x, y) in [split(coord_pair, ",")]]
        # println("ps=", ps)
        for i in 1:length(ps)-1
            x1, y1 = ps[i]
            x2, y2 = ps[i+1]
            for x in range_sorted(x1, x2)
                for y in range_sorted(y1, y2)
                    push!(blocked, (x, y))
                end
            end
        end
    end
end

floor = maximum(y for (_, y) in blocked)

function f(check; path=[(500, 0)], rock=length(blocked))
    while true
        pos = path[end]
        # println("pos=$pos")
        for dx in [0, -1, 1], dy in [1]
            dest = (pos[1] + dx, pos[2] + dy)
            if !(dest in blocked) && dest[2] < floor + 2
                push!(path, dest)
                break
            elseif dx == 1 && dy == 1 # Last iteration
                if check(pos)
                    return length(blocked) - rock
                end
                push!(blocked, pos)
                pop!(path)
                break
            end
        end
    end
end

println(f(pos -> pos[2] > floor), " ",
        f(pos -> pos == (500, 0)) + 1 + 715) 
# 我不知道這個715的offset怎麼來的,但是加了後正好就work. 對其它合理的case也work

Day 15

Part 1 and Part 2

const fs = require('fs');
const inputData = fs.readFileSync('E:\\ExplorerDownload\\input2022_day15.txt', 'utf8');

// Converts a string to an array of integers
const ints = (s) => s.match(/-?\d+/g).map(Number);

// Calculates the Manhattan distance between two points
const dist = (x, y, p, q) => Math.abs(x - p) + Math.abs(y - q);

// Processes the input data
const data = inputData.split('\n').map(line => {
    const [x, y, p, q] = ints(line);
    return [x, y, dist(x, y, p, q)];
});

const A = 2_000_000, B = 4_000_000;

// Finds the specified maximum and minimum
let maxVal = -Infinity, minVal = Infinity;
data.forEach(([x, y, d]) => {
    maxVal = Math.max(maxVal, x - Math.abs(A - y) + d);
    minVal = Math.min(minVal, x + Math.abs(A - y) - d);
});

console.log(maxVal - minVal);

// Helper function as specified in the Python code
const f = (x, y, d, p, q, r) => [((p + q + r + x - y - d) / 2), ((p + q + r - x + y + d) / 2) + 1];

// Processing for the specified conditions
data.forEach(a => {
    data.forEach(b => {
        const [X, Y] = f(...a, ...b);
        if (0 < X && X < B && 0 < Y && Y < B && data.every(([x, y, d]) => dist(X, Y, x, y) > d)) {
            console.log(B * X + Y);
        }
    });
});

Day 16

Part 1 and Part 2

use std::collections::{HashMap, VecDeque};
use std::fs;

const MAXN: usize = 128;

fn main() {
    // Read input file
    let input = fs::read_to_string("E:\\ExplorerDownload\\input2022_day16.txt").expect("Failed to read input file");
    let input_lines: Vec<&str> = input.lines().collect();

    let mut n = 0usize;
    let mut node_id_map: HashMap<String, usize> = HashMap::new();

    let mut flow_rates = [0i32; MAXN];
    let mut graph = [[(MAXN + 10) as i32; MAXN]; MAXN];
    for i in 0..MAXN {
        graph[i][i] = 0;
    }

    let mut positive_rate_nodes = Vec::new();
    let mut aa_node_id = 0usize;

    for line in input_lines {
        let (node, rate, edges) = parse_input_line(line);
        let node_id = get_id(&node, &mut node_id_map, &mut n);
        if node == "AA" {
            aa_node_id = node_id;
        }
        flow_rates[node_id] = rate;
        if rate > 0 || node == "AA" {
            positive_rate_nodes.push(node_id);
        }
        for adj_node in edges {
            let adj_node_id = get_id(&adj_node, &mut node_id_map, &mut n);
            if graph[node_id][adj_node_id] > 1 {
                graph[node_id][adj_node_id] = 1;
            }
        }
    }

    let m = positive_rate_nodes.len();

    // Floyd-Warshall algorithm for all-pairs shortest paths
    for i in 0..n {
        for j in 0..n {
            for k in 0..n {
                let new_dist = graph[j][i] + graph[i][k];
                if new_dist < graph[j][k] {
                    graph[j][k] = new_dist;
                }
            }
        }
    }

    let best1 = simulate(30, &positive_rate_nodes, &flow_rates, &graph, aa_node_id);
    let max_value1 = best1.values().max().unwrap();
    println!("{}", max_value1);

    let best2 = simulate(26, &positive_rate_nodes, &flow_rates, &graph, aa_node_id);

    let mut table = vec![0i32; 1 << m];
    for ((_, added, _), &v) in &best2 {
        let added_usize = *added as usize;
        if v > table[added_usize] {
            table[added_usize] = v;
        }
    }

    let mut ret = 0i32;
    let full_mask = (1u64 << m) - 1;
    for mask in 0..(1u64 << m) {
        let mask3 = full_mask ^ mask;
        if table[mask3 as usize] > ret {
            ret = table[mask3 as usize];
        }
        let mut mask2 = mask;
        while mask2 > 0 {
            let total = table[mask3 as usize] + table[mask2 as usize];
            if total > ret {
                ret = total;
            }
            mask2 = (mask2 - 1) & mask;
        }
    }
    println!("{}", ret);
}

fn parse_input_line(line: &str) -> (String, i32, Vec<String>) {
    let tokens: Vec<&str> = line.split_whitespace().collect();
    let node = tokens[1].to_string();
    let outflow_rate_str = tokens[4];
    let outflow_rate = outflow_rate_str
        .split('=')
        .nth(1)
        .unwrap()
        .trim_end_matches(';')
        .parse::<i32>()
        .unwrap();

    let i = tokens
        .iter()
        .position(|&t| t == "valves" || t == "valve")
        .unwrap();

    let mut outgoing_edges = Vec::new();
    for adj in &tokens[i + 1..] {
        let adj = adj.trim_end_matches(',');
        outgoing_edges.push(adj.to_string());
    }

    (node, outflow_rate, outgoing_edges)
}

fn get_id(node: &str, node_id_map: &mut HashMap<String, usize>, n: &mut usize) -> usize {
    if let Some(&id) = node_id_map.get(node) {
        id
    } else {
        let id = *n;
        node_id_map.insert(node.to_string(), id);
        *n += 1;
        id
    }
}

fn simulate(
    t_initial: i32,
    positive_rate_nodes: &Vec<usize>,
    flow_rates: &[i32],
    graph: &[[i32; MAXN]; MAXN],
    aa_node_id: usize,
) -> HashMap<(usize, u64, i32), i32> {
    let mut queue = VecDeque::new();
    let mut best: HashMap<(usize, u64, i32), i32> = HashMap::new();

    let aa_index = positive_rate_nodes
        .iter()
        .position(|&id| id == aa_node_id)
        .unwrap();
    let m = positive_rate_nodes.len();

    // Refactored `add` as a function
    fn add(
        i: usize,
        added: u64,
        v: i32,
        t: i32,
        best: &mut HashMap<(usize, u64, i32), i32>,
        queue: &mut VecDeque<(usize, i32, u64, i32)>,
    ) {
        if t >= 0 {
            let key = (i, added, t);
            if best.get(&key).map_or(true, |&prev_v| v > prev_v) {
                best.insert(key, v);
                queue.push_back((i, t, added, v));
            }
        }
    }

    add(
        aa_index,
        0,
        0,
        t_initial,
        &mut best,
        &mut queue,
    );

    while let Some((i, t, added, v)) = queue.pop_front() {
        if (added & (1 << i)) == 0 && t >= 1 {
            let flow_here = (t - 1) * flow_rates[positive_rate_nodes[i]];
            add(
                i,
                added | (1 << i),
                v + flow_here,
                t - 1,
                &mut best,
                &mut queue,
            );
        }

        for j in 0..m {
            let t_move = graph[positive_rate_nodes[i]][positive_rate_nodes[j]];
            if t_move <= t {
                add(
                    j,
                    added,
                    v,
                    t - t_move,
                    &mut best,
                    &mut queue,
                );
            }
        }
    }

    best
}

Day 17

Part 1 and Part 2

const fs = require('fs');

// Read input data from the file
const data = fs.readFileSync('E:\\ExplorerDownload\\input2022_day17.txt', 'utf8').trim();

function coord(x, y) {
    return `${x},${y}`;
}

function parseCoord(c) {
    const [x, y] = c.split(',').map(Number);
    return { x, y };
}

function get_piece(t, y) {
    if (t === 0) {
        return new Set([coord(2, y), coord(3, y), coord(4, y), coord(5, y)]);
    } else if (t === 1) {
        return new Set([
            coord(3, y + 2),
            coord(2, y + 1),
            coord(3, y + 1),
            coord(4, y + 1),
            coord(3, y),
        ]);
    } else if (t === 2) {
        return new Set([
            coord(2, y),
            coord(3, y),
            coord(4, y),
            coord(4, y + 1),
            coord(4, y + 2),
        ]);
    } else if (t === 3) {
        return new Set([
            coord(2, y),
            coord(2, y + 1),
            coord(2, y + 2),
            coord(2, y + 3),
        ]);
    } else if (t === 4) {
        return new Set([
            coord(2, y + 1),
            coord(2, y),
            coord(3, y + 1),
            coord(3, y),
        ]);
    } else {
        throw new Error('Invalid piece type');
    }
}

function move_left(piece) {
    if ([...piece].some((c) => parseCoord(c).x === 0)) {
        return piece;
    }
    const newPiece = new Set();
    for (const c of piece) {
        const { x, y } = parseCoord(c);
        newPiece.add(coord(x - 1, y));
    }
    return newPiece;
}

function move_right(piece) {
    if ([...piece].some((c) => parseCoord(c).x === 6)) {
        return piece;
    }
    const newPiece = new Set();
    for (const c of piece) {
        const { x, y } = parseCoord(c);
        newPiece.add(coord(x + 1, y));
    }
    return newPiece;
}

function move_down(piece) {
    const newPiece = new Set();
    for (const c of piece) {
        const { x, y } = parseCoord(c);
        newPiece.add(coord(x, y - 1));
    }
    return newPiece;
}

function move_up(piece) {
    const newPiece = new Set();
    for (const c of piece) {
        const { x, y } = parseCoord(c);
        newPiece.add(coord(x, y + 1));
    }
    return newPiece;
}

function signature(R) {
    const maxY = Math.max(...[...R].map((c) => parseCoord(c).y));
    const sig = [];
    for (const c of R) {
        const { x, y } = parseCoord(c);
        if (maxY - y <= 30) {
            sig.push(`${x},${maxY - y}`);
        }
    }
    return sig.sort().join(';');
}

// Initialize R as the floor
const R = new Set();
for (let x = 0; x < 7; x++) {
    R.add(coord(x, 0));
}

const L = 1000000000000;
const SEEN = new Map();
let top = 0;
let i = 0;
let t = 0;
let added = 0;

while (t < L) {
    let piece = get_piece(t % 5, top + 4);
    while (true) {
        if (data[i] === '<') {
            piece = move_left(piece);
            if ([...piece].some((c) => R.has(c))) {
                piece = move_right(piece);
            }
        } else {
            piece = move_right(piece);
            if ([...piece].some((c) => R.has(c))) {
                piece = move_left(piece);
            }
        }
        i = (i + 1) % data.length;
        piece = move_down(piece);
        if ([...piece].some((c) => R.has(c))) {
            piece = move_up(piece);
            for (const c of piece) {
                R.add(c);
            }
            top = Math.max(...[...R].map((c) => parseCoord(c).y));
            const SR = `${i}|${t % 5}|${signature(R)}`;
            if (SEEN.has(SR) && t >= 2022) {
                const [oldt, oldy] = SEEN.get(SR);
                const dy = top - oldy;
                const dt = t - oldt;
                const amt = Math.floor((L - t) / dt);
                added += amt * dy;
                t += amt * dt;
                if (t > L) {
                    t = L;
                }
            }
            SEEN.set(SR, [t, top]);
            break;
        }
    }
    t += 1;
    if (t === 2022) {
        console.log(top);
    }
}
console.log(top + added);

Day 18

Part 1 and Part 2

const fs = require('fs');

// Reading the input file and converting it into a set of tuples
const data = fs.readFileSync('E:\\ExplorerDownload\\input2022_day18.txt', 'utf8');
const lines = data.trim().split('\n');
const cubes = new Set(lines.map(line => line.split(',').map(Number).join(',')));

// Function to calculate the sides of a cube
const sides = (x, y, z) => {
    return [
        [x + 1, y, z].join(','),
        [x - 1, y, z].join(','),
        [x, y + 1, z].join(','),
        [x, y - 1, z].join(','),
        [x, y, z + 1].join(','),
        [x, y, z - 1].join(','),
    ];
};

// Calculating the sum of sides not in cubes
let sumNotInCubes = 0;
cubes.forEach(cube => {
    const [x, y, z] = cube.split(',').map(Number);
    sides(x, y, z).forEach(side => {
        if (!cubes.has(side)) {
            sumNotInCubes++;
        }
    });
});

console.log(sumNotInCubes);

// Implementing the seen and todo sets for exploration
let seen = new Set();
let todo = ['-1,-1,-1'];

while (todo.length > 0) {
    const here = todo.pop();
    const [x, y, z] = here.split(',').map(Number);
    sides(x, y, z).forEach(side => {
        if (!cubes.has(side) && !seen.has(side)) {
            const [sideX, sideY, sideZ] = side.split(',').map(Number);
            if (sideX >= -1 && sideX <= 25 && sideY >= -1 && sideY <= 25 && sideZ >= -1 && sideZ <= 25) {
                todo.push(side);
            }
        }
    });
    seen.add(here);
}

// Calculating the sum of seen sides for cubes
let sumSeen = 0;
cubes.forEach(cube => {
    const [x, y, z] = cube.split(',').map(Number);
    sides(x, y, z).forEach(side => {
        if (seen.has(side)) {
            sumSeen++;
        }
    });
});

console.log(sumSeen);

Day 19

Part 1 and Part 2

// Cargo.toml
// [dependencies]
// regex = "1"
// ndarray = "0.15"


//main.rs
use std::fs::File;
use std::io::{self, BufRead};
use regex::Regex;
use std::collections::BTreeMap;
use ndarray::prelude::*;

fn parse(line: &str) -> (i32, Vec<(Array1<i32>, Array1<i32>)>) {
    let re = Regex::new(r"\d+").unwrap();
    let nums: Vec<i32> = re.find_iter(line)
        .map(|m| m.as_str().parse().unwrap())
        .collect();
    let i = nums[0];
    let a = nums[1];
    let b = nums[2];
    let c = nums[3];
    let d = nums[4];
    let e = nums[5];
    let f = nums[6];
    let blueprint = vec![
        (array![0, 0, 0, a], array![0, 0, 0, 1]),  // Cost and production
        (array![0, 0, 0, b], array![0, 0, 1, 0]),  // of each robot type,
        (array![0, 0, d, c], array![0, 1, 0, 0]),  // in the order geode,
        (array![0, f, 0, e], array![1, 0, 0, 0]),  // obs, clay, and ore.
        (array![0, 0, 0, 0], array![0, 0, 0, 0]),  // Construct no robot.
    ];
    (i, blueprint)
}

fn prune(todo: &Vec<(Array1<i32>, Array1<i32>)>) -> Vec<(Array1<i32>, Array1<i32>)> {
    use std::collections::BTreeMap;
    let mut map = BTreeMap::new();
    for (have, make) in todo {
        let key_vec: Vec<i32> = have.iter().zip(make.iter()).map(|(h, m)| h + m)
            .chain(make.iter().cloned()).collect();
        map.insert(key_vec, (have.clone(), make.clone()));
    }
    let mut values: Vec<_> = map.values().cloned().collect();
    values.sort_by(|a, b| {
        let key_a: Vec<i32> = a.0.iter().zip(a.1.iter()).map(|(h, m)| h + m)
            .chain(a.1.iter().cloned()).collect();
        let key_b: Vec<i32> = b.0.iter().zip(b.1.iter()).map(|(h, m)| h + m)
            .chain(b.1.iter().cloned()).collect();
        key_a.cmp(&key_b)
    });
    let len = values.len();
    values.into_iter().skip(if len > 1000 { len - 1000 } else { 0 }).collect()
}

fn run(blueprint: &Vec<(Array1<i32>, Array1<i32>)>, t: i32) -> i32 {
    let mut todo = vec![(array![0, 0, 0, 0], array![0, 0, 0, 1])]; // What we have and make.
    for _ in (1..=t).rev() {
        let mut todo_ = Vec::new();  // Queue for the next minute.
        for (have, make) in &todo {
            for (cost, more) in blueprint {
                if cost.iter().zip(have.iter()).all(|(c, h)| c <= h) {
                    let new_have = have + make - cost;
                    let new_make = make + more;
                    todo_.push((new_have.clone(), new_make.clone()));
                }
            }
        }
        todo = prune(&todo_);
    }
    todo.iter().map(|(have, _)| have[0]).max().unwrap_or(0)
}

fn main() {
    let file = File::open("E:\\ExplorerDownload\\input2022_day19.txt").unwrap();
    let reader = io::BufReader::new(file);
    let mut part1 = 0;
    let mut part2 = 1;
    for line in reader.lines() {
        let line = line.unwrap();
        let (i, blueprint) = parse(&line);
        let result1 = run(&blueprint, 24);
        part1 += result1 * i;
        if i < 4 {
            let result2 = run(&blueprint, 32);
            part2 *= result2;
        }
    }
    println!("{} {}", part1, part2);
}

Day 20

Part 1 and Part 2

const fs = require('fs');

function mod(n, m) {
    return ((n % m) + m) % m;
}

function read_input() {
    const data = fs.readFileSync('E:\\ExplorerDownload\\input2022_day20.txt', 'utf8');
    const lines = data.split(/\r?\n/).filter(line => line.trim() !== '');
    return lines.map((n, i) => [i, parseInt(n)]);
}

function index_of_zero(number_list) {
    for (let i = 0; i < number_list.length; i++) {
        if (number_list[i][1] === 0) {
            return i;
        }
    }
}

function mix(mix_count = 1, multiplier = 1) {
    let number_list = read_input();
    const list_size = number_list.length;

    number_list = number_list.map(([i, n]) => [i, n * multiplier]);

    for (let count = 0; count < mix_count; count++) {
        for (let i = 0; i < list_size; i++) {
            for (let j = 0; j < list_size; j++) {
                if (number_list[j][0] === i) {
                    const num = number_list[j];
                    number_list.splice(j, 1); // Remove element at index j
                    if (num[1] === -j) {
                        number_list.push(num);
                    } else {
                        const newIndex = mod(j + num[1], list_size - 1);
                        number_list.splice(newIndex, 0, num);
                    }
                    break;
                }
            }
        }
    }

    const zi = index_of_zero(number_list);
    let sum = 0;
    for (let i = 1000; i <= 3000; i += 1000) {
        sum += number_list[(zi + i) % number_list.length][1];
    }
    return sum;
}

console.log("Part 1:", mix());
console.log("Part 2:", mix(10, 811589153));

Day 21 ToExpression[yourContentString, InputForm] Mathematica處理輸入文字並將其作為輸入程式碼

Part 1 and Part 2

ClearAll["Global`*"];
(*Step 1:Read the content of the text file as a string*)
content = Import["E:\\ExplorerDownload\\input2022_day21.txt", "Text"];

(*Step 2:Replace':' with'=' in the string*)
modifiedContent = StringReplace[content, ":" -> "="];

(*Step 3:Execute the modified string as Mathematica input*)
result = ToExpression[modifiedContent, InputForm];
Print["Part1=", root];
ClearAll["Global`*"];
(*Import the text file as a string*)
text = StringSplit[
   Import["E:\\ExplorerDownload\\input2022_day21.txt", "Text"], "\n"];

(*Perform the replacements*)
modifiedText = 
  StringReplace[
   text, {"humn: " ~~ expr1__ :> "", 
    "root: " ~~ expr1__ ~~ " + " ~~ expr2__ ~~ "" :> 
     "root = (" ~~ expr1 ~~ "==" ~~ expr2 ~~ ")", ":" -> "="}];
result = ToExpression[modifiedText, InputForm];
Solve[root, humn]

Day 22

Part 1 and Part 2

const fs = require('fs');

const x = fs.readFileSync('E:\\ExplorerDownload\\input2022_day22.txt', 'utf-8');
let [grid, ins] = x.split('\n\n');

//// Parsing ////
let gridLines = grid.split('\n');
let width = Math.max(...gridLines.map(line => line.length));
let height = gridLines.length;
gridLines = gridLines.map(line => ' ' + line.padEnd(width) + ' ');
width += 2;
height += 2;
const emptyLine = ' '.repeat(width);
gridLines = [emptyLine, ...gridLines, emptyLine];

let insList = [];
let buffer = '';
for (const c of ins.trim()) {
    if (c === 'L' || c === 'R') {
        if (buffer !== '') {
            insList.push(parseInt(buffer));
            buffer = '';
        }
        insList.push(c);
    } else {
        buffer += c;
    }
}
if (buffer !== '') {
    insList.push(parseInt(buffer));
    buffer = '';
}

//// Starting Position ////
let xPos = 1;
let yPos = 1; // Note: positions are 1-indexed due to the padding
let dir = 0;
const dirLookup = [[0, 1], [1, 0], [0, -1], [-1, 0]];
for (let j = 0; j < width; j++) {
    if (gridLines[1][j] === '.') {
        yPos = j;
        break;
    }
}
const dirCache = [xPos, yPos];

//// Part 1 ////
for (const step of insList) {
    if (step === 'R') {
        dir = (dir + 1) % 4;
    } else if (step === 'L') {
        dir = (dir + 3) % 4; // Equivalent to (dir - 1) % 4
    } else {
        let [dx, dy] = dirLookup[dir];
        for (let i = 0; i < step; i++) {
            let nx = xPos + dx;
            let ny = yPos + dy;
            if (gridLines[nx][ny] === ' ') {
                do {
                    nx -= dx;
                    ny -= dy;
                } while (gridLines[nx][ny] !== ' ');
                nx += dx;
                ny += dy;
            }
            if (gridLines[nx][ny] === '#') {
                break;
            }
            xPos = nx;
            yPos = ny;
        }
    }
}

console.log(xPos * 1000 + yPos * 4 + dir);

//// Face size (work with both input and test data, and other sizes in general) ////
let totalNonSpace = gridLines.reduce((acc, line) => acc + [...line].filter(c => c !== ' ').length, 0);
let faceSize = Math.round(Math.sqrt(Math.floor(totalNonSpace / 6)));

//// Generate initial net adjacencies ////
function posKey(x, y) {
    return x + ',' + y;
}

let Q = [dirCache];
let visited = {};
visited[posKey(...dirCache)] = [null, null, null, null];

while (Q.length > 0) {
    const v = Q.shift();
    const [x, y] = v;
    const vKey = posKey(x, y);
    for (let dir = 0; dir < 4; dir++) {
        const [dx, dy] = dirLookup[dir];
        const i = x + dx * faceSize;
        const j = y + dy * faceSize;
        if (!(0 <= i && i < height && 0 <= j && j < width)) {
            continue;
        }
        if (gridLines[i][j] === ' ') {
            continue;
        }
        const w = [i, j];
        const wKey = posKey(i, j);
        if (!(wKey in visited)) {
            visited[vKey][dir] = wKey;
            const wList = [null, null, null, null];
            wList[(dir + 2) % 4] = vKey;
            visited[wKey] = wList;
            Q.push(w);
        }
    }
}

//// Normalize face-edge mapping ////
function faceIndex(x) {
    return Math.floor((x - 1) / faceSize);
}

let faces = {};
for (const vKey in visited) {
    const [i, j] = vKey.split(',').map(Number);
    const faceKey = faceIndex(i) + ',' + faceIndex(j);
    faces[faceKey] = visited[vKey].map(wKey => {
        if (wKey === null) return null;
        const [w_i, w_j] = wKey.split(',').map(Number);
        const w_faceKey = faceIndex(w_i) + ',' + faceIndex(w_j);
        return w_faceKey;
    });
}

//// Fill in missing edge data using corners ////
function hasNullEdges(faces) {
    for (const faceKey in faces) {
        const edges = faces[faceKey];
        if (edges.some(edge => edge === null)) {
            return true;
        }
    }
    return false;
}

while (hasNullEdges(faces)) {
    for (const faceKey in faces) {
        const edges = faces[faceKey];
        for (let dir = 0; dir < 4; dir++) {
            if (edges[dir] === null) {
                for (const delta of [-1, 1]) {
                    const neighborDir = (dir + delta + 4) % 4;
                    const commonFace = edges[neighborDir];
                    if (commonFace === null) continue;
                    const commonFaceEdges = faces[commonFace];
                    const commonFaceEdge = commonFaceEdges.indexOf(faceKey);
                    const missingFaceDir = (commonFaceEdge + delta + 4) % 4;
                    const missingFace = commonFaceEdges[missingFaceDir];
                    if (missingFace === null) continue;
                    const missingFaceEdges = faces[missingFace];
                    const missingFaceEdge = missingFaceEdges.indexOf(commonFace);
                    missingFaceEdges[(missingFaceEdge + delta + 4) % 4] = faceKey;
                    edges[dir] = missingFace;
                    break;
                }
            }
        }
    }
}

//// Part 2 ////
xPos = dirCache[0];
yPos = dirCache[1];
dir = 0;
const edgeTopOffsetOut = [[1, 1], [1, faceSize], [faceSize, faceSize], [faceSize, 1]];

for (const step of insList) {
    if (step === 'R') {
        dir = (dir + 1) % 4;
    } else if (step === 'L') {
        dir = (dir + 3) % 4; // Equivalent to (dir - 1) % 4
    } else {
        let dx = dirLookup[dir][0];
        let dy = dirLookup[dir][1];
        let newDir = dir;
        for (let i = 0; i < step; i++) {
            let nx = xPos + dx;
            let ny = yPos + dy;
            if (gridLines[nx][ny] === ' ') {
                // Compute current edge properties
                const curFace = [faceIndex(xPos), faceIndex(yPos)];
                let curOffset = 0;
                while (true) {
                    const pos = [
                        curFace[0] * faceSize + edgeTopOffsetOut[(dir + 1) % 4][0] + dirLookup[(dir + 1) % 4][0] * curOffset,
                        curFace[1] * faceSize + edgeTopOffsetOut[(dir + 1) % 4][1] + dirLookup[(dir + 1) % 4][1] * curOffset,
                    ];
                    if (pos[0] === xPos && pos[1] === yPos) {
                        break;
                    }
                    curOffset += 1;
                }
                // Compute next edge properties
                const curFaceKey = curFace[0] + ',' + curFace[1];
                const nextFaceKey = faces[curFaceKey][dir];
                const nextFaceEdges = faces[nextFaceKey];
                newDir = (nextFaceEdges.indexOf(curFaceKey) + 2) % 4;
                const nextFaceIndices = nextFaceKey.split(',').map(Number);
                nx =
                    nextFaceIndices[0] * faceSize +
                    edgeTopOffsetOut[newDir][0] +
                    dirLookup[(newDir + 1) % 4][0] * curOffset;
                ny =
                    nextFaceIndices[1] * faceSize +
                    edgeTopOffsetOut[newDir][1] +
                    dirLookup[(newDir + 1) % 4][1] * curOffset;
            }
            if (gridLines[nx][ny] === '#') {
                break;
            } else {
                xPos = nx;
                yPos = ny;
                dir = newDir;
                dx = dirLookup[dir][0];
                dy = dirLookup[dir][1];
            }
        }
    }
}

console.log(xPos * 1000 + yPos * 4 + dir);

Day 23

Part 1 and Part 2

const fs = require('fs');

// Read the input file
const f = "E:\\ExplorerDownload\\input2022_day23.txt";
const s = fs.readFileSync(f, 'utf8').trim();
const lines = s.split('\n');

// Initialize the elves set
const elves = new Set();
lines.forEach((row, y) => {
    for (let x = 0; x < row.length; x++) {
        if (row[x] === '#') {
            elves.add(`${x},${y}`);
        }
    }
});

// Define directions and adjacent positions
const x8 = [
    { dx: 1, dy: 0 },
    { dx: 1, dy: 1 },
    { dx: 0, dy: 1 },
    { dx: -1, dy: 1 },
    { dx: -1, dy: 0 },
    { dx: -1, dy: -1 },
    { dx: 0, dy: -1 },
    { dx: 1, dy: -1 },
];

const dirs = [
    { dx: 0, dy: -1 }, // Up
    { dx: 0, dy: 1 },  // Down
    { dx: -1, dy: 0 }, // Left
    { dx: 1, dy: 0 },  // Right
];

// Helper functions
function parsePos(posStr) {
    const [xStr, yStr] = posStr.split(',');
    return { x: parseInt(xStr), y: parseInt(yStr) };
}

function posToStr(pos) {
    return `${pos.x},${pos.y}`;
}

function addPos(p, dir) {
    return { x: p.x + dir.dx, y: p.y + dir.dy };
}

function rotate90(dir) {
    return { dx: -dir.dy, dy: dir.dx };
}

function rotateMinus90(dir) {
    return { dx: dir.dy, dy: -dir.dx };
}

function areSetsEqual(setA, setB) {
    if (setA.size !== setB.size) return false;
    for (const elem of setA) {
        if (!setB.has(elem)) return false;
    }
    return true;
}

// Move function
function move(elves, pStr, fdir) {
    const p = parsePos(pStr);

    // Check if there are any adjacent elves
    let hasAdjacent = false;
    for (const delta of x8) {
        const newPos = { x: p.x + delta.dx, y: p.y + delta.dy };
        const newPosStr = posToStr(newPos);
        if (elves.has(newPosStr)) {
            hasAdjacent = true;
            break;
        }
    }
    if (!hasAdjacent) return pStr;

    for (let t = 0; t < 4; t++) {
        const dir = dirs[(fdir + t) % 4];
        const pos1 = addPos(p, dir);
        const rotate90d = rotate90(dir);
        const rotateMinus90d = rotateMinus90(dir);
        const pos2 = addPos(pos1, rotate90d);
        const pos3 = addPos(pos1, rotateMinus90d);
        const positionsToCheck = [pos1, pos2, pos3];
        let hasElf = false;
        for (const pos of positionsToCheck) {
            const posStr = posToStr(pos);
            if (elves.has(posStr)) {
                hasElf = true;
                break;
            }
        }
        if (!hasElf) {
            return posToStr(pos1);
        }
    }
    return pStr;
}

// Calculate empty ground tiles
function emptyGround(elves) {
    const xs = [];
    const ys = [];
    for (const posStr of elves) {
        const pos = parsePos(posStr);
        xs.push(pos.x);
        ys.push(pos.y);
    }
    const minX = Math.min(...xs);
    const maxX = Math.max(...xs);
    const minY = Math.min(...ys);
    const maxY = Math.max(...ys);
    return (maxX - minX + 1) * (maxY - minY + 1) - elves.size;
}

// Update function
function update(elves, r) {
    const want = new Map(); // Map from elf position to desired new position

    // Sort elves by y, then x
    const sortedElves = Array.from(elves).sort((aStr, bStr) => {
        const a = parsePos(aStr);
        const b = parsePos(bStr);
        if (a.y !== b.y) return a.y - b.y;
        return a.x - b.x;
    });

    for (const elfStr of sortedElves) {
        const newPosStr = move(elves, elfStr, r % 4);
        want.set(elfStr, newPosStr);
    }

    // Count how many elves want each position
    const c = new Map(); // Map from position to count
    for (const newPosStr of want.values()) {
        c.set(newPosStr, (c.get(newPosStr) || 0) + 1);
    }

    const canhave = new Set();
    for (const [elfStr, newPosStr] of want.entries()) {
        if (c.get(newPosStr) === 1) {
            canhave.add(elfStr);
        }
    }

    const canthave = new Set();
    for (const elfStr of elves) {
        if (!canhave.has(elfStr)) {
            canthave.add(elfStr);
        }
    }

    // Update elves positions
    const newElves = new Set();

    for (const elfStr of canthave) {
        newElves.add(elfStr);
    }

    for (const elfStr of canhave) {
        const newPosStr = want.get(elfStr);
        newElves.add(newPosStr);
    }

    return newElves;
}

// Main loop
let i = 0;
let pElves = null;

while (true) {
    const newElves = update(elves, i);
    if (areSetsEqual(elves, newElves)) {
        break;
    }
    elves.clear();
    for (const elfStr of newElves) {
        elves.add(elfStr);
    }
    i += 1;
    if (i === 10) {
        console.log(emptyGround(elves)); // Part 1
    }
}
console.log(i+1); // Part 2

Day 24

Part 1 and Part 2

## 測了一下,Julia程式設計方面,claude要比chatgpt要好

grid = readlines("E:\\ExplorerDownload\\input2022_day24.txt")
h, w = length(grid)-2, length(strip(grid[1]))-2

wrap(p) = Complex(mod(real(p), w), mod(imag(p), h))

dirs = Dict('x' => 0, '<' => -1, '>' => 1, '^' => -im, 'v' => im)

bliz = Dict{Char, Set{Complex{Int}}}()
for d in keys(dirs)
    bliz[d] = Set{Complex{Int}}()
    for x in 0:w-1, y in 0:h-1
        if grid[y+2][x+2] == d
            push!(bliz[d], Complex(x, y))
        end
    end
end

home, goal = Complex(0, -1), Complex(w-1, h)
todo, time, trip = [home], 0, 0

while !isempty(todo)
    # Update blizzard positions
    global bliz = Dict(d => Set(wrap(p + dirs[d]) for p in bliz[d]) for d in keys(dirs))
    
    # Calculate possible new positions
    curr = Set(p + dirs[d] for p in todo for d in keys(dirs))
    
    global todo, time, trip = [], time + 1, trip
    
    for pos in curr
        if (trip, pos) == (0, goal) || (trip, pos) == (1, home) || (trip, pos) == (2, goal)
            if trip == 0
                println(time)
            end
            if trip == 2
                println(time)
                exit()
            end
            global todo, trip = [pos], trip + 1
            break
        end
        
        if all(pos ∉ bliz[d] for d in keys(bliz)) && 
           (pos == wrap(pos) || pos in (home, goal))
            push!(todo, pos)
        end
    end
end

Day 25

Part 1

import scala.io.Source

object Main {

    def pythonMod(a: Long, b: Long): Long = ((a % b) + b) % b

    def pythonDiv(a: Long, b: Long): Long = {
    if ((a > 0 && b > 0) || (a < 0 && b < 0)) a / b
    else if (a % b == 0) a / b
    else a / b - 1
    }


  // SNAFU to decimal
  def f(s: String): Long = {
    if (s.nonEmpty) {
      val (a, b) = s.splitAt(s.length-1)
      f(a) * 5 + "=-012".indexOf(b) - 2
    } else 0
  }

  // Decimal to SNAFU
  def g(d: Long): String = {
    if (d != 0) {
      val a=pythonDiv(d+2, 5)
      val b=pythonMod(d+2, 5)

      g(a) + "=-012"(b.toInt)
    } else ""
  }

  def main(args: Array[String]): Unit = {
    val filePath = "E:\\ExplorerDownload\\input2022_day25.txt"
    try {
      val lines = Source.fromFile(filePath).getLines().toList
      val sumOfValues = lines.map(f).sum
      println(g(sumOfValues))
    } catch {
      case e: Exception => println(s"An error occurred: ${e.getMessage}")
    }
  }
}

Part 2

Day 25的Part 2在其餘所有問題解答出來後自動解鎖並透過該關卡。

相關文章