Compare commits

...

10 Commits

Author SHA1 Message Date
Aryadev Chavali
61aa2c1ded Optimise solutions a bit for 2024 2024-12-04 02:43:12 +00:00
Aryadev Chavali
e253bc5006 Solve round 2 and 3 for 2024 2024-12-03 16:40:08 +00:00
Aryadev Chavali
88351633d2 Add search-all function to util.lisp for 2024 2024-12-03 16:39:58 +00:00
Aryadev Chavali
1ddc695cb9 Belated 2024 first puzzle solution 2024-12-02 00:31:06 +00:00
Aryadev Chavali
3784d148c7 Update README 2024-11-01 11:29:53 +00:00
Aryadev Chavali
af730bedc0 Finished puzzle 6 in JabbaScript for 2015 2024-11-01 11:29:47 +00:00
Aryadev Chavali
c07e124b69 Finish part 2 of puzzle 5 for 2015. 2024-11-01 10:41:22 +00:00
Aryadev Chavali
389b39b1d5 Puzzle 5 part 1 of 2015 in rust (eww) 2024-11-01 03:05:00 +00:00
Aryadev Chavali
928dcb5572 Finished problem 4 of 2015 in racket 2024-11-01 02:32:49 +00:00
Aryadev Chavali
bbc5da95e7 Switched racket with rust (didn't want to use rust with external packages) 2024-11-01 02:32:32 +00:00
8 changed files with 326 additions and 6 deletions

View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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)))