Compare commits
10 Commits
be7c370916
...
61aa2c1ded
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
61aa2c1ded | ||
|
|
e253bc5006 | ||
|
|
88351633d2 | ||
|
|
1ddc695cb9 | ||
|
|
3784d148c7 | ||
|
|
af730bedc0 | ||
|
|
c07e124b69 | ||
|
|
389b39b1d5 | ||
|
|
928dcb5572 | ||
|
|
bbc5da95e7 |
@@ -18,12 +18,12 @@ I want to do this advent of code in more than one language if possible.
|
||||
Here is a list of all the languages I am aware of enough to program in,
|
||||
ordered from least to most confidence:
|
||||
|
||||
- (0) POSIX Shell
|
||||
- (0) Haskell
|
||||
- (0) Ocaml
|
||||
- (0) Rust
|
||||
- (0) Racket
|
||||
- (0) JavaScript/TypeScript
|
||||
- (1) POSIX Shell
|
||||
- (2) Haskell
|
||||
- (3) Ocaml
|
||||
- (4) Racket
|
||||
- (5) Rust
|
||||
- (6) JavaScript/TypeScript
|
||||
- (0) Common Lisp
|
||||
- (0) C
|
||||
- (0) Python
|
||||
|
||||
20
2015/puzzle-4.rkt
Normal file
20
2015/puzzle-4.rkt
Normal file
@@ -0,0 +1,20 @@
|
||||
#lang racket
|
||||
|
||||
(require racket/file)
|
||||
(require file/md5)
|
||||
|
||||
(define input (file->string "4-input"))
|
||||
|
||||
(define (find-salt requested-string current)
|
||||
(let* ([full-message (string-append input (number->string current))]
|
||||
[hash (bytes->string/locale (md5 full-message))])
|
||||
(if (string-prefix? hash requested-string)
|
||||
current
|
||||
(find-salt requested-string (+ current 1)))))
|
||||
|
||||
(printf "Round 1: ~a~%" (find-salt "00000" 0))
|
||||
(printf "Round 2: ~a~%" (find-salt "000000" 0))
|
||||
|
||||
;; Local Variables:
|
||||
;; compile-command: "racket puzzle-4.rkt"
|
||||
;; End:
|
||||
80
2015/puzzle-5.rs
Normal file
80
2015/puzzle-5.rs
Normal file
@@ -0,0 +1,80 @@
|
||||
use std::fs;
|
||||
|
||||
const VOWELS_STR: &str = "aeiou";
|
||||
const DO_NOT_WANT: [&str; 4] = ["ab", "cd", "pq", "xy"];
|
||||
|
||||
fn is_nice_round1(line: &str) -> bool {
|
||||
let mut unwanted_substr = false;
|
||||
let mut has_consecutive = false;
|
||||
let mut vowels = 0;
|
||||
for i in 0..line.len() - 1 {
|
||||
let slide: &str = &line[i..i + 2];
|
||||
if DO_NOT_WANT.iter().position(|&x| x == slide).is_some() {
|
||||
unwanted_substr = true;
|
||||
break;
|
||||
}
|
||||
let first = slide.chars().nth(0).unwrap();
|
||||
let second = slide.chars().nth(1).unwrap();
|
||||
if VOWELS_STR.contains(first) {
|
||||
vowels += 1;
|
||||
}
|
||||
if first == second {
|
||||
has_consecutive = true;
|
||||
}
|
||||
}
|
||||
|
||||
if VOWELS_STR.contains(line.chars().nth(line.len() - 1).unwrap()) {
|
||||
vowels += 1;
|
||||
}
|
||||
|
||||
if unwanted_substr {
|
||||
return false;
|
||||
}
|
||||
return vowels >= 3 && has_consecutive;
|
||||
}
|
||||
|
||||
fn is_nice_round2(line: &str) -> bool {
|
||||
/*
|
||||
Justifying the O(|line|^2) runtime is easy: |line| is constant, such that at
|
||||
worst we're doing roughly O(256) iterations. Not too bad.
|
||||
|
||||
If |line| could be really big I'd look into optimising the rest, but why do
|
||||
that?
|
||||
*/
|
||||
let mut has_pair = false;
|
||||
|
||||
// Unfortunate O(|line|^2) runtime
|
||||
for i in 0..line.len() - 1 {
|
||||
let slide = &line[i..i + 2];
|
||||
let rest = &line[i + 2..];
|
||||
if rest.contains(slide) {
|
||||
has_pair = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// O(|line|) runtime
|
||||
let mut has_triple = false;
|
||||
for i in 0..line.len() - 2 {
|
||||
let slide = &line[i..i + 3];
|
||||
if slide.chars().nth(0) == slide.chars().nth(2) {
|
||||
has_triple = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return has_pair && has_triple;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let binding = fs::read_to_string("5-input").expect("wget 5-input please.");
|
||||
let contents: Vec<&str> = binding.split("\n").collect();
|
||||
let nice_lines_1 = contents.iter().filter(|&x| is_nice_round1(x)).count();
|
||||
let nice_lines_2 = contents.iter().filter(|&x| is_nice_round2(x)).count();
|
||||
println!("Round 1: {nice_lines_1}");
|
||||
println!("Round 2: {nice_lines_2}");
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// compile-command: "rustc puzzle-5.rs && ./puzzle-5"
|
||||
// End:
|
||||
83
2015/puzzle-6.js
Normal file
83
2015/puzzle-6.js
Normal file
@@ -0,0 +1,83 @@
|
||||
const fs = require('node:fs/promises');
|
||||
|
||||
let arr = []
|
||||
|
||||
function count_1() {
|
||||
return arr.filter(x => x).length;
|
||||
}
|
||||
|
||||
function count_2() {
|
||||
return arr.reduce((x, y) => x + y);
|
||||
}
|
||||
|
||||
async function read_file() {
|
||||
const data = await fs.readFile("6-input", {encoding: 'utf8'});
|
||||
return data;
|
||||
}
|
||||
|
||||
function parse_line(line) {
|
||||
let [type, ...rest] = line.split(" ")
|
||||
let obj = {type: "", bottom: [], top: []};
|
||||
if (type === "toggle") {
|
||||
obj.type = "toggle";
|
||||
} else {
|
||||
obj.type = rest[0];
|
||||
rest = rest.slice(1);
|
||||
}
|
||||
obj.bottom = rest[0].split(",").map(x => parseInt(x));
|
||||
obj.top = rest[2].split(",").map(x => parseInt(x));
|
||||
return obj
|
||||
}
|
||||
|
||||
function execute_inst_1(inst) {
|
||||
for (let i = inst.bottom[0]; i <= inst.top[0]; ++i) {
|
||||
for (let j = inst.bottom[1]; j <= inst.top[1]; ++j) {
|
||||
if (inst.type === "on") {
|
||||
arr[(i * 1000) + j] = true;
|
||||
} else if (inst.type === "off") {
|
||||
arr[(i * 1000) + j] = false;
|
||||
} else {
|
||||
arr[(i * 1000) + j] = !arr[(i * 1000) + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function execute_inst_2(inst) {
|
||||
for (let i = inst.bottom[0]; i <= inst.top[0]; ++i) {
|
||||
for (let j = inst.bottom[1]; j <= inst.top[1]; ++j) {
|
||||
if (inst.type === "on") {
|
||||
arr[(i * 1000) + j] += 1;
|
||||
} else if (inst.type === "off") {
|
||||
arr[(i * 1000) + j] = Math.max(0, arr[(i * 1000) + j] - 1);
|
||||
} else {
|
||||
arr[(i * 1000) + j] += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(async () => {
|
||||
let lines = (await read_file()).split(/\n/);
|
||||
const insts = lines.map(parse_line);
|
||||
|
||||
for (let i = 0; i < 1000000; ++i) {
|
||||
arr.push(false);
|
||||
}
|
||||
for (let i = 0; i < insts.length; ++i) {
|
||||
execute_inst_1(insts[i]);
|
||||
}
|
||||
console.log("Round 1:", count_1());
|
||||
|
||||
for (let i = 0; i < 1000000; ++i) {
|
||||
arr[i] = 0;
|
||||
}
|
||||
for (let i = 0; i < insts.length; ++i) {
|
||||
execute_inst_2(insts[i]);
|
||||
}
|
||||
console.log("Round 2:", count_2());
|
||||
})()
|
||||
|
||||
// Local Variables:
|
||||
// compile-command: "node puzzle-6.js"
|
||||
// End:
|
||||
15
2024/puzzle-1.lisp
Normal file
15
2024/puzzle-1.lisp
Normal file
@@ -0,0 +1,15 @@
|
||||
(load "util.lisp")
|
||||
|
||||
(--> (uiop:read-file-lines "1-input")
|
||||
(loop for line in _
|
||||
for x = (search " " line)
|
||||
collect (parse-integer (subseq line 0 x)) into left
|
||||
collect (parse-integer (subseq line (+ x 3))) into right
|
||||
finally (return (list (sort left #'<) (sort right #'<))))
|
||||
(format t "Round 1: ~a~%Round 2: ~a~%"
|
||||
(loop for x in (car _)
|
||||
for y in (cadr _)
|
||||
sum (abs (- y x)))
|
||||
(loop for item in (car _)
|
||||
for count = (count item (cadr _))
|
||||
sum (* item count))))
|
||||
43
2024/puzzle-2.py
Normal file
43
2024/puzzle-2.py
Normal file
@@ -0,0 +1,43 @@
|
||||
lines = []
|
||||
with open("2-input", "r") as fp:
|
||||
lines = fp.readlines()
|
||||
|
||||
levels = [list(map(int, line.strip().split(" "))) for line in lines]
|
||||
|
||||
def is_good_level_1(level):
|
||||
# 1) Is decreasing
|
||||
# 2) Sliding window of two cells (x, y) => 1 <= |x-y| <= 3
|
||||
# figure out if decreasing from first two
|
||||
decreasing = level[0] > level[1]
|
||||
for i in range(len(level) - 1):
|
||||
x = level[i]
|
||||
y = level[i + 1]
|
||||
diff = abs(x - y)
|
||||
if (decreasing and x < y) or (not decreasing and x > y) or not (diff <= 3 and diff >= 1):
|
||||
return False
|
||||
return True
|
||||
|
||||
good_levels = [level for level in levels if is_good_level_1(level)]
|
||||
print(f"Round 1: {len(good_levels)}")
|
||||
|
||||
def check_two_levels(x, y, decreasing):
|
||||
diff = abs(x - y)
|
||||
return not ((decreasing and x < y)\
|
||||
or (not decreasing and x > y) \
|
||||
or not (diff <= 3 and diff >= 1))
|
||||
|
||||
def is_good_level_2(level):
|
||||
# 1) Is decreasing
|
||||
# 2) Sliding window of two cells (x, y) => 1 <= |x-y| <= 3
|
||||
# 3) Can remove any one item to make it safe
|
||||
if is_good_level_1(level):
|
||||
return True
|
||||
# Consider slices of the level and check if they're good
|
||||
slices = [level[:i] + level[i + 1:] for i in range(len(level))]
|
||||
for s in slices:
|
||||
if is_good_level_1(s):
|
||||
return True
|
||||
return False
|
||||
|
||||
good_levels = [level for level in levels if is_good_level_2(level)]
|
||||
print(f"Round 2: {len(good_levels)}")
|
||||
59
2024/puzzle-3.lisp
Normal file
59
2024/puzzle-3.lisp
Normal file
@@ -0,0 +1,59 @@
|
||||
(load "util.lisp")
|
||||
|
||||
(defparameter input (uiop:read-file-string "3-input"))
|
||||
|
||||
(defun is-good-mul (str)
|
||||
(let ((start (search "(" str))
|
||||
(middle (search "," str))
|
||||
(end (search ")" str)))
|
||||
(and (not (null start)) (not (null middle)) (not (null end))
|
||||
;; mul( <- 3 character
|
||||
(eq start 3)
|
||||
;; Simple to understand
|
||||
(< start end)
|
||||
(< start middle)
|
||||
(< middle end)
|
||||
;; Make sure the arguments are purely numbers
|
||||
(every #'digit-char-p (subseq str (1+ start) middle))
|
||||
(every #'digit-char-p (subseq str (1+ middle) end)))))
|
||||
|
||||
(defun parse-mul (str)
|
||||
(let ((start (search "(" str))
|
||||
(middle (search "," str))
|
||||
(end (search ")" str)))
|
||||
(list (parse-integer (subseq str (1+ start) middle))
|
||||
(parse-integer (subseq str (1+ middle) end)))))
|
||||
|
||||
(defun parse-input-muls (line)
|
||||
(let ((possible (search-all "mul" line)))
|
||||
(--> (cdr possible)
|
||||
(append _ (list (length line)))
|
||||
;; index of mul -> (position substring)
|
||||
(mapcar (lambda (z1 z2) (cons z1 (subseq line z1 z2))) possible _)
|
||||
;; remove any bad muls
|
||||
(remove-if-not (lambda (x) (is-good-mul (cdr x))) _)
|
||||
;; parse muls
|
||||
(mapcar (lambda (x) (cons (car x) (parse-mul (cdr x)))) _))))
|
||||
|
||||
(format t "Round 1: ~a~%"
|
||||
(loop for (pos x y) in (parse-input-muls input)
|
||||
sum (* x y)))
|
||||
|
||||
(defun parse-input-conds (input)
|
||||
(let ((dos (search-all "do()" input))
|
||||
(donts (search-all "don't()" input)))
|
||||
(--> (append (mapcar (lambda (x) (cons 'do x)) dos)
|
||||
(mapcar (lambda (x) (cons 'dont x)) donts))
|
||||
(sort _ (lambda (x y) (< (cdr x) (cdr y))))
|
||||
(cons '(do . 0) _))))
|
||||
|
||||
(defun current-cond (pos conds)
|
||||
(caar (last (remove-if (lambda (x) (> (cdr x) pos)) conds))))
|
||||
|
||||
(format t "Round 2: ~a~%"
|
||||
(let ((conds (parse-input-conds input))
|
||||
(muls (parse-input-muls input)))
|
||||
(loop for (pos x y) in muls
|
||||
for current = (current-cond pos conds)
|
||||
if (eq current 'do)
|
||||
sum (* x y))))
|
||||
20
2024/util.lisp
Normal file
20
2024/util.lisp
Normal file
@@ -0,0 +1,20 @@
|
||||
(defmacro --> (first &rest functions)
|
||||
(if (null functions)
|
||||
first
|
||||
`(let* ,(loop :for f :in (cons first functions)
|
||||
:appending `((_ ,f)))
|
||||
_)))
|
||||
|
||||
(defun search-all (substr str &optional acc len)
|
||||
(let ((x (search substr str))
|
||||
(len (or len 0)))
|
||||
(if (null x)
|
||||
(reverse acc)
|
||||
(search-all substr (subseq str (1+ x))
|
||||
(cons (+ x len) acc)
|
||||
(+ len x 1)))))
|
||||
|
||||
(defun zip (a b)
|
||||
(loop for i in a
|
||||
for j in b
|
||||
collect (cons i j)))
|
||||
Reference in New Issue
Block a user