欢迎访问yhm138的博客园博客, 你可以通过 [RSS] 的方式持续关注博客更新

MyAvatar

yhm138

HelloWorld!

Advent of Code 2023 solution [Mathematica/Python/MATLAB/Rust/Scala/Javascript/Julia]

简介

"Advent of Code" 是一个在12月初至12月25日的25天里进行的编程挑战。这个活动模仿了圣诞节倒计时的"Advent Calendar",每天解锁一个新的挑战。每天的挑战题目在美国东部时间午夜(EST, UTC -5)发布。北京时间是UTC +8,所以相对于美国东部时间快了13小时。因此,"Advent of Code" 的新题目会在北京时间的每天下午1点发布。

试题地址

https://adventofcode.com/2023

Day 1

Part 1

(*读取文件*)lines = ReadList["E:\\ExplorerDownload\input.txt", String];

(*计算校准值*)
calibrationValues = 
  ToExpression[
     StringJoin[#[[1]], #[[-1]]]] & /@ (StringCases[#, 
       DigitCharacter] & /@ lines);

(*打印总和*)
Print[Total[calibrationValues]]

Part 2

import re

# 英文数字词对应的字典
word_to_num = {
    'one': 1,
    'two': 2,
    'three': 3,
    'four': 4,
    'five': 5,
    'six': 6,
    'seven': 7,
    'eight': 8,
    'nine': 9
    # ,
    # 'ten': 10,
    # 'eleven': 11,
    # 'twelve': 12,
    # 'thirteen': 13,
    # 'fourteen': 14,
    # 'fifteen': 15,
    # 'sixteen': 16,
    # 'seventeen': 17,
    # 'eighteen': 18,
    # 'nineteen': 19,
    # 'twenty': 20,
    # 'thirty': 30,
    # 'forty': 40,
    # 'fifty': 50,
    # 'sixty': 60,
    # 'seventy': 70,
    # 'eighty': 80,
    # 'ninety': 90,
    # 'hundred': 100,
    # 'thousand': 1000,
    # 'million': 1000000,
    # 'billion': 1000000000,
}

# 输入的字符串
# input_strs = [
#     'two1nine',
#     'eightwothree',
#     'abcone2threexyz',
#     'xtwone3four',
#     '4nineeightseven2',
#     'zoneight234',
#     '7pqrstsixteen'
# ]
# 从文件中读取输入的字符串
with open('input_part2.txt', 'r') as f:
    input_strs = [line.strip() for line in f]


# 抽取英文数字词和它们的位置
word_num_positions = []
for i, s in enumerate(input_strs):
    for word, num in word_to_num.items():
        for match in re.finditer(word, s):
            start, end = match.span()
            word_num_positions.append((i, start, end, word, num))

# 抽取所有的数字和它们的位置
digit_positions = []
for i, s in enumerate(input_strs):
    for match in re.finditer(r'\d', s):
        start, end = match.span()
        digit_positions.append((i, start, end, int(s[start:end])))

# 输出结果
# print('Word numbers and their positions:')
# for pos in word_num_positions:
#     print(f'String index: {pos[0]}, Start: {pos[1]}, End: {pos[2]}, Word: {pos[3]}, Number: {pos[4]}')
#
# print('\nDigits and their positions:')
# for pos in digit_positions:
#     print(f'String index: {pos[0]}, Start: {pos[1]}, End: {pos[2]}, Digit: {pos[3]}')

# for [StringIndex, Start, End, Word, Number] in word_num_positions:
#     print(f"{StringIndex=} {Start=} {End=} {Number=}")
# for [StringIndex, Start, End, Digit] in digit_positions:
#     print(f"{StringIndex=} {Start=} {End=} {Digit=}")

# 英文数字词和数字的位置
word_num_positions.sort()
digit_positions.sort()

# 创建存储每个StringIndex最小Start和最大End的字典
start_dict = {}
end_dict = {}

# 找到每个StringIndex的最小Start
for i, s, e, w, n in word_num_positions:
    if i in start_dict:
        start_dict[i] = min(start_dict[i], (s, n))
    else:
        start_dict[i] = (s, n)

for i, s, e, d in digit_positions:
    if i in start_dict:
        start_dict[i] = min(start_dict[i], (s, d))
    else:
        start_dict[i] = (s, d)

# 找到每个StringIndex的最大End
for i, s, e, w, n in word_num_positions[::-1]:
    if i in end_dict:
        end_dict[i] = max(end_dict[i], (e, n))
    else:
        end_dict[i] = (e, n)

for i, s, e, d in digit_positions[::-1]:
    if i in end_dict:
        end_dict[i] = max(end_dict[i], (e, d))
    else:
        end_dict[i] = (e, d)

# 输出每个StringIndex的二位数
total=0
for i in range(len(input_strs)):
    start_num = start_dict.get(i, (None, 0))[1]
    end_num = end_dict.get(i, (None, 0))[1]
    total+=(start_num * 10 + end_num)
    print(f'String index: {i}, Number: {start_num * 10 + end_num}')
print(f"{total=}")

Day2

Part 1

(*(*Define the \
games*)games={{1,{{"blue",3},{"red",4}},{{"red",1},{"green",2},{\
"blue",6}},{{"green",2}}},{2,{{"blue",1},{"green",2}},{{"green",3},{\
"blue",4},{"red",1}},{{"green",1},{"blue",1}}},{3,{{"green",8},{\
"blue",6},{"red",20}},{{"blue",5},{"red",4},{"green",13}},{{"green",5}\
,{"red",1}}},{4,{{"green",1},{"red",3},{"blue",6}},{{"green",3},{\
"red",6}},{{"green",3},{"blue",15},{"red",14}}},{5,{{"red",6},{"blue",\
1},{"green",3}},{{"blue",2},{"red",1},{"green",2}}}};*)

(*Read the input file*)
gamesList = ReadList["/Users/yhm138/Downloads/input.txt", String];

(*Function to parse a game*)

parseGame[s_String] := 
 Module[{id, rounds, parsedRounds}, {id, rounds} = 
   StringSplit[s, ": "];
  id = ToExpression[StringReplace[id, {"Game" -> ""}]];
  rounds = StringSplit[rounds, ";"];
  parsedRounds = 
   Map[StringCases[#, 
      n : NumberString ~~ " " ~~ 
        color : ("red" | "green" | "blue") :> {color, 
        ToExpression[n]}] &, rounds];
  Prepend[parsedRounds, id]]
(*Parse each game*)
games = parseGame /@ gamesList;
Print[games]


(*Define the available cubes*)

availableCubes = <|"red" -> 12, "green" -> 13, "blue" -> 14|>;

(*Check each game*)possibleGames = {};
For[i = 1, i <= Length[games], i++, game = games[[i]];
  gameID = game[[1]];
  (*Initialize cubes for each game*)
  cubes = <|"red" -> 0, "green" -> 0, "blue" -> 0|>;
  possible = True;
  (*Check each round in the game*)
  For[j = 2, j <= Length[game], j++, round = game[[j]];
   (*Initialize cubes for each round*)
   cubes = <|"red" -> 0, "green" -> 0, "blue" -> 0|>;
   (*Check each item in the round*)
   For[k = 1, k <= Length[round], k++, item = round[[k]];
    color = item[[1]];
    number = item[[2]];
    If[cubes[color] + number <= availableCubes[color], 
     cubes[color] += number, possible = False;
     Break[];];];
   (*If a round is not possible,break the outer loop as well*)
   If[Not[possible], Break[]];];
  If[possible, AppendTo[possibleGames, gameID]];];

Print[possibleGames]
(*Sum the IDs of the possible games*)
sumOfIDs = Total[possibleGames]

Part 2

