/advent22

Advent of Code 2022

Primary LanguageRust

About

My main solutions are in Rust, but this document holds other solutions, mostly in AWK so far

Table of Contents

Day 1

Bash (mostly awk)

just change 1q to 3q for part 2

   awk '/^$/ {print sum; sum = 0}; {sum += $1}; END {print sum}' day1/input \
	 | sort -nr | sed 1q | paste -sd+ | bc -l

Just awk

s - 1 to s - 3 for part 2

   /^$/ {
	 sums[s++] = sum;
	 sum = 0
   }

   {
	 sum += $1
   }

   END {
	 asort(sums)
	 for (i = s; i > s - 1; i--) tot += sums[i]
	 print tot
   }

Day 2

my awk

   BEGIN {
	 hand["A"] = 1 # rock
	 hand["B"] = 2 # paper
	 hand["C"] = 3 # scissors
	 hand["X"] = 1 # rock
	 hand["Y"] = 2 # paper
	 hand["Z"] = 3 # scissors
   }

   function score(a, b) {
	 o = 0
	 t = 0
	 if (a == b) {
	     # draw
	     o += 3
	     t += 3;
	 } else if (a == 1 && b == 2) {
	     t += 6
	 } else if (a == 1 && b == 3) {
	     o += 6
	 } else if (a == 2 && b == 1) {
	     o += 6
	 } else if (a == 2 && b == 3) {
	     t += 6
	 } else if (a == 3 && b == 1) {
	     t += 6
	 } else if (a == 3 && b == 2) {
	     o += 6
	 }
	 o += a
	 t += b
	 return o" "t
   }

   {
	 # t"h"eirs
	 h = hand[$1]
	 # o"u"tcome
	 u = hand[$2]
	 switch (h" "u) {
	 case "2 2":
	 case "1 2":
	 case "3 2":
	     ours = h
	     break;
	 case "1 1":
	     ours = 3
	     break;
	 case "2 1":
	     ours = 1
	     break;
	 case "3 1":
	     ours = 2
	     break;
	 case "1 3":
	     ours = 2
	     break;
	 case "2 3":
	     ours = 3
	     break;
	 case "3 3":
	     ours = 1
	     break;
	 }
	 theirs = h
	 s = score(ours, theirs)
	 split(s, a, " ")
	 o = a[1]
	 t = a[2]
	 # print ours, theirs, o, t
	 tot += o
   }

   END { print tot }

awk after reading reddit

you can just write down all of the possible options and look up the answer. it could be even shorter if we could initialize a literal array without all of the assignments. you can translate this straight to Rust with a HashMap::from([...])

   BEGIN {
	 part1["A X"] = 1 + 3; part1["A Y"] = 2 + 6; part1["A Z"] = 3 + 0;
	 part1["B X"] = 1 + 0; part1["B Y"] = 2 + 3; part1["B Z"] = 3 + 6;
	 part1["C X"] = 1 + 6; part1["C Y"] = 2 + 0; part1["C Z"] = 3 + 3;

	 part2["A X"] = 3 + 0; part2["A Y"] = 1 + 3; part2["A Z"] = 2 + 6;
	 part2["B X"] = 1 + 0; part2["B Y"] = 2 + 3; part2["B Z"] = 3 + 6;
	 part2["C X"] = 2 + 0; part2["C Y"] = 3 + 3; part2["C Z"] = 1 + 6;

   }
   {
	 p1 += part1[$1" "$2]
	 p2 += part2[$1" "$2]
   }
   END { print p1; print p2 }

Day 3

   BEGIN {
   # build a table mapping characters to priorities
	FS = ""
	c = 27
	for (n = 65; n <= 90; n++) priority[sprintf("%c", n)] = c++
	c = 1
	for (n = 97; n <= 122; n++) priority[sprintf("%c", n)] = c++
   }
   {
   # part 1
	delete a
	for (i = 1; i <= NF/2; i++) a[$i] = 1
	for (i = NF/2 + 1; i <= NF; i++)
	    if (a[$i]) {
		tot1 += priority[$i]
		break;
	    }

   # part 2
	if (NR % 3 == 0) {
	    for (i = 1; i <= NF; i++)
		if (r1[$i] && r2[$i]) {
		    tot2 += priority[$i]
		    break;
		}
	    delete r1
	    delete r2
	} else if (NR % 3 == 1 ) {
	    for (i = 1; i <= NF; i++) r1[$i] = 1
	} else if (NR % 3 == 2) {
	    for (i = 1; i <= NF; i++) r2[$i] = 1
	}
   }
   END { print tot1, tot2 }

Day 4

   BEGIN { FS = "," }
   function contains(a, b) {return a[1] >= b[1] && a[2] <= b[2]}
   function contains_any(a, b) {return !(a[1] > b[2] || a[2] < b[1])}
   {
	split($1, a, "-");
	split($2, b, "-");
	sum1 += (contains(a, b) || contains(b, a)) ? 1 : 0
	sum2 += (contains_any(a, b) || contains_any(b, a)) ? 1 : 0
   }
   END { print sum1, sum2 }

Day 6

   BEGIN { FS = ""; width = 14 }
   {
	for (i = 1; i <= NF-width; i++) {
	    for (j = i; j < i+width; j++) {
		hold[$j] = 1;
	    }
	    if (length(hold) == width) {
		print i+width-1
		exit
	    }
	    delete hold
	}
   }

Day 7

Not my solution, but the top person’s (betaveros) from the leaderboard in his language noulith is pretty cool. I expected that you could ignore constructing a real directory tree, but I didn’t think actually explore that option in the code. It looks like under the assumption that you only list each directory’s contents once, you can treat the current directory as a stack and push the file’s size to every directory on the stack. With this, betaveros finished the challenge in just over 5 minutes compared to the more than 2 hours in my Rust video. I translate his noulith solution to awk here:

   BEGIN {
	# stack pointer since we can't push/pop in awk
	stack[1] = "/"
	p = 2
   }
   $2 ~ /^ls$/ { next }
   $1 ~ /^dir$/ { next }
   $2 ~ /^cd$/ {
	if ($3 == "/") {
	    stack[1] = "/"
	    p = 2
	}
	else if ($3 == "..") p--
	else stack[p++] = $3
	next
   }
   {
	# otherwise we're in a file
	for (i = p-1; i >= 1; i--) {
   if (stack[i] == "ddhfvv") print $0, "adding", sizes[stack[i]]
	    sizes[stack[i]] += $1
	}
   }
   END {
   print "missing: ", sizes["ddhfvv"]
   print "missing: ", sizes["jjshzrhd"]
   for (key in sizes) {
	    size = sizes[key]
	    if (size <= 100000) {
   print size, key
		tot += size
	    }
	}
	print tot
   }

Footer