From 5191b7bd39276cbdccb2317edf2aaa3512ba67d3 Mon Sep 17 00:00:00 2001
From: h7x4 <h7x4@nani.wtf>
Date: Sun, 11 Dec 2022 19:01:30 +0100
Subject: [PATCH] Day 10

---
 day10/default.nix |  98 ++++++++++++++++++++++++++++++++
 day10/input.txt   | 139 ++++++++++++++++++++++++++++++++++++++++++++++
 flake.nix         |   1 +
 3 files changed, 238 insertions(+)
 create mode 100644 day10/default.nix
 create mode 100644 day10/input.txt

diff --git a/day10/default.nix b/day10/default.nix
new file mode 100644
index 0000000..a3cf278
--- /dev/null
+++ b/day10/default.nix
@@ -0,0 +1,98 @@
+{ pkgs, lib }:
+
+with lib;
+
+let
+  # See https://github.com/NixOS/nixpkgs/pull/205457
+  toInt = str:
+    let
+      inherit (builtins) match fromJSON;
+      # RegEx: Match any leading whitespace, possibly a '-', one or more digits,
+      # and finally match any trailing whitespace.
+      strippedInput = match "[[:space:]]*(-?[[:digit:]]+)[[:space:]]*" str;
+
+      # RegEx: Match a leading '0' then one or more digits.
+      isLeadingZero = match "0[[:digit:]]+" (head strippedInput) == [];
+
+      # Attempt to parse input
+      parsedInput = fromJSON (head strippedInput);
+
+      generalError = "toInt: Could not convert ${escapeNixString str} to int.";
+
+      octalAmbigError = "toInt: Ambiguity in interpretation of ${escapeNixString str}"
+      + " between octal and zero padded integer.";
+
+    in
+      # Error on presence of non digit characters.
+      if strippedInput == null
+      then throw generalError
+      # Error on presence of leading zero/octal ambiguity.
+      else if isLeadingZero
+      then throw octalAmbigError
+      # Error if parse function fails.
+      else if !isInt parsedInput
+      then throw generalError
+      # Return result.
+      else parsedInput;
+
+  lineToInstruction = line:
+    if line == "noop"
+      then { type = "n"; }
+      else { type = "a"; val = toInt (elemAt (splitString " " line) 1); };
+
+  foldToSignalState = { cycles ? 0, X ? 0, nextX ? 1 }: instructions: let
+    instr = head instructions;
+    nextSignalState = if instr.type == "n" 
+                        then { cycles = 1; X = nextX; inherit nextX; }
+                        # Implicit `addx`
+                        else { cycles = 2; X = nextX; nextX = nextX + instr.val; };
+  in if instructions == [] then [] else [nextSignalState] ++ (foldToSignalState nextSignalState (tail instructions));
+
+  repeat = item: times: map (const item) (range 1 times);
+
+  expandSignalStates = signalStates: let
+    s = head signalStates;
+  in if signalStates == []
+       then []
+       else (repeat s.X s.cycles) ++ (expandSignalStates (tail signalStates));
+
+  takeWithStride = n: l:
+    if l == [] then [] else [(head l)] ++ takeWithStride n (drop n l);
+
+  signalStates = pipe ./input.txt [
+    fileContents
+    (splitString "\n")
+    (map lineToInstruction)
+    (foldToSignalState {})
+    expandSignalStates
+  ];
+
+  answer1 = pipe signalStates [
+    (imap1 (i: v: i * v))
+    (drop 19)
+    (takeWithStride 40)
+    (foldr add 0)
+    toString
+  ];
+
+  splitAtInterval = n: list:
+    if list == [] then []
+                  else [(take n list)] ++ (splitAtInterval n (drop n list));
+
+  f = i: v: if v <= i && i <= v + 2 then "#" else ".";
+
+  answer2 = pipe signalStates [
+    (splitAtInterval 40)
+    (map (imap1 f))
+    (map (concatStringsSep ""))
+    (concatStringsSep "\n")
+    toString
+  ];
+
+in pkgs.writeText "answers" ''
+  Task1:
+    ${answer1}
+
+  Task2:
+  ${answer2}
+''
diff --git a/day10/input.txt b/day10/input.txt
new file mode 100644
index 0000000..008b1e7
--- /dev/null
+++ b/day10/input.txt
@@ -0,0 +1,139 @@
+noop
+noop
+noop
+addx 5
+noop
+addx 1
+addx 2
+addx 5
+addx 2
+addx 1
+noop
+addx 5
+noop
+addx -1
+noop
+addx 5
+noop
+noop
+addx 5
+addx 1
+noop
+noop
+addx 3
+addx 2
+noop
+addx -38
+noop
+addx 3
+addx 2
+addx -5
+addx 12
+addx 2
+addx 27
+addx -40
+addx 19
+addx 2
+addx 19
+addx -18
+addx 2
+addx 5
+addx 2
+addx -23
+addx 22
+addx 4
+addx -34
+addx -1
+addx 5
+noop
+addx 2
+addx 1
+addx 20
+addx -17
+noop
+addx 25
+addx -17
+addx -2
+noop
+addx 3
+addx 19
+addx -12
+addx 3
+addx -2
+addx 3
+addx 1
+noop
+addx 5
+noop
+noop
+addx -37
+addx 3
+addx 4
+noop
+addx 24
+addx -6
+addx -15
+addx 2
+noop
+addx 6
+addx -2
+addx 6
+addx -12
+addx -2
+addx 19
+noop
+noop
+noop
+addx 3
+noop
+addx 7
+addx -2
+addx -24
+addx -11
+addx 4
+addx 3
+addx -2
+noop
+addx 7
+addx -2
+addx 2
+noop
+addx 3
+addx 7
+noop
+addx -2
+addx 5
+addx 2
+addx 5
+noop
+noop
+noop
+addx 3
+addx -35
+addx 35
+addx -21
+addx -14
+noop
+addx 5
+addx 2
+addx 33
+addx -7
+addx -23
+addx 5
+addx 2
+addx 1
+noop
+noop
+addx 5
+addx -1
+noop
+addx 3
+addx -23
+addx 30
+addx 1
+noop
+addx 4
+addx -17
+addx 11
+noop
+noop
diff --git a/flake.nix b/flake.nix
index 3b851c1..ff7513f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -14,6 +14,7 @@
       day06 = pkgs.callPackage ./day06 { };
       day07 = pkgs.callPackage ./day07 { };
       day08 = pkgs.callPackage ./day08 { };
+      day10 = pkgs.callPackage ./day10 { };
     };
   };
 }