(*(*Define the \
games*)games={{1,{{"blue",3},{"red",4}},{{"red",1},{"green",2},{\
"blue",6}},{{"green",2}}},{2,{{"blue",1},{"green",2}},{{"green",3},{\
"blue",4},{"red",1}},{{"green",1},{"blue",1}}},{3,{{"green",8},{\
"blue",6},{"red",20}},{{"blue",5},{"red",4},{"green",13}},{{"green",5}\
,{"red",1}}},{4,{{"green",1},{"red",3},{"blue",6}},{{"green",3},{\
"red",6}},{{"green",3},{"blue",15},{"red",14}}},{5,{{"red",6},{"blue",\
1},{"green",3}},{{"blue",2},{"red",1},{"green",2}}}};*)

(*Read the input file*)
gamesList = ReadList["/Users/yhm138/Downloads/input.txt", String];

(*Function to parse a game*)

parseGame[s_String] := 
 Module[{id, rounds, parsedRounds}, {id, rounds} = 
   StringSplit[s, ": "];
  id = ToExpression[StringReplace[id, {"Game" -> ""}]];
  rounds = StringSplit[rounds, ";"];
  parsedRounds = 
   Map[StringCases[#, 
      n : NumberString ~~ " " ~~ 
        color : ("red" | "green" | "blue") :> {color, 
        ToExpression[n]}] &, rounds];
  Prepend[parsedRounds, id]]
(*Parse each game*)
games = parseGame /@ gamesList;
Print[games]


(*Check each game*)totalPower = 0;
For[i = 1, i <= Length[games], i++, game = games[[i]];
  gameID = game[[1]];
  cubesNeeded = <|"red" -> 0, "green" -> 0, "blue" -> 0|>;
  (*Check each round in the game*)
  For[j = 2, j <= Length[game], j++, round = game[[j]];
   (*Check each item in the round and update the cubesNeeded*)
   For[k = 1, k <= Length[round], k++, item = round[[k]];
    color = item[[1]];
    number = item[[2]];
    cubesNeeded[color] = Max[cubesNeeded[color], number];];];
  (*Remove colors that are not needed for this game*)
  cubesNeeded = DeleteCases[cubesNeeded, 0];
  (*Calculate the power for this game*)
  power = Times @@ Values[cubesNeeded];
  If[power > 0, totalPower += power];];

totalPower

Day 3

Part 1

def calculate_sum(schematic):
    import string

    # 所有的ASCII字符
    all_chars = string.printable

    # 过滤掉'.'和数码
    symbols = [char for char in all_chars if not char.isdigit() and char != '.']
    total = 0

    # Convert schematic into a list of lists for easier processing
    schematic = [list(row) for row in schematic]

    # Get the dimensions of the schematic
    rows, cols = len(schematic), len(schematic[0])
    directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)]

    # Iterate over each cell in the schematic
    for i in range(rows):
        for j in range(cols):
            # If the cell is a number and it's not the continuation of a number
            if schematic[i][j].isdigit() and (j == 0 or not schematic[i][j-1].isdigit()):
                # Find the end of the number
                k = j
                while k < cols and schematic[i][k].isdigit():
                    k += 1
                number = int(''.join(schematic[i][j:k]))

                # Check all surrounding cells of the number for a symbol
                has_symbol = False
                for x in range(j, k):
                    for dx, dy in directions:
                        ni, nj = i + dx, x + dy
                        # If the surrounding cell exists and is a symbol
                        if 0 <= ni < rows and 0 <= nj < cols and schematic[ni][nj] in symbols:
                            has_symbol = True
                            break
                    if has_symbol:
                        break

                if has_symbol:
                    total += number

    return total

with open('/Users/yhm138/Downloads/input_day3.txt', 'r') as file:
    schematic = [line.strip() for line in file.readlines()]

print(calculate_sum(schematic))

Part 2

# import os
# import re

INPUT_DIR = "/Users/yhm138/Downloads/input_day3.txt"
DIRECTIONS = [(0,1), (1,0), (0,-1), (-1,0), (-1,-1), (-1,1), (1,-1), (1,1)]
numbers_adjacent_to_gears = {}

def check_bounds(x, y, r, c):
    return x >= 0 and x < r and y >= 0 and y < c

def can_pick(x, y, grid):
    return grid[x][y] != '.' and not grid[x][y].isdigit()

def is_valid(i, start, end, grid):
    r = len(grid)
    c = len(grid[0])
    for j in range(start, end+1):
        for d in DIRECTIONS:
            next_x = i + d[0]
            next_y = j + d[1]
            if check_bounds(next_x, next_y, r, c) and can_pick(next_x, next_y, grid):
                if grid[next_x][next_y] == '*':
                    key = next_x * c + next_y
                    val = int(grid[i][start:end+1])
                    if key not in numbers_adjacent_to_gears:
                        numbers_adjacent_to_gears[key] = []
                    numbers_adjacent_to_gears[key].append(val)
                return True
    return False

def get_sum_of_parts(grid):
    r = len(grid)
    c = len(grid[0])
    ans = 0
    for i in range(r):
        token = ""
        for j in range(c):
            if token and not grid[i][j].isdigit():
                start = j - len(token)
                if is_valid(i, start, j - 1, grid):
                    ans += int(token)
                token = ""
            if grid[i][j].isdigit():
                token += grid[i][j]
        if token:
            if is_valid(i, c - len(token), c - 1, grid):
                ans += int(token)
    return ans

def main():
    with open(INPUT_DIR, 'r') as file:
        grid = [line.strip() for line in file]
    ans = get_sum_of_parts(grid)
    ans_2 = 0
    for values in numbers_adjacent_to_gears.values():
        if len(values) == 2:
            ans_2 += (values[0] * values[1])
    print("Ans Part 1 = ", ans)
    print("Ans Part 2 = ", ans_2)

if __name__ == "__main__":
    main()

Day 4

Part 1

def calculate_points(cards):
    total_points = 0

    for card in cards:
        # Skip lines that don't contain ':'
        if ':' not in card:
            continue

        # Split the line by ':' and use the second part
        card = card.split(':')[1]

        card = card.split('|')
        winning_numbers = list(map(int, card[0].strip().split()))
        card_numbers = list(map(int, card[1].strip().split()))

        matches = len(set(winning_numbers) & set(card_numbers))
        if matches > 0:
            points = 1<<(matches-1)
            total_points += points

    return total_points

# Read the cards from a file
with open('E:\\ExplorerDownload\input_day4.txt', 'r') as file:
    cards = file.readlines()

# Calculate the total points
total_points = calculate_points(cards)

print(f"The total points of the cards are {total_points}")

Part 2

clear all;close all;clc;


fileID = fopen('E:\\ExplorerDownload\input_day4.txt','r');
formatSpec = '%s';
lines = textscan(fileID, formatSpec, 'Delimiter', '\n');
fclose(fileID);

cards = struct('winning', {}, 'numbers', {}, 'count', {});

for i = 1:length(lines{1})
    line = lines{1}{i};
    parts = split(line, '|');
    winningNumbers = str2double(split(parts{1}, ' '));
    cardNumbers = str2double(split(parts{2}, ' '));
    cards(i) = struct('winning', winningNumbers, 'numbers', cardNumbers, 'count', 1);
end

format longG;
Ans_Part2 = solve2(cards)


%% solve2
function result = solve2(cards)
for i = 1:length(cards)
    card = cards(i);
    matching = intersect(card.winning, card.numbers);
    
    for j = 1:card.count
        for k = i+1:min(i+length(matching), length(cards))
            cards(k).count = cards(k).count + 1;
        end
    end
end

result = sum([cards.count]);
end

Day 5

Part 1 and Part 2

use std::fs;
use std::str::FromStr;
use std::cmp::{min, max};

struct Function {
    tuples: Vec<(i64, i64, i64)>,  // changed from i32 to i64
}

