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点发布。
试题地址
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