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,
|
Here is a list of all the languages I am aware of enough to program in,
|
||||||
ordered from least to most confidence:
|
ordered from least to most confidence:
|
||||||
|
|
||||||
- (0) POSIX Shell
|
- (1) POSIX Shell
|
||||||
- (0) Haskell
|
- (2) Haskell
|
||||||
- (0) Ocaml
|
- (3) Ocaml
|
||||||
- (0) Rust
|
- (4) Racket
|
||||||
- (0) Racket
|
- (5) Rust
|
||||||
- (0) JavaScript/TypeScript
|
- (6) JavaScript/TypeScript
|
||||||
- (0) Common Lisp
|
- (0) Common Lisp
|
||||||
- (0) C
|
- (0) C
|
||||||
- (0) Python
|
- (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