impl Function {
    fn new(s: &str) -> Self {
        let lines: Vec<&str> = s.lines().collect();
        let tuples: Vec<(i64, i64, i64)> = lines[1..].iter()  // skip the first line
            .map(|line| {
                let parts: Vec<i64> = line.split_whitespace()
                    .map(|x| i64::from_str(x).unwrap())  // changed from i32 to i64
                    .collect();
                (parts[0], parts[1], parts[2])
            })
            .collect();
        Function { tuples }
    }

    fn apply_one(&self, x: i64) -> i64 {  // changed from i32 to i64
        for (dst, src, sz) in &self.tuples {
            if *src <= x && x < *src + *sz {
                return x + dst - src;
            }
        }
        x
    }

    fn apply_range(&self, mut R: Vec<(i64, i64)>) -> Vec<(i64, i64)> {  // changed from i32 to i64
        let mut A = Vec::new();
        for (dest, src, sz) in &self.tuples {
            let src_end = *src + *sz;
            let mut NR = Vec::new();
            while let Some((st, ed)) = R.pop() {
                let before = (st, min(ed, *src));
                let inter = (max(st, *src), min(src_end, ed));
                let after = (max(src_end, st), ed);
                if before.1 > before.0 {
                    NR.push(before);
                }
                if inter.1 > inter.0 {
                    A.push((inter.0 - src + dest, inter.1 - src + dest));
                }
                if after.1 > after.0 {
                    NR.push(after);
                }
            }
            R = NR;
        }
        A.append(&mut R);
        A
    }
}

fn main() {
    let data = fs::read_to_string("E:\\ExplorerDownload\\input_day5.txt")
        .expect("Unable to read file");
    let parts: Vec<&str> = data.split("\n\n").collect();
    let seed: Vec<i64> = parts[0].split(':').nth(1).unwrap()
        .split_whitespace()
        .map(|x| i64::from_str(x).unwrap())  // changed from i32 to i64
        .collect();
    let functions: Vec<Function> = parts[1..].iter()
        .map(|s| Function::new(s))
        .collect();

    let mut P1 = Vec::new();
    for x in &seed {
        let mut y = *x;
        for f in &functions {
            y = f.apply_one(y);
        }
        P1.push(y);
    }
    println!("{}", P1.iter().min().unwrap());

    let mut P2 = Vec::new();
    let pairs = seed.chunks(2);
    for pair in pairs {
        let st = pair[0];
        let sz = pair[1];
        let mut R = vec![(st, st+sz)];
        for f in &functions {
            R = f.apply_range(R);
        }
        P2.push(R.iter().map(|(s, _)| *s).min().unwrap());
    }
    println!("{}", P2.iter().min().unwrap());
}

Day 6

Part 1 and Part 2

Clear["Global`*"];
(*Define a function to calculate distance*)
calculateDistance[held_, remaining_] := held*remaining

