first commit
This commit is contained in:
8
.editorconfig
Normal file
8
.editorconfig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# EditorConfig is awesome: https://editorconfig.org
|
||||||
|
|
||||||
|
[*]
|
||||||
|
charset = utf-8
|
||||||
|
end_of_line = lf
|
||||||
|
indent_size = 4
|
||||||
|
indent_style = space
|
||||||
|
insert_final_newline = true
|
||||||
8
README.md
Normal file
8
README.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## Advent of Code 2025
|
||||||
|
|
||||||
|
At the suggestion of a co-worker, I'm participating in the Advent of Code for 2025, and thiss repo will have my solutions.
|
||||||
|
|
||||||
|
While I plan to do some of these in different languages, I'm 2 days in and so far, it's 100% JavaScript (my preferred language over the decade or so, and the one I work in the most).
|
||||||
|
|
||||||
|
Each day should have instructions for running it. Fopr the JS stuff, it's node 22 with no special packages.
|
||||||
|
|
||||||
4531
day01/input.txt
Normal file
4531
day01/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
88
day01/js/day01a.js
Normal file
88
day01/js/day01a.js
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
import { promises as fsPromises } from "fs";
|
||||||
|
|
||||||
|
async function asyncReadFile(filename) {
|
||||||
|
try {
|
||||||
|
const contents = await fsPromises.readFile(filename, "utf-8");
|
||||||
|
|
||||||
|
const arr = contents.split(/\r?\n/);
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dial 0-99
|
||||||
|
|
||||||
|
const DIAL_START = 50;
|
||||||
|
|
||||||
|
const Dial = (start = DIAL_START) => {
|
||||||
|
let countZero = 0,
|
||||||
|
current = start;
|
||||||
|
const getCountZero = () => countZero,
|
||||||
|
reset = () => {
|
||||||
|
countZero = 0;
|
||||||
|
current = start;
|
||||||
|
},
|
||||||
|
rotate = (initialVal = "") => {
|
||||||
|
const val = initialVal.trim(),
|
||||||
|
dir = val.length ? val.substring(0, 1).toUpperCase() : "",
|
||||||
|
amount = val.length ? (val.substring(1) * 1) % 100 : 0;
|
||||||
|
|
||||||
|
if (!dir) {
|
||||||
|
console.log(`${val} => invalid value!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const initial = current;
|
||||||
|
|
||||||
|
if (dir === "R") {
|
||||||
|
current = (current + amount) % 100;
|
||||||
|
} else if (dir === "L") {
|
||||||
|
current =
|
||||||
|
(current - amount + (current - amount < 0 ? 100 : 0)) % 100;
|
||||||
|
}
|
||||||
|
console.log(
|
||||||
|
`${val} => rotating ${
|
||||||
|
dir === "R" ? "RIGHT" : "LEFT"
|
||||||
|
} ${amount} from ${initial} to ${current}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (current === 0) {
|
||||||
|
countZero++;
|
||||||
|
console.log("CountZero!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
getCountZero,
|
||||||
|
reset,
|
||||||
|
rotate,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const dial = Dial();
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Test Data
|
||||||
|
|
||||||
|
const dataToParse = [
|
||||||
|
"L68",
|
||||||
|
"L30",
|
||||||
|
"R48",
|
||||||
|
"L5",
|
||||||
|
"R60",
|
||||||
|
"L55",
|
||||||
|
"L1",
|
||||||
|
"L99",
|
||||||
|
"R14",
|
||||||
|
"L82",
|
||||||
|
];
|
||||||
|
*/
|
||||||
|
|
||||||
|
const dataToParse = await asyncReadFile("../input.txt");
|
||||||
|
|
||||||
|
dataToParse.forEach((val) => {
|
||||||
|
if (val.trim()) dial.rotate(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Final countZero is ${dial.getCountZero()}`);
|
||||||
103
day01/js/day01b.js
Normal file
103
day01/js/day01b.js
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import { readFileSync, promises as fsPromises } from "fs";
|
||||||
|
|
||||||
|
async function asyncReadFile(filename) {
|
||||||
|
try {
|
||||||
|
const contents = await fsPromises.readFile(filename, "utf-8");
|
||||||
|
|
||||||
|
const arr = contents.split(/\r?\n/);
|
||||||
|
|
||||||
|
// console.log(arr); // 👉️ ['One', 'Two', 'Three', 'Four']
|
||||||
|
|
||||||
|
return arr;
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// dial 0-99
|
||||||
|
|
||||||
|
const DIAL_START = 50;
|
||||||
|
|
||||||
|
const Dial = (start = DIAL_START) => {
|
||||||
|
let countZero = 0,
|
||||||
|
current = start;
|
||||||
|
const getCountZero = () => countZero,
|
||||||
|
reset = () => {
|
||||||
|
countZero = 0;
|
||||||
|
current = start;
|
||||||
|
},
|
||||||
|
rotate = (initialVal = "") => {
|
||||||
|
const val = initialVal.trim(),
|
||||||
|
dir = val.length ? val.substring(0, 1).toUpperCase() : "",
|
||||||
|
originalAmount = val.length ? val.substring(1) * 1 : 0,
|
||||||
|
amount = originalAmount % 100,
|
||||||
|
hundreds = Math.floor(originalAmount / 100);
|
||||||
|
|
||||||
|
if (!dir) {
|
||||||
|
console.log(`${val} => invalid value!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const initial = current;
|
||||||
|
|
||||||
|
if (hundreds) {
|
||||||
|
countZero += hundreds;
|
||||||
|
console.log(`${val} => has hundreds: ${hundreds} x CountZero!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dir === "R") {
|
||||||
|
if (current + amount > 100) {
|
||||||
|
countZero++;
|
||||||
|
console.log(`${val} => passing 0: CountZero!`);
|
||||||
|
}
|
||||||
|
current = (current + amount) % 100;
|
||||||
|
} else if (dir === "L") {
|
||||||
|
if (current && current - amount < 0) {
|
||||||
|
countZero++;
|
||||||
|
console.log(`${val} => passing 0: CountZero!`);
|
||||||
|
}
|
||||||
|
current = (100 + current - amount) % 100;
|
||||||
|
}
|
||||||
|
console.log(
|
||||||
|
`${val} => rotating ${
|
||||||
|
dir === "R" ? "RIGHT" : "LEFT"
|
||||||
|
} ${amount} from ${initial} to ${current}`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (current === 0) {
|
||||||
|
countZero++;
|
||||||
|
console.log("CountZero!");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
getCountZero,
|
||||||
|
reset,
|
||||||
|
rotate,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const dial = Dial();
|
||||||
|
|
||||||
|
// Test Data
|
||||||
|
/*
|
||||||
|
const dataToParse = [
|
||||||
|
"L68",
|
||||||
|
"L30",
|
||||||
|
"R48",
|
||||||
|
"L5",
|
||||||
|
"R60",
|
||||||
|
"L55",
|
||||||
|
"L1",
|
||||||
|
"L99",
|
||||||
|
"R14",
|
||||||
|
"L82",
|
||||||
|
];
|
||||||
|
*/
|
||||||
|
|
||||||
|
const dataToParse = await asyncReadFile("../input.txt");
|
||||||
|
|
||||||
|
dataToParse.forEach((val) => {
|
||||||
|
if (val.trim()) dial.rotate(val);
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Final countZero is ${dial.getCountZero()}`);
|
||||||
11
day01/notes.md
Normal file
11
day01/notes.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
## Day 1: Secret Entrance
|
||||||
|
|
||||||
|
This was fun, took about 90 minutes to get first two solutions (in JS).
|
||||||
|
|
||||||
|
### JS Solutions
|
||||||
|
|
||||||
|
```
|
||||||
|
cd js
|
||||||
|
node day01a.js
|
||||||
|
node day01b.js
|
||||||
|
```
|
||||||
1
day02/input.txt
Normal file
1
day02/input.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3335355312-3335478020,62597156-62638027,94888325-95016472,4653-6357,54-79,1-19,314-423,472-650,217886-298699,58843645-58909745,2799-3721,150748-178674,9084373-9176707,1744-2691,17039821-17193560,2140045-2264792,743-1030,6666577818-6666739950,22946-32222,58933-81008,714665437-714803123,9972438-10023331,120068-142180,101-120,726684-913526,7575737649-7575766026,8200-11903,81-96,540949-687222,35704-54213,991404-1009392,335082-425865,196-268,3278941-3383621,915593-991111,32-47,431725-452205
|
||||||
45
day02/js/day02a.js
Normal file
45
day02/js/day02a.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
import { promises as fsp } from "node:fs";
|
||||||
|
|
||||||
|
async function asyncReadFile(filename) {
|
||||||
|
try {
|
||||||
|
const contents = await fsp.readFile(filename, "utf-8");
|
||||||
|
|
||||||
|
return contents.trim();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
const dataToParse =
|
||||||
|
"11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124";
|
||||||
|
*/
|
||||||
|
|
||||||
|
const dataToParse = await asyncReadFile("../input.txt");
|
||||||
|
|
||||||
|
const isDuplicate = (val = "") => {
|
||||||
|
const strVal = `${val}`,
|
||||||
|
strLen = strVal.length;
|
||||||
|
if (!strLen || strLen % 2 === 1) return false;
|
||||||
|
|
||||||
|
return strVal.substring(0, strLen / 2) === strVal.substring(strLen / 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ranges = dataToParse.split(",");
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
ranges.forEach((range) => {
|
||||||
|
console.log(`> running range ${range}`);
|
||||||
|
const [start, end] = range.split("-"),
|
||||||
|
last = end * 1;
|
||||||
|
let curr = start * 1;
|
||||||
|
while (curr <= last) {
|
||||||
|
if (isDuplicate(curr)) {
|
||||||
|
total += curr;
|
||||||
|
console.log(`>> found duplicate: ${curr} / ${total}`);
|
||||||
|
}
|
||||||
|
curr++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`> FINAL: ${total}`);
|
||||||
59
day02/js/day02b.js
Normal file
59
day02/js/day02b.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { promises as fsp } from "node:fs";
|
||||||
|
|
||||||
|
async function asyncReadFile(filename) {
|
||||||
|
try {
|
||||||
|
const contents = await fsp.readFile(filename, "utf-8");
|
||||||
|
|
||||||
|
return contents.trim();
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
const dataToParse =
|
||||||
|
"11-22,95-115,998-1012,1188511880-1188511890,222220-222224,1698522-1698528,446443-446449,38593856-38593862,565653-565659,824824821-824824827,2121212118-2121212124";
|
||||||
|
*/
|
||||||
|
|
||||||
|
const dataToParse = await asyncReadFile("../input.txt");
|
||||||
|
|
||||||
|
const isDuplicateOld = (val = "") => {
|
||||||
|
const strVal = `${val}`,
|
||||||
|
strLen = strVal.length;
|
||||||
|
if (!strLen || strLen % 2 === 1) return false;
|
||||||
|
|
||||||
|
return strVal.substring(0, strLen / 2) === strVal.substring(strLen / 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const duplicateRE = /^(\d+)\1+$/;
|
||||||
|
const isDuplicate = (val = "") => {
|
||||||
|
// new process - runa regex that looks for repeats from start to end
|
||||||
|
const strVal = `${val}`,
|
||||||
|
strLen = strVal.length;
|
||||||
|
if (!strLen) return false;
|
||||||
|
|
||||||
|
const matches = strVal.match(duplicateRE);
|
||||||
|
|
||||||
|
if (matches === null) return false;
|
||||||
|
|
||||||
|
return matches.length >= 1 && matches[0] === strVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
const ranges = dataToParse.split(",");
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
ranges.forEach((range) => {
|
||||||
|
console.log(`> running range ${range}`);
|
||||||
|
const [start, end] = range.split("-"),
|
||||||
|
last = end * 1;
|
||||||
|
let curr = start * 1;
|
||||||
|
while (curr <= last) {
|
||||||
|
if (isDuplicate(curr)) {
|
||||||
|
total += curr;
|
||||||
|
console.log(`>> found duplicate: ${curr} / ${total}`);
|
||||||
|
}
|
||||||
|
curr++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`> FINAL: ${total}`);
|
||||||
13
day02/notes.md
Normal file
13
day02/notes.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
## Day 2: Gift Shop
|
||||||
|
|
||||||
|
This got a bit frustrating with the regex in the second part.
|
||||||
|
|
||||||
|
It only took about 30 minutes to solve first part, but my answer involved literally splitting strings, so it didn't work for arbitrary matches and had to be replaced by a regex solution. After struggling with the regex for another 30 minutes, I put it away until the next day, when a 5-minute web search lead me to the fix for my bad regex.
|
||||||
|
|
||||||
|
### JS Solutions
|
||||||
|
|
||||||
|
```
|
||||||
|
cd js
|
||||||
|
node day01a.js
|
||||||
|
node day01b.js
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user