(*Define a function to get number of wins*)
getWins[time_, record_] := 
 Length[Select[Range[0, time], 
   calculateDistance[#, time - #] > record &]]

(*Read the file and process data*)
filePath = "E:\\ExplorerDownload\\input_day6.txt";
lines = ReadList[filePath, "String"];

(*Extract times and records from the lines*)
times = ToExpression /@ 
   StringSplit[StringReplace[lines[[1]], "Time:" -> ""], Whitespace];
records = 
  ToExpression /@ 
   StringSplit[StringReplace[lines[[2]], "Distance:" -> ""], 
    Whitespace];

(*Part One*)
races = Transpose[{times, records}];
numWays = getWins[#[[1]], #[[2]]] & /@ races;
result = Times @@ numWays;
Print["Part 1: ", result]

(*Part Two*)
time = ToExpression[StringJoin[Riffle[ToString /@ times, ""]]];
record = ToExpression[StringJoin[Riffle[ToString /@ records, ""]]];
wins = getWins[time, record];
Print["Part 2: ", wins]

Day 7

Part 1 and Part 2

import scala.io.Source
import scala.collection.mutable

object Main extends App{
  val D = Source.fromFile("E:\\ExplorerDownload\\input_day7.txt").mkString.stripLineEnd
  val L = D.split('\n')

  def strength(hand: String, part2: Boolean): (Int, String) = {
    val hand1 = hand.replace('T', ('9'.toInt + 1).toChar)
    val hand2 = if (part2) hand1.replace('J', ('2'.toInt - 1).toChar) else hand1.replace('J', ('9'.toInt + 2).toChar)
    val hand3 = hand2.replace('Q', ('9'.toInt + 3).toChar)
    val hand4 = hand3.replace('K', ('9'.toInt + 4).toChar)
    val hand5 = hand4.replace('A', ('9'.toInt + 5).toChar)

    val C = mutable.Map[Char, Int]().withDefaultValue(0)
    hand5.foreach(c => C(c) += 1)

    if (part2) {
      val filteredKeys = C.keys.filter(_ != '1')
      if (filteredKeys.nonEmpty) {
        val target = filteredKeys.maxBy(C)
        if (C.contains('1') && target != '1') {
          C(target) += C('1')
          C -= '1'
        }
      }
    }

    val countValues = C.values.toSeq.sorted
    if (countValues == Seq(5)) {
      (10, hand5)
    } else if (countValues == Seq(1, 4)) {
      (9, hand5)
    } else if (countValues == Seq(2, 3)) {
      (8, hand5)
    } else if (countValues == Seq(1, 1, 3)) {
      (7, hand5)
    } else if (countValues == Seq(1, 2, 2)) {
      (6, hand5)
    } else if (countValues == Seq(1, 1, 1, 2)) {
      (5, hand5)
    } else if (countValues == Seq(1, 1, 1, 1, 1)) {
      (4, hand5)
    } else {
      throw new Exception(s"Invalid counts: $C, $hand5, $countValues")
    }
  }

  for (part2 <- Seq(false, true)) {
    val H = L.map { line =>
      val Array(hand, bid) = line.split(" ")
      (hand, bid.toInt)
    }.toSeq

    val sortedH = H.sortBy(hb => strength(hb._1, part2))
    val ans = sortedH.zipWithIndex.map { case ((_, bid), i) => (i + 1) * bid }.sum
    println(ans)
  }
}

Day 8

Part 1 and Part 2

clear all;close all;clc;

% LLRLRRRLLLRLRRLRRRLRLRRLRLRLRRRLRRRLRLRLRRLLRRRLRRLRRLLRLRRRLRLRLLRRRLLRRRLRLRRRLRRRLRRRLLLRRRLRRLRRLRLRRLRLRRRLRLRRLRLRLRRRLRLLLRRRLLLRLRRRLRLRRLRLRLRLRRLRRLRRLRLRRRLRRRLRRLRRRLRRLRRLRRRLLRLRRLLLRRLRRLRLRLLLRRLRRLRRRLRRLLRLRRRLRRRLRRLRRLRLRRLRLRRRLRRLRRRLLRRRLRLRLLLRRRLLLRRLLRRLRLRRLRLLLRRRR
% 
% BNR = (DLB, QNM)
% CTN = (NVJ, DRS)
% VHS = (XDL, LVL)
% MLQ = (VXK, CJK)
% CNX = (CTN, DRK)
% ...

% load data
fid = fopen('E:\ExplorerDownload\input_day8.txt', 'r');
data = textscan(fid, '%s', 'Delimiter', '\n');
fclose(fid);
instructions = char(data{1}{1});
connections = data{1}(3:end); % Get the connections starting from the 3rd line

% create connections map
conn = containers.Map();
for i = 1:length(connections)
    l = (connections(i));
    splitLine = split(l, ' = '); % Split based on ' = '
    a = splitLine{1};
    b_c = split(splitLine{2}, ', '); % Further split the second part based on ', '
    b = strtrim(strtok(b_c{1}, '(')); % Remove the opening parentheses
    c = strtrim(strtok(b_c{2}, ')')); % Remove the closing parentheses
    conn(a) = {b, c};
end

% After creating conn
% disp('Keys:');
% disp(keys(conn));


% Part 1
pos = 'AAA';
idx = 0;
while ~strcmp(pos, 'ZZZ')
    d = instructions(mod(idx, length(instructions)) + 1);
    % After creating conn
    %     disp('Keys:');
    %     disp(keys(conn));
    
    % Before accessing conn
    %     disp(['Accessing key: ', pos]);
    conn_pos=conn(pos);
    pos = conn_pos{1 + strcmp(d, 'R')};
    idx = idx + 1;
end
disp(['p1 ', num2str(idx)])

% Part 2
solvesteps = @(start) steps_to_end(conn, instructions, start);
starts = keys(conn);
ret = 1;
for i = 1:length(starts)
    if endsWith(starts{i}, 'A')
        ret = lcm(ret, solvesteps(starts{i}));
    end
end
disp(['p2 ', num2str(ret)])

%% steps_to_end Function
function steps = steps_to_end(conn, instructions, start)
pos = start;
steps = 0;
while ~endsWith(pos, 'Z')
    d = instructions(mod(steps, length(instructions)) + 1);
    conn_pos = conn(pos);
    pos = conn_pos{1 + strcmp(d, 'R')};
    steps = steps + 1;
end
end

Day 9

Part 1 and Part 2

(*Define the recursive function n*)
n[l_List] := 
  Module[{m, nonzeroElements}, nonzeroElements = Select[l, # != 0 &];
   If[Length[nonzeroElements] == 0, 0, m = Differences[l];
    Last[l] + n[m]]];

(*Read the list of lists from the file'input'*)

inputData = 
  Import["/Users/yhm138/Downloads/input_day9.txt", "Table"];

(*Apply the function n to each list and sum the results*)

sumDirect = Total[n /@ inputData];

(*Apply the function n to the reversed list and sum the results*)

sumReversed = Total[n /@ Reverse /@ inputData];

{sumDirect, sumReversed}

Day 10

Part 1 and Part 2

可以直接 node day10.js运行

const fs = require('fs');

let inp = fs.readFileSync('E:\\\\ExplorerDownload/input_day10_mine.txt', 'utf8').split(/\s+/);

const width = inp[0].length;
const height = inp.length;

let data = inp.join('');

const dmap = {
    'S': [],
    '|': [width, -width],
    '-': [-1, 1],
    '.': [],
    '7': [-1, width],
    'L': [1, -width],
    'J': [-1, -width],
    'F': [1, width]
};

let start = data.indexOf('S');
let path = new Set([start]);
data = [...data].map(c => dmap[c]);

for (let i = 0; i < data.length; i++) {
    let offsets = data[i];
    if (offsets.some(o => start === i + o)) {
        dmap['S'].push(i - start);
    }
}

let dist = 0;
let new_ = null;
while (true) {
    let new2 = new_;
    new_ = new Set();
    let paths = new2 || path;
    paths.forEach(p => {
        data[p].forEach(offset => {
            if (!path.has(p + offset)) {
                new_.add(p + offset);
            }
        });
    });

    if (new_.size) {
        new_.forEach(p => path.add(p));
        dist += 1;
    } else {
        break;
    }
}

console.log('Part 1:', dist);

let inside = 0;
for (let i = 0; i < data.length; i++) {
    if (path.has(i)) {
        continue;
    }
    let outside_right = true;
    let outside_left = true;
    let j = i;
    while (j > 0) {
        if (path.has(j) && data[j].includes(1)) {
            outside_right = !outside_right;
        }
        if (path.has(j) && data[j].includes(-1)) {
            outside_left = !outside_left;
        }
        j -= width;
    }

    if (!(outside_right || outside_left)) {
        inside++;
    }
}

console.log('Part 2:', inside);

Day 11

Part 1 and Part 2

clear all;close all;clc;
fileID = fopen('E:\\ExplorerDownload\\input_day11.txt', 'r');
grid = [];
line = fgetl(fileID);
while ischar(line)
    grid = [grid; line];
    line = fgetl(fileID);
end
fclose(fileID);
if ~ischar(grid)
    grid = char(grid);
end
[ys, xs] = find(grid' == '#');
ys=ys.'-1; %offset for 1-index and 0-index
xs=xs.'-1; %offset for 1-index and 0-index

global l;
% Compute the sum for the given lengths
for l = [2, 1000000]
    fprintf('%d\n', sum(dist(xs)) + sum(dist(ys)) );
end

% Define the dist function
function distance_sum = dist(points)
    global l;
    modified_points = zeros(size(points));
    for idx = 1:length(points)
        modified_value = 0;
        for point = 1:points(idx)
            if any(points == point)
                modified_value = modified_value + 1;
            else
                modified_value = modified_value + l; % This should be changed to the correct logic
            end
        end
        modified_points(idx) = modified_value;
    end
    % Calculate the pairwise absolute difference and return the sum of those differences
    distance_sum = 0;
    for i = 1:length(modified_points)
        for j = i+1:length(modified_points)
            distance_sum = distance_sum + abs(modified_points(i) - modified_points(j));
        end
    end
end

Day 12

Part 1 and Part 2

const fs = require('fs');

// Simple cache implementation
const cache = new Map();

function cacheKey(lava, springs) {
    return `${lava}-${springs.join(',')}`;
}

function recurse(lava, springs, result = 0) {
    const key = cacheKey(lava, springs);
    if (cache.has(key)) {
        return cache.get(key);
    }
    
    if (springs.length === 0) {
        result = lava.includes('#') ? 0 : 1;
        cache.set(key, result);
        return result;
    }

    let current = springs[0];
    let nextSprings = springs.slice(1);
    for (let i = 0; i <= lava.length - nextSprings.reduce((a, b) => a + b, 0) - nextSprings.length - current; i++) {
        if (lava.substring(0, i).includes('#')) {
            break;
        }
        let next = i + current;
        if (next <= lava.length && !lava.substring(i, next).includes('.') && lava.substring(next, next + 1) !== '#') {
            result += recurse(lava.substring(next + 1), nextSprings);
        }
    }
    
    cache.set(key, result);
    return result;
}

fs.readFile("E:\\ExplorerDownload\\input_day12.txt", "utf8", (err, data) => {
    if (err) throw err;
    
    const lines = data.split('\n');
    let p1 = 0, p2 = 0;
    for (let line of lines) {
        let parts = line.split(/\s+/);
        if (parts.length < 2) continue;
        let lava = parts[0];
        let springs = parts[1].split(',').map(Number);
        
        p1 += recurse(lava, springs);

        // Correctly repeat the lava string and springs array for part 2
        let extendedLava = Array(5).fill(lava).join('?');
        let extendedSprings = Array(5).fill(springs).flat();
        
        p2 += recurse(extendedLava, extendedSprings);
    }
    
    console.log(`${p1}\n${p2}`);
});

Day 13

Part 1 and Part 2

const fs = require('fs');

const D = fs.readFileSync("E:\\ExplorerDownload\\input_day13.txt", {
		encoding: 'utf8',
		flag: 'r'
	})
	.trim();
const L = D.split('\n');
const G = L.map(row => [...row]);

const processGrid = (D, part2) => {
	let ans = 0;

	const grids = D.split('\n\n');
	for (const grid of grids) {
		const G = grid.split('\n')
			.map(row => [...row]);
		const R = G.length;
		const C = G[0].length;

		// vertical symmetry
		for (let c = 0; c < C - 1; c++) {
			let badness = 0;
			for (let dc = 0; dc < C; dc++) {
				const left = c - dc;
				const right = c + 1 + dc;
				if (0 <= left && left < right && right < C) {
					for (let r = 0; r < R; r++) {
						if (G[r][left] !== G[r][right]) {
							badness += 1;
						}
					}
				}
			}
			if (badness === (part2 ? 1 : 0)) {
				ans += c + 1;
			}
		}

		// horizontal symmetry
		for (let r = 0; r < R - 1; r++) {
			let badness = 0;
			for (let dr = 0; dr < R; dr++) {
				const up = r - dr;
				const down = r + 1 + dr;
				if (0 <= up && up < down && down < R) {
					for (let c = 0; c < C; c++) {
						if (G[up][c] !== G[down][c]) {
							badness += 1;
						}
					}
				}
			}
			if (badness === (part2 ? 1 : 0)) {
				ans += 100 * (r + 1);
			}
		}
	}

	return ans;
};

console.log(processGrid(D, false));
console.log(processGrid(D, true));

Day 14

Part 1 and Part 2

import scala.io.Source
import java.nio.file.{Paths, Files}
import java.util.concurrent.TimeUnit

object AdventOfCode2023Day14 extends App {
  val inputPath = Paths.get("E://ExplorerDownload/input_day14.txt")
  val lines = Files.readAllLines(inputPath).toArray(Array[String]())
  val width = lines(0).length
  val height = lines.length

  // Part 1
  var startTime = System.nanoTime()
  var map = createMap(lines)
  var result = computeLoad(tiltNorth(map))

  println(s"Result part 1 : $result in ${TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)}ms")

  // Part 2
  startTime = System.nanoTime()
  map = createMap(lines)

  val index = scala.collection.mutable.Map[String, Long]()

  var i=0L;
  while (i < 1000000000L) {
    map = cycle(map)
    val str = toString(map)
    if (index.contains(str)) {
      val delta = i - index(str)
      i += delta * ((1000000000L - i) / delta)
    }
    index.put(str, i)
    i=i+1;
  }
  result = computeLoad(map)

  println(s"Result part 2 : $result in ${TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)}ms")

  def computeLoad(map: Array[Array[Char]]): Long = {
    var result = 0L
    for (x <- 0 until width; y <- 0 until height) {
      if (map(x)(y) == 'O') {
        result += height - y
      }
    }
    result
  }

  def toString(map: Array[Array[Char]]): String = {
    map.map(new String(_)).mkString
  }

  def rotate(map: Array[Array[Char]]): Array[Array[Char]] = {
    Array.tabulate(height, width)((x, y) => map(y)(height - x - 1))
  }

  def cycle(map: Array[Array[Char]]): Array[Array[Char]] = {
    (0 until 4).foldLeft(map)((acc, _) => rotate(tiltNorth(acc)))
  }

  def createMap(lines: Array[String]): Array[Array[Char]] = {
    Array.tabulate(width, height)((x, y) => lines(y)(x))
  }

  def tiltNorth(map: Array[Array[Char]]): Array[Array[Char]] = {
    for (x <- 0 until width) {
      var move = true
      while (move) {
        move = false
        for (y <- 1 until height) {
          if (map(x)(y) == 'O' && map(x)(y - 1) == '.') {
            map(x)(y) = '.'
            map(x)(y - 1) = 'O'
            move = true
          }
        }
      }
    }
    map
  }

  def dump(map: Array[Array[Char]]): Unit = {
    map.transpose.foreach { row =>
      println(row.mkString)
    }
  }
}

Day 15

Part 1 and Part 2

直接 scala AdventOfCode2023Day15.scala 运行就可以。

import scala.io.Source
import scala.collection.mutable

object AdventOfCode2023Day15 {
  def main(args: Array[String]): Unit = {
    val ll = Source.fromFile("E:\\ExplorerDownload\\input_day15.txt").getLines().mkString.trim().split(',')
    var p1 = 0
    var p2 = 0

    def hash(l: String): Int = {
      var v = 0
      for (ch <- l) {
        v += ch.toInt
        v *= 17
        v %= 256
      }
      v
    }

    val lenses = Array.fill[mutable.ListBuffer[String]](256)(mutable.ListBuffer[String]())
    val lenslengths = Array.fill[mutable.HashMap[String, Int]](256)(mutable.HashMap[String, Int]())

    for ((l, i) <- ll.zipWithIndex) {
      p1 += hash(l)
      val parts = l.split("=")
      val label = parts(0).split("-")(0)
      val v = hash(label)
      if (l.contains("-")) {
        lenses(v) -= label
      }
      if (l.contains("=")) {
        if (!lenses(v).contains(label)) {
          lenses(v) += label
        }
        lenslengths(v)(label) = parts(1).toInt
      }
    }

    for ((lns, box) <- lenses.zipWithIndex) {
      for ((lens, i) <- lns.zipWithIndex) {
        p2 += (box + 1) * (i + 1) * lenslengths(box)(lens)
      }
    }

    println(s"$p1\n$p2")
  }
}

Day 16

Part 1 and Part 2

object AdventOfCode2023Day16 {
  val D = scala.io.Source.fromFile("E:\\ExplorerDownload\\input_day16.txt").getLines.mkString("\n").trim
  val L = D.split('\n')
  val G = L.map(_.toArray).toArray

  val R = G.length
  val C = G(0).length

  val DR = Array(-1, 0, 1, 0)
  val DC = Array(0, 1, 0, -1)

  def step(r: Int, c: Int, d: Int): (Int, Int, Int) = {
    (r + DR(d), c + DC(d), d)
  }

  def score(sr: Int, sc: Int, sd: Int): Int = {
    var pos = List((sr, sc, sd))
    val seen = scala.collection.mutable.Set[(Int, Int)]()
    val seen2 = scala.collection.mutable.Set[(Int, Int, Int)]()
    while (pos.nonEmpty) {
      val np = scala.collection.mutable.ListBuffer[(Int, Int, Int)]()
      for ((r, c, d) <- pos) {
        if (r >= 0 && r < R && c >= 0 && c < C) {
          seen.add((r, c))
          if (!seen2.contains((r, c, d))) {
            seen2.add((r, c, d))
            G(r)(c) match {
              case '.' => np.append(step(r, c, d))
              case '/' => np.append(step(r, c, Map(0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2)(d)))
              case '\\' => np.append(step(r, c, Map(0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0)(d)))
              case '|' =>
                if (Array(0, 2).contains(d)) np.append(step(r, c, d))
                else {
                  np.append(step(r, c, 0))
                  np.append(step(r, c, 2))
                }
              case '-' =>
                if (Array(1, 3).contains(d)) np.append(step(r, c, d))
                else {
                  np.append(step(r, c, 1))
                  np.append(step(r, c, 3))
                }
              case _ => assert(false)
            }
          }
        }
      }
      pos = np.toList
    }
    seen.size
  }

  def main(args: Array[String]): Unit = {
    println(score(0, 0, 1))
    var ans = 0
    for (r <- 0 until R) {
      ans = ans max score(r, 0, 1)
      ans = ans max score(r, C - 1, 3)
    }
    for (c <- 0 until C) {
      ans = ans max score(0, c, 2)
      ans = ans max score(R - 1, c, 0)
    }
    println(ans)
  }
}

Day 17

Part 1 and Part 2

import scala.io.Source
import scala.collection.mutable

object AdventOfCode2023Day17 {
  val filePath = "E:\\ExplorerDownload\\input_day17.txt"
  val lines = Source.fromFile(filePath).getLines().toList
  val grid = lines.map(_.toArray)
  val rows = grid.length
  val cols = grid.headOption.getOrElse(Array.emptyCharArray).length

  case class State(dist: Int, r: Int, c: Int, dir: Int, indir: Int)
  implicit val stateOrdering: Ordering[State] = Ordering.by(-_.dist)

  def solve(part2: Boolean): Int = {
    val queue = mutable.PriorityQueue[State](State(0, 0, 0, -1, -1))
    val visited = mutable.Map[(Int, Int, Int, Int), Int]()

    while (queue.nonEmpty) {
      val State(dist, r, c, dir, indir) = queue.dequeue()
      if (!visited.contains((r, c, dir, indir)) || dist < visited((r, c, dir, indir))) {
        visited((r, c, dir, indir)) = dist

        val directions = List((-1, 0), (0, 1), (1, 0), (0, -1))

        for (((dr, dc), i) <- directions.zipWithIndex) {
          val rr = r + dr
          val cc = c + dc
          val newDir = i
          val newIndir = if (newDir != dir) 1 else indir + 1

          val isntReverse = (newDir + 2) % 4 != dir

          val isValidPart1 = newIndir <= 3
          val isValidPart2 = newIndir <= 10 && (newDir == dir || indir >= 4 || indir == -1)
          val isValid = if (part2) isValidPart2 else isValidPart1

          if (0 <= rr && rr < rows && 0 <= cc && cc < cols && isntReverse && isValid) {
            val cost = grid(rr)(cc).asDigit
            if (!visited.contains((rr, cc, newDir, newIndir))) {
              queue.enqueue(State(dist + cost, rr, cc, newDir, newIndir))
            }
          }
        }
      }
    }

    visited.filterKeys { case (r, c, dir, indir) =>
      r == rows - 1 && c == cols - 1 && (indir >= 4 || !part2)
    }.values.minOption.getOrElse(Int.MaxValue)
  }

  def main(args: Array[String]): Unit = {
    println(solve(part2 = false))
    println(solve(part2 = true))
  }
}

Day 18

Part 1 and Part 2

clear all;close all;clc;
inputPath = 'E:\ExplorerDownload\input_day18.txt';
input = regexp(fileread(inputPath), '\r?\n', 'split');
input = input(~cellfun('isempty', input));

%% Part 1
directions = containers.Map({'R', 'D', 'L', 'U'}, {[0, 1]; [1, 0]; [0, -1]; [-1, 0]});
instructions = cellfun(@(line) strsplit(line, ' '), input, 'UniformOutput', false);
instructions = cellfun(@(inst) {str2double(inst{2}), directions(inst{1})}, instructions, 'UniformOutput', false);
trench = [0, 0];
for i = 1:length(instructions)
    trench = [trench; trench(end, :) + instructions{i}{1} * instructions{i}{2}];
end
polyshapeTrench = polyshape(trench(:,1), trench(:,2));
myArea = area(polyshapeTrench);
myPerimeter = perimeter(polyshapeTrench);
resultPart1 = myArea + myPerimeter/2 + 1;
fprintf('Part 1 Result: %.2f\n', resultPart1);

%% Part 2
directions = containers.Map({'0', '1', '2', '3'}, {[0, 1]; [1, 0]; [0, -1]; [-1, 0]});
trench = [0, 0];
for i = 1:length(input)
    line = input{i};
    hexStartIndex = strfind(line, '#');
    if isempty(hexStartIndex)
        error('No # symbol found in line: %s', line);
    end
    hexStartIndex = hexStartIndex(1) + 1;
    hexNumber = line(hexStartIndex:hexStartIndex+4);
    directionChar = line(end-1);
    if ~all(isstrprop(hexNumber, 'xdigit'))
        error('Invalid hexadecimal string: %s', hexNumber);
    end
    distance = hex2dec(hexNumber);
    direction = directions(directionChar);
    trench = [trench; trench(end, :) + distance * direction];
end
trenchPoly = polyshape(trench(:,1), trench(:,2));
myArea = area(trenchPoly);
myPerimeter = perimeter(trenchPoly);
resultPart2 = myArea + myPerimeter / 2 + 1;
fprintf('Part 2 Result: %.2f\n', resultPart2);

Day 19

Part 1 and Part 2

const fs = require('fs');
const re = /\d+/g;

function ints(s) {
  return s.match(re).map(Number);
}

const content = fs.readFileSync('E:\\ExplorerDownload\\input_day19.txt', 'utf8').trim().split('\n\n');
const [workflowStr, partsStr] = content;

const parts = partsStr.split("\n").map(ints);
const workflow = workflowStr.split("\n").reduce((acc, l) => {
  const [key, value] = l.split("{");
  acc[key] = value.slice(0, -1);
  return acc;
}, {});

function eval2(part, work) {
  const w = workflow[work];
  const [x, m, a, s] = part;
  for (const it of w.split(",")) {
    if (it === "R") {
      return false;
    }
    if (it === "A") {
      return true;
    }
    if (!it.includes(":")) {
      return eval2(part, it);
    }
    const [cond, res] = it.split(":");
    if (eval(cond)) {
      if (res === "R") {
        return false;
      }
      if (res === "A") {
        return true;
      }
      return eval2(part, res);
    }
  }
  throw new Error(w);
}

let p1 = 0;

for (const part of parts) {
  if (eval2(part, 'in')) {
    p1 += part.reduce((a, b) => a + b, 0);
  }
}
console.log(p1);

function both(ch, gt, val, ranges) {
  ch = 'xmas'.indexOf(ch);
  const ranges2 = [];
  for (let rng of ranges) {
    rng = [...rng];
    let [lo, hi] = rng[ch];
    if (gt) {
      lo = Math.max(lo, val + 1);
    } else {
      hi = Math.min(hi, val - 1);
    }
    if (lo > hi) {
      continue;
    }
    rng[ch] = [lo, hi];
    ranges2.push(rng);
  }
  return ranges2;
}

function acceptance_ranges_outer(work) {
  return acceptance_ranges_inner(workflow[work].split(","));
}

function acceptance_ranges_inner(w) {
    const it = w[0];
    if (it === "R") {
      return [];
    }
    if (it === "A") {
      return [[[1, 4000], [1, 4000], [1, 4000], [1, 4000]]];
    }
    if (!it.includes(":")) {
      return acceptance_ranges_outer(it);
    }
    const [cond, res] = it.split(":");
    const gt = cond.includes(">");
    const ch = cond[0];
    const val = parseInt(cond.slice(2), 10); // Corrected line
    const val_inverted = gt ? val + 1 : val - 1;
    const if_cond_is_true = both(ch, gt, val, acceptance_ranges_inner([res]));
    const if_cond_is_false = both(ch, !gt, val_inverted, acceptance_ranges_inner(w.slice(1)));
    return if_cond_is_true.concat(if_cond_is_false);
  }
  

let p2 = 0;
for (const rng of acceptance_ranges_outer('in')) {
  let v = 1;
  for (const [lo, hi] of rng) {
    v *= hi - lo + 1;
  }
  p2 += v;
}
console.log(p2);

Day 20

Part 1 and Part 2

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

// LCM function using the greatest common divisor (GCD) approach
const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b));
const lcm = (a, b) => (a * b) / gcd(a, b);

// LCM for more than two numbers
const lcmMultiple = (numbers) => numbers.reduce((a, b) => lcm(a, b));

// Read the file
const data = fs.readFileSync(path.resolve('E:\\ExplorerDownload\\input_day20.txt'), 'utf8').trim();
const lines = data.split('\n');

let adj = {};
let conjs = {};
let ffs = {};
let rx_conj = "";

lines.forEach((line) => {
    const [module, dests] = line.split(" -> ");
    const destinations = dests.split(", ");
    const t = module[0];
    if (module === "broadcaster") {
        adj["broadcaster"] = destinations;
    } else {
        const label = module.substring(1);
        adj[label] = destinations;

        if (destinations.includes("rx")) {
            rx_conj = label;
        }

        if (t === "&") {
            conjs[label] = {};
        }

        if (t === "%") {
            ffs[label] = false;
        }
    }
});

Object.keys(adj).forEach((label) => {
    adj[label].forEach((dest) => {
        if (dest in conjs) {
            conjs[dest][label] = 0;
        }
    });
});

let low_pulses = 0;
let high_pulses = 0;
let presses = 0;
let rx_conj_presses = {};

const press = () => {
    presses++;

    low_pulses += 1 + adj["broadcaster"].length;
    let queue = [];
    adj["broadcaster"].forEach((dest) => {
        queue.push([0, "broadcaster", dest]);
    });

    while (queue.length > 0) {
        const [pulse, src, label] = queue.shift();

        if (label === "rx") {
            continue;
        }

        let to_send = 0;
        if (label in conjs) {
            conjs[label][src] = pulse;
            if (Object.values(conjs[label]).some(n => n === 0)) {
                to_send = 1;
            }
        }

        if (label in ffs) {
            if (pulse === 1) {
                continue;
            }
            ffs[label] = !ffs[label];
            if (ffs[label]) {
                to_send = 1;
            }
        }

        if (to_send === 1) {
            high_pulses += adj[label].length;
        } else {
            low_pulses += adj[label].length;
        }

        adj[label].forEach((dest) => {
            queue.push([to_send, label, dest]);
        });

        Object.keys(conjs[rx_conj]).forEach((key) => {
            if (conjs[rx_conj][key] === 1 && !(key in rx_conj_presses)) {
                rx_conj_presses[key] = presses;
            }
        });
    }
};

for (let i = 0; i < 1000; i++) {
    press();
}

console.log(low_pulses * high_pulses);

while (Object.keys(rx_conj_presses).length < 4) {
    press();
}

console.log(lcmMultiple(Object.values(rx_conj_presses)));

Day 21

Part 1 and Part2

Reddit评论区大佬写的Python代码,可以用Julia重写一下。
Julia支持Complex{BigInt}作为哈希表键的类型,但是要注意Python是0-indexed的,Julia是1-indexed的。实际改写后运行发现Julia代码要比Python代码运行慢一点。

G = {}
done = []
todo = set()
with open('E:\\ExplorerDownload\\input_day21.txt') as file:
    for i, r in enumerate(file):
        for j, c in enumerate(r):
            if c in '.S':
                G[i+j*1j] = c
                if c=='S':
                    todo.add(i+j*1j)

def cmod(x):
    return complex(x.real % 131, x.imag % 131)

for s in range(3 * 131):
    if s == 64:
        print("part 1: ",len(todo))
    if s % 131 == 65:
        done.append(len(todo))

    new_todo = set()
    for p in todo:
        for d in {1, -1, 1j, -1j}:
            if cmod(p+d) in G:
                new_todo.add(p+d)
    todo = new_todo

def f(n, a, b, c):
    return a + n * (b - a + (n - 1) * (c - b - b + a) // 2)

print("part 2:", f(26501365 // 131, *done)
using Base: im

# Define the complex dictionary and sets with BigInt
G = Dict{Complex{BigInt}, Char}()
done = BigInt[]
todo = Set{Complex{BigInt}}()

# Read the file and populate the dictionary and sets
open("E:\\ExplorerDownload\\input_day21.txt") do file
    for (i, r) in enumerate(eachline(file))
        for (j, c) in enumerate(r)
            if c == '.' || c == 'S'
                G[BigInt(i-1) + BigInt(j-1) * im] = c
                if c == 'S'
                    push!(todo, BigInt(i-1) + BigInt(j-1) * im)
                end
            end
        end
    end
end


# Function to apply modulus to complex numbers with BigInt components
function cmod(x::Complex{BigInt})
    return Complex(mod(x.re, BigInt(131)), mod(x.im, BigInt(131)))
end

# Main loop for spreading the 'S' states
for s in 0:(3 * 131 - 1)
    global todo
    if s == 64
        println("part 1: ", length(todo))
    end
    if s % 131 == 65
        push!(done, length(todo))
    end

    new_todo = Set{Complex{BigInt}}()
    for p in todo
        for d in [1, -1, im, -im]
            neighbor = cmod(p+d)
            if haskey(G, neighbor)
                push!(new_todo, p+d)
            end
        end
    end
    todo = copy(new_todo)
end

# Function to calculate the formula given in the original code
function f(n::BigInt, a::BigInt, b::BigInt, c::BigInt)
    return a + n * (b - a + (n - 1) * (c - b - b + a) ÷ BigInt(2))
end

# Calculate the final values and print the results
n = BigInt(26501365) ÷ BigInt(131)
println("part 2: ", f(n, done...))

Day 22

Part 1 and Part 2

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

const filePath = path.resolve('E:\\ExplorerDownload', 'input_day22.txt');
let ans = 0;

const content = fs.readFileSync(filePath, { encoding: 'utf-8' });
const s = content.trim();

let bricks = [];
// line by line input
s.split("\n").forEach(l => {
    const [sloc, eloc] = l.split("~");
    const [sx, sy, sz] = sloc.split(",").map(Number);
    const [ex, ey, ez] = eloc.split(",").map(Number);
    bricks.push({ sx, sy, sz, ex, ey, ez });
});

function isSolid(bset, x, y, z) {
    if (z === 0) {
        return true;
    }
    return bset.has(`${x},${y},${z}`);
}

function bfall(bricks) {
    let fell = false;
    const bset = new Set();
    bricks.forEach(({ sx, sy, sz, ex, ey, ez }) => {
        for (let x = sx; x <= ex; x++) {
            for (let y = sy; y <= ey; y++) {
                bset.add(`${x},${y},${ez}`);
            }
        }
    });

    const newBricks = [];
    for (const { sx, sy, sz, ex, ey, ez } of bricks) {
        let supp = false;
        for (let x = sx; x <= ex; x++) {
            for (let y = sy; y <= ey; y++) {
                if (isSolid(bset, x, y, sz - 1)) {
                    supp = true;
                    break;
                }
            }
            if (supp) {
                break;
            }
        }
        if (!supp) {
            fell = true;
            newBricks.push({ sx, sy, sz: sz - 1, ex, ey, ez: ez - 1 });
        } else {
            newBricks.push({ sx, sy, sz, ex, ey, ez });
        }
    }
    return [fell, newBricks];
}


let fell = true;
let cnt = 0;
while (fell) {
    cnt += 1;
    [fell, bricks] = bfall(bricks); // 'bricks' is reassigned here, so it must be a 'let' variable
}

const bcopy = bricks.slice();

ans = 0;
for (let i = 0; i < bcopy.length; i++) {
    let bcopy2 = bcopy.slice();
    bcopy2.splice(i, 1);
    if (!bfall(bcopy2)[0]) {
        ans += 1;
    }
}
console.log("part 1:", ans);

ans = 0;
for (let i = 0; i < bcopy.length; i++) {
    let bcopy2 = bcopy.slice();
    bcopy2.splice(i, 1);
    let bcopy3 = bcopy2.slice();
    fell = true;
    while (fell) {
        [fell, bcopy2] = bfall(bcopy2);
    }
    let mm = 0;
    for (let j = 0; j < bcopy2.length; j++) {
        if (bcopy2[j].sx !== bcopy3[j].sx || bcopy2[j].sy !== bcopy3[j].sy || bcopy2[j].sz !== bcopy3[j].sz ||
            bcopy2[j].ex !== bcopy3[j].ex || bcopy2[j].ey !== bcopy3[j].ey || bcopy2[j].ez !== bcopy3[j].ez) {
            mm += 1;
        }
    }
    ans += mm;
}
console.log("part 2:", ans);

Day 23

Part 1 and Part 2

const fs = require('fs');
const path = 'E:\\ExplorerDownload\\input_day23.txt';
const data = fs.readFileSync(path, 'utf8').trim().split('\n');

// Helper function to make coordinate strings
function makeCoordString(r, c) {
    return `${r},${c}`;
}

// Helper function to parse coordinate strings
function parseCoordString(coordString) {
    return coordString.split(',').map(Number);
}

// Part 1
let edges = {};
data.forEach((row, r) => {
    row.split('').forEach((v, c) => {
        if (v === '.') {
            [[-1, 0], [0, -1], [0, 1], [1, 0]].forEach(([dr, dc]) => {
                let ar = r + dr, ac = c + dc;
                if (ar >= 0 && ar < data.length && ac >= 0 && ac < row.length && data[ar][ac] === '.') {
                    let coord1 = makeCoordString(r, c);
                    let coord2 = makeCoordString(ar, ac);
                    edges[coord1] = edges[coord1] || new Set();
                    edges[coord2] = edges[coord2] || new Set();
                    edges[coord1].add(coord2);
                    edges[coord2].add(coord1);
                }
            });
        }
        if (v === '>') {
            let coord1 = makeCoordString(r, c);
            let coord2 = makeCoordString(r, c + 1);
            let coord3 = makeCoordString(r, c - 1);
            edges[coord1] = edges[coord1] || new Set();
            edges[coord3] = edges[coord3] || new Set();
            edges[coord1].add(coord2);
            edges[coord3].add(coord1);
        }
        if (v === 'v') {
            let coord1 = makeCoordString(r, c);
            let coord2 = makeCoordString(r + 1, c);
            let coord3 = makeCoordString(r - 1, c);
            edges[coord1] = edges[coord1] || new Set();
            edges[coord3] = edges[coord3] || new Set();
            edges[coord1].add(coord2);
            edges[coord3].add(coord1);
        }
    });
});

let n = data.length, m = data[0].length;

let q = [[0, 1, 0]];
let visited = new Set();
let best = 0;
while (q.length > 0) {
    let [r, c, d] = q.pop();
    let coord = makeCoordString(r, c);
    if (d === -1) {
        visited.delete(coord);
        continue;
    }
    if (r === n - 1 && c === m - 2) {
        best = Math.max(best, d);
        continue;
    }
    if (visited.has(coord)) {
        continue;
    }
    visited.add(coord);
    q.push([r, c, -1]);
    edges[coord].forEach(adjCoord => {
        let [ar, ac] = parseCoordString(adjCoord);
        q.push([ar, ac, d + 1]);
    });
}
console.log(best);

// Part 2
// Re-initialize edges for part 2
edges = {};
data.forEach((row, r) => {
    row.split('').forEach((v, c) => {
        if ('.>v'.includes(v)) {
            [[-1, 0], [0, -1], [0, 1], [1, 0]].forEach(([dr, dc]) => {
                let ar = r + dr, ac = c + dc;
                if (ar >= 0 && ar < data.length && ac >= 0 && ac < row.length && '.>v'.includes(data[ar][ac])) {
                    let coord1 = makeCoordString(r, c);
                    let coord2 = makeCoordString(ar, ac);
                    edges[coord1] = edges[coord1] || new Set();
                    edges[coord2] = edges[coord2] || new Set();
                    edges[coord1].add(`${coord2},1`);
                    edges[coord2].add(`${coord1},1`);
                }
            });
        }
    });
});

// Remove nodes with degree 2 by merging the edges
while (true) {
    let removed = false;
    for (let [n, e] of Object.entries(edges)) {
        if (e.size === 2) {
            let [a, b] = [...e].map(parseCoordString);
            let aKey = makeCoordString(a[0], a[1]);
            let bKey = makeCoordString(b[0], b[1]);
            edges[aKey].delete(n + `,${a[2]}`);
            edges[bKey].delete(n + `,${b[2]}`);
            let newEdge = makeCoordString(b[0], b[1]) + `,${a[2] + b[2]}`;
            edges[aKey].add(newEdge);
            edges[bKey].add(makeCoordString(a[0], a[1]) + `,${a[2] + b[2]}`);
            delete edges[n];
            removed = true;
            break;
        }
    }
    if (!removed) {
        break;
    }
}

q = [[0, 1, 0]];
visited = new Set();
best = 0;
while (q.length > 0) {
    let [r, c, d] = q.pop();
    let coord = makeCoordString(r, c);
    if (d === -1) {
        visited.delete(coord);
        continue;
    }
    if (r === n - 1 && c === m - 2) {
        best = Math.max(best, d);
        continue;
    }
    if (visited.has(coord)) {
        continue;
    }
    visited.add(coord);
    q.push([r, c, -1]);
    edges[coord].forEach(edge => {
        let [ar, ac, l] = parseCoordString(edge);
        q.push([ar, ac, d + l]);
    });
}
console.log(best);

Day 24

Part 1 and Part 2

lines = Import["E:\\ExplorerDownload\\input_day24.txt", "Lines"];
rawPoints = StringReplace[#, "@" -> ","] & /@ lines;
pts = ToExpression["{" <> # <> "}"] & /@ rawPoints;
AtTime[pt_, t_] := {pt[[1]] + t*pt[[4]], pt[[2]] + t*pt[[5]], 
   pt[[3]] + t*pt[[6]]};
cnt = 0;
For[i = 1, i <= Length[pts], i++, 
  For[j = i + 1, j <= Length[pts], j++, a = pts[[i]];
   b = pts[[j]];
   soln = 
    Solve[AtTime[a, t1][[1 ;; 2]] == AtTime[b, t2][[1 ;; 2]], {t1, 
      t2}];
   If[Length[soln] > 0 && (t1 /. soln[[1]]) > 0 && (t2 /. soln[[1]]) >
       0, pos = AtTime[a, t1] /. soln[[1]];
    If[pos[[1]] > 200000000000000 && pos[[2]] > 200000000000000 && 
      pos[[1]] < 400000000000000 && pos[[2]] < 400000000000000, 
     cnt += 1]]]];
Print["Part 1 is ", cnt];
magicRock = {sx, sy, sz, dx, dy, dz};
part2solution = 
  Solve[(AtTime[magicRock, t1] == AtTime[pts[[1]], t1] && 
     AtTime[magicRock, t2] == AtTime[pts[[2]], t2] && 
     AtTime[magicRock, t3] == AtTime[pts[[3]], t3]), {sx, sy, sz, dx, 
    dy, dz, t1, t2, t3}];
Print["Part 2 is ", sx + sy + sz /. part2solution[[1]]];

Day 25

最后一天只有Part 1

(*Step 1:Import the data from the text file*)
rawData = Import["E:\\ExplorerDownload\\input_day25.txt"];

(*Step 2:Split the imported data into lines*)
lines = StringSplit[rawData, "\n"];

(*Step 3:Further split each line into parts separated by ":" or " "*)


splitLines = StringSplit[#, ":" | " "] & /@ lines;

(*Step 4:Convert the string representations into Mathematica \
expressions*)
input = ToExpression[splitLines];

(*Step 5:Generate edges for the graph*)
edges = Flatten[
   Table[(*Each line defines a vertex and its connected \
vertices*)(*Create edges between the first vertex and each of the \
connected vertices*)#[[1]] \[UndirectedEdge] n, {n, #[[3 ;;]]}] & /@ 
    input];

(*Step 6:Create the undirected graph*)
g = Graph[edges];

(*Step 7:Find the minimum cut of the graph*)
minCut = FindMinimumCut[g];

(*Step 8:Retrieve the two subsets from the minimum cut*)
subsets = minCut[[2]];

(*Step 9:Calculate the size of each subset*)
subsetSizes = Length /@ subsets;

(*Step 10:Calculate the product of the sizes of the two subsets*)
result = Times @@ subsetSizes;

(*Step 11:Output the result*)
result
posted @ 2023-12-01 14:38  yhm138  阅读(52)  评论(0编辑  收藏  举报