changeset 52:0a0ff94175b5

Day 08 Part 1
author Lewin Bormann <lbo@spheniscida.de>
date Thu, 14 Dec 2023 13:10:22 +0100
parents fd579cbd3a93
children 52ad18a532ca
files 2023/day08.ml 2023/dune 2023/input/08.txt 2023/input/08_test.txt 2023/input/08_test2.txt
diffstat 5 files changed, 913 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/day08.ml	Thu Dec 14 13:10:22 2023 +0100
@@ -0,0 +1,88 @@
+open Base
+open Core
+open Angstrom
+
+(* good old simple hashtable *)
+module Hashtbl = Base.Hashtbl
+
+type direction = L | R [@@deriving sexp]
+type pointer = string [@@deriving sexp]
+type node = { id : pointer; left : pointer; right : pointer } [@@deriving sexp]
+type network = (pointer, node) Base.Hashtbl.t
+
+let create_network () = Hashtbl.create (module String)
+
+let string_of_network net =
+  let f ~key ~data acc =
+    Printf.sprintf "%s => (%s, %s)\n" key data.left data.right :: acc
+  in
+  let ss = Hashtbl.fold ~init:[] ~f net in
+  String.concat ss
+
+let network_of_nodes nodes : network =
+  let f n = (n.id, n) in
+  let l = List.map ~f nodes in
+  Hashtbl.of_alist_exn (module String) l
+
+module Parse = struct
+  let directionP = char 'L' *> return L <|> char 'R' *> return R
+  let instructionsP = many1 directionP <* char '\n'
+  let pointerP = take_while Char.is_uppercase
+
+  let nodeP =
+    let open Angstrom.Let_syntax in
+    let%bind id = pointerP in
+    let%bind _ = string " = (" in
+    let%bind left = pointerP in
+    let%bind _ = string ", " in
+    let%bind right = pointerP in
+    let%bind _ = char ')' in
+    let%bind _ = option '\n' (char '\n') in
+    return { id; left; right }
+
+  let contentsP =
+    let open Angstrom.Let_syntax in
+    let%bind instructions = instructionsP in
+    let%bind _ = char '\n' in
+    let%bind nodes = many1 nodeP in
+    let network = network_of_nodes nodes in
+    return (network, instructions)
+
+  exception Parse_exn of string
+
+  let parse_all ch =
+    let input = In_channel.input_all ch in
+    match parse_string ~consume:All contentsP input with
+    | Ok ok -> ok
+    | Error e -> raise (Parse_exn e)
+end
+
+module Part1 = struct
+  let rec traverse_once network current count instrs =
+    match current with
+    | "ZZZ" -> (current, count)
+    | _ -> (
+        let node = Hashtbl.find_exn network current in
+        match instrs with
+        | [] -> (current, count)
+        | x :: xs -> (
+            match x with
+            | L -> traverse_once network node.left (count + 1) xs
+            | R -> traverse_once network node.right (count + 1) xs))
+
+  let initial_node : pointer = "AAA"
+
+  let traverse network instructions =
+    let rec do_it from count0 =
+      match traverse_once network from count0 instructions with
+      | "ZZZ", count -> count
+      | from', count -> do_it from' count
+    in
+    do_it initial_node 0
+end
+
+let () =
+  let network, instructions = Parse.parse_all In_channel.stdin in
+  let count = Part1.traverse network instructions in
+  Out_channel.output_string Out_channel.stdout (string_of_network network);
+  Out_channel.printf "Took %d turns\n" count
--- a/2023/dune	Wed Dec 13 15:02:07 2023 +0100
+++ b/2023/dune	Thu Dec 14 13:10:22 2023 +0100
@@ -55,5 +55,14 @@
   (pps ppx_let ppx_sexp_conv)))
 
 (env
-  (dev
-    (flags (:standard -w -32-33))))
+ (dev
+  (flags
+   (:standard -w -32-33))))
+
+(executable
+ (name day08)
+ (modules day08)
+ (libraries base core angstrom)
+ (modes byte exe)
+ (preprocess
+  (pps ppx_let ppx_sexp_conv)))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/input/08.txt	Thu Dec 14 13:10:22 2023 +0100
@@ -0,0 +1,800 @@
+LRLRRRLRRRLLLRLRRLLRLRRRLRLRRRLRLRRRLRLRRRLRRRLRLLRRRLRLRLRRLRRLRLRRLRRLRRLLRRRLRRRLRRLRRLRRLRRRLLRRLRLRRLRLRRLRRLRLRRLRRLLRLRRRLRRLRRRLLRLRLRLLRLLRLLRLRRLLRRLRLRLRRLRLLRRRLLRRRLRRLLRRRLRRRLRLRRRLLRRRLRLRRRLLLRRRLRLRLRRRLRRRLRRRLRLRRLLLRRLRRRLLRLRRRLRLRLLLRRLRLRRRLRLRRRR
+
+GNK = (LBV, QNP)
+PJQ = (GHF, FJF)
+KLM = (TTR, BQL)
+LDT = (FXS, FBB)
+TKH = (NBH, JRN)
+QND = (KJC, SRD)
+SNG = (BQP, LXN)
+GMS = (JDN, NKM)
+NTL = (PTS, DHK)
+NBN = (FFD, PRL)
+NCP = (QKB, HMR)
+NQT = (RDK, BHC)
+TDK = (GHM, GHM)
+BJS = (TGC, GBJ)
+XNH = (GGJ, TKL)
+NKV = (GTC, NCP)
+HFL = (LQQ, RVT)
+HKC = (BQM, NKP)
+KCH = (GJG, GJG)
+MFD = (CRD, VDP)
+FNZ = (XSM, PQQ)
+NVT = (TDN, JVT)
+PCQ = (HLD, BKQ)
+GPF = (MNJ, NGP)
+PCX = (LPD, BJK)
+CCG = (TTS, TTS)
+BGG = (TQP, NFG)
+HSP = (DVS, QQM)
+TSX = (GBV, KXM)
+RKK = (BNC, FNZ)
+HVJ = (RPD, MGB)
+CXC = (BTD, VDN)
+NBH = (SQQ, PJB)
+CQN = (SRV, MCF)
+LPD = (PPR, RHS)
+BKM = (FJV, XTV)
+KQV = (PCK, DXJ)
+VCL = (PDN, MTC)
+JVS = (QQP, BDM)
+MJT = (JCX, NRR)
+VSR = (NQT, KNG)
+NKM = (HNF, BFD)
+HGJ = (BNT, KFK)
+VMC = (QND, RKC)
+DJG = (PRD, LBD)
+JCT = (NFM, NJF)
+FPX = (NJF, NFM)
+HPD = (SNT, JXR)
+QLK = (KXV, KLF)
+HMR = (TDK, CXJ)
+RQL = (QDP, GBQ)
+VDT = (BGP, MXH)
+PFV = (TNH, LQV)
+TTF = (FLV, SKM)
+QKL = (JNB, SKX)
+RXC = (QFP, VMV)
+NGJ = (QPN, GSF)
+MPZ = (JVH, BNB)
+FPB = (XNH, NMS)
+LQP = (SNG, VVM)
+HQF = (MNM, VHL)
+XXJ = (PRL, FFD)
+KPH = (TTF, SNQ)
+JDT = (KCH, JMC)
+KRK = (PCX, BMG)
+FJV = (QLK, QSN)
+MPG = (LJG, PKD)
+TCH = (RRQ, QTL)
+SDS = (JQR, BXR)
+RKR = (KVD, NGN)
+TVJ = (XGS, PCQ)
+VSQ = (NHP, QQS)
+RDK = (XTD, MHB)
+SGP = (PRP, XJD)
+SVN = (BKM, NSV)
+SJC = (DGL, FRH)
+NJX = (TRN, MHN)
+RCG = (BSN, DQR)
+HXJ = (KDL, SRR)
+BQZ = (PQL, FRM)
+NKS = (SHM, SHM)
+FPJ = (STM, CTN)
+SFM = (PVC, TGM)
+VSS = (MGV, JLS)
+DGL = (NBB, BST)
+XRQ = (LPN, MKF)
+RSZ = (SVM, XMG)
+TTK = (KST, MGQ)
+FJF = (CRC, RXF)
+CMT = (HPH, KPL)
+SDR = (LTD, TVK)
+BST = (KQV, QPH)
+DGT = (BCQ, MLX)
+QPN = (MMD, LKL)
+SHM = (FRM, PQL)
+XDD = (QCS, VMD)
+SNQ = (FLV, SKM)
+TLF = (QTC, GRK)
+CPB = (DFX, GDN)
+BRJ = (LDR, CDR)
+JNL = (JTD, SMV)
+FTG = (VRN, VRN)
+GBJ = (VGH, DJT)
+TGS = (FPB, QGT)
+MHB = (DKL, KMX)
+GNH = (SFQ, JXK)
+LTD = (XJQ, MBL)
+PCR = (JDD, KTL)
+DMD = (KHC, KVH)
+FTT = (LTB, BLD)
+LMT = (RKC, QND)
+JGT = (FDT, VDD)
+MDV = (XTS, MRF)
+PLV = (KXC, CNM)
+PRJ = (SHC, MNL)
+PML = (GRX, QGJ)
+VVM = (LXN, BQP)
+NGN = (GBG, XJX)
+VCG = (SRV, MCF)
+QFP = (TJS, XPD)
+LVX = (FPX, JCT)
+RBC = (DRM, VHC)
+XKT = (CCG, FLM)
+SDH = (BNF, GKN)
+BVQ = (QSH, VSQ)
+SMV = (SKN, HHJ)
+DBD = (RSM, PKB)
+DQR = (HVS, DVC)
+MNK = (DXT, CLD)
+FFD = (DLF, JPQ)
+GBG = (TKP, KPM)
+CHK = (MMT, MQC)
+BXR = (GMV, BGT)
+SFD = (XSP, SDS)
+PRT = (HDB, RCG)
+QXJ = (QQT, BHG)
+TGR = (TQD, TJM)
+GJG = (RVQ, TVJ)
+BFD = (SGS, NCH)
+PND = (BPL, TKV)
+JPG = (GNQ, QKP)
+FDT = (NPF, SFF)
+DLX = (XVP, BNR)
+SNT = (QFR, RMT)
+DND = (TVK, LTD)
+SSF = (LLF, FRV)
+DRK = (FTG, LBT)
+VQV = (JVS, RRH)
+XBV = (DSC, NRL)
+CVL = (KRF, NJX)
+XGP = (BQJ, RXC)
+MLX = (TBD, QSG)
+JDF = (CCG, CCG)
+GVN = (SCN, PKH)
+NCB = (GKN, BNF)
+LLF = (PND, LMM)
+SHX = (TXM, PRJ)
+KNL = (KSL, VQQ)
+JSK = (SQD, MPG)
+PPS = (KHC, KVH)
+NKJ = (DBD, RFB)
+CNM = (FCB, DHP)
+TXJ = (DBJ, DLX)
+QSH = (QQS, NHP)
+BRC = (PLN, GMS)
+BHP = (JNH, CLP)
+BQL = (SDR, DND)
+TGC = (VGH, DJT)
+MHM = (VHV, HFP)
+NGP = (HNN, HDX)
+SKM = (SXH, PTR)
+TFN = (SMK, GXL)
+NSR = (GLB, PCH)
+RHS = (XCX, RFH)
+BNC = (PQQ, XSM)
+XJX = (KPM, TKP)
+LFT = (TMH, SSP)
+KVD = (XJX, GBG)
+SKX = (NGF, NTC)
+CKQ = (FCL, MRM)
+MTC = (PBM, TGR)
+RHV = (TGS, KDV)
+MMD = (VMJ, TFN)
+PSM = (XDK, GSG)
+KXM = (RDN, XPS)
+PLN = (NKM, JDN)
+HDK = (SKX, JNB)
+XGS = (HLD, BKQ)
+FMB = (PHL, TFG)
+LHH = (XRF, STP)
+LTB = (TDC, BCX)
+FRV = (LMM, PND)
+GRK = (FDH, CQD)
+NRR = (HNS, KBJ)
+BGT = (LDT, VBJ)
+SRD = (CBG, DMM)
+KNF = (DVL, KNL)
+KXC = (FCB, DHP)
+GHB = (NNJ, QMH)
+PGQ = (JJX, VSF)
+SKB = (XXT, NTM)
+LXP = (PRD, LBD)
+PRL = (JPQ, DLF)
+FRM = (LBN, CPB)
+KSL = (FPT, TTC)
+CRC = (RCL, HQF)
+SVM = (BJS, XKD)
+PXB = (PMC, HPD)
+JPQ = (MKJ, MKC)
+TTR = (DND, SDR)
+CBH = (FTD, JJQ)
+XPS = (NSP, LSS)
+KMX = (QSL, SJC)
+CLD = (MDP, CKQ)
+GXV = (MKK, DBB)
+BQP = (TQH, LKN)
+FTB = (GJQ, GXV)
+KPL = (DRR, RSZ)
+MKF = (SDH, NCB)
+SSP = (CBN, XCF)
+XJQ = (NND, TPT)
+NTT = (NDJ, QFB)
+PLF = (NBH, JRN)
+XDK = (GPF, FSG)
+NTC = (DGT, XRB)
+SGJ = (QMH, NNJ)
+TNH = (VGB, FDR)
+DFX = (HFC, KTX)
+DBJ = (XVP, BNR)
+VDD = (SFF, NPF)
+JKL = (FRT, CVL)
+XSP = (BXR, JQR)
+DBP = (PSR, LJS)
+KHC = (MJT, KTP)
+TKP = (VRX, GVN)
+DKL = (SJC, QSL)
+DLP = (XXJ, NBN)
+KLN = (HRP, JPM)
+TPP = (NHJ, PCR)
+QVF = (QNP, LBV)
+VMD = (CTF, SFM)
+NFM = (QKL, HDK)
+MCF = (BJV, JXL)
+PQG = (XTQ, QMC)
+BGP = (HFT, KTD)
+PTS = (DDG, RBC)
+JLS = (SHL, VPT)
+DHT = (NPC, KRP)
+TJM = (KHM, BXB)
+TRH = (NDJ, QFB)
+CTF = (PVC, TGM)
+PMJ = (BHP, TDF)
+AAA = (MPF, VMM)
+XCF = (LVX, FNT)
+FRH = (BST, NBB)
+QLL = (HDB, RCG)
+XVP = (QHD, PML)
+BNX = (TLQ, TSX)
+BXB = (JSJ, KDQ)
+FPT = (LBC, VJF)
+FCB = (TJK, MJD)
+KNG = (RDK, BHC)
+DBB = (RFX, FLK)
+LQQ = (RTP, HGJ)
+LBT = (VRN, RLT)
+XKD = (GBJ, TGC)
+LKN = (XDD, CPC)
+XHM = (CNM, KXC)
+DTC = (QQT, BHG)
+BPL = (DMS, GQC)
+QPP = (MRF, XTS)
+PRK = (NKP, BQM)
+MGS = (MPG, SQD)
+STM = (MTS, GHD)
+SKD = (MGV, JLS)
+QPH = (DXJ, PCK)
+HDB = (DQR, BSN)
+DSC = (VXM, CHK)
+TQF = (GJT, FNJ)
+FXS = (GHQ, BVQ)
+SFF = (HKC, PRK)
+DRR = (XMG, SVM)
+RKP = (XXN, LDQ)
+NNJ = (KLG, HFL)
+VJF = (HMJ, RDC)
+LXN = (TQH, LKN)
+CXJ = (GHM, CMT)
+HMC = (GMS, PLN)
+LJS = (JDF, XKT)
+XCH = (TTR, BQL)
+LKG = (QXJ, DTC)
+QFB = (MHT, CFL)
+RDN = (LSS, NSP)
+DHS = (SHM, BQZ)
+NKT = (GSG, XDK)
+MCH = (HTP, BLC)
+NVX = (MGS, JSK)
+QTC = (FDH, FDH)
+NND = (DGP, LBF)
+GJV = (XHM, PLV)
+GSG = (FSG, GPF)
+BNV = (STM, CTN)
+LDQ = (MCH, GXS)
+MHN = (KPH, PKC)
+LBF = (PPS, DMD)
+QDP = (NKV, HSQ)
+MPF = (MNK, LTH)
+DHQ = (CDR, LDR)
+VMM = (MNK, LTH)
+HFT = (BRC, HMC)
+LTR = (NKT, PSM)
+HDX = (GJC, FTT)
+GHF = (RXF, CRC)
+BKQ = (FTB, HJH)
+BXX = (NJC, NPK)
+FVP = (BRG, NTJ)
+RDC = (LHT, VMG)
+JKT = (QPP, MDV)
+PVP = (GHB, SGJ)
+XXN = (GXS, MCH)
+SHC = (GNH, PCJ)
+GSF = (LKL, MMD)
+KRP = (MGL, VGQ)
+JXK = (TGN, TJP)
+MGQ = (XRQ, VBN)
+FLN = (MGB, RPD)
+DHP = (MJD, TJK)
+SQQ = (DVP, VCD)
+HFH = (CBH, JMM)
+MBP = (NDF, TFK)
+KLG = (RVT, LQQ)
+NPF = (PRK, HKC)
+NMS = (GGJ, TKL)
+QQP = (CGM, TCH)
+SFG = (NVG, NSR)
+RVQ = (XGS, PCQ)
+SQD = (PKD, LJG)
+JCX = (HNS, KBJ)
+QSN = (KXV, KLF)
+GLX = (NKT, PSM)
+TJS = (GJV, MPK)
+QLJ = (XJD, PRP)
+NSV = (FJV, XTV)
+GXX = (RFB, DBD)
+HSR = (BRG, NTJ)
+HBF = (CDC, NXL)
+XSS = (PSR, LJS)
+QTL = (TQF, HQM)
+TKL = (DNF, PVP)
+BRK = (JKQ, JKK)
+SCN = (MFC, PMJ)
+GMV = (VBJ, LDT)
+HNS = (LMT, VMC)
+RGR = (NTT, TRH)
+PNC = (KCH, KCH)
+XNK = (JNL, QFH)
+RRR = (PQT, NGR)
+TDN = (KBC, TTK)
+NQN = (KHN, SSF)
+HMK = (RRH, JVS)
+RFB = (PKB, RSM)
+SFQ = (TGN, TJP)
+JKQ = (SVN, BDB)
+CTN = (MTS, GHD)
+QNT = (TQP, NFG)
+VHL = (JJP, HBF)
+RFH = (PLF, TKH)
+KTD = (BRC, HMC)
+VRX = (SCN, PKH)
+BNT = (JKL, JCL)
+MDN = (DLC, BRK)
+CBG = (SKS, PJQ)
+QFH = (JTD, SMV)
+HVS = (XGP, CCX)
+NQH = (BKX, VSR)
+GQQ = (MBV, HMN)
+LSN = (NTM, XXT)
+FLQ = (RRR, QLT)
+LXM = (PRT, QLL)
+HJH = (GXV, GJQ)
+SRV = (JXL, BJV)
+TMH = (XCF, CBN)
+PRB = (KTV, NDD)
+JJQ = (QHQ, QDB)
+KSV = (NTT, TRH)
+XKH = (VJS, JGT)
+SJP = (QNT, BGG)
+NTR = (BNC, BNC)
+PBM = (TJM, TQD)
+RPD = (DVG, PRB)
+XPD = (MPK, GJV)
+NCH = (GKG, NGJ)
+KTP = (JCX, NRR)
+GQC = (QNR, PFV)
+MKC = (VLF, SFD)
+NTM = (FBF, XNK)
+TVK = (MBL, XJQ)
+RMT = (XKV, RHC)
+NHP = (DPM, MHM)
+JNB = (NGF, NTC)
+RTP = (BNT, KFK)
+GJT = (TKR, GPL)
+TTS = (VFM, VFM)
+FLK = (BNV, FPJ)
+CJJ = (QVF, GNK)
+QKP = (FBG, TPP)
+XQT = (JVT, TDN)
+JVH = (XKX, JKM)
+NDJ = (CFL, MHT)
+JXX = (BRK, DLC)
+XJD = (SMN, LKG)
+JXL = (KVB, RHV)
+VMG = (KKM, JKT)
+FBG = (NHJ, PCR)
+LKL = (VMJ, TFN)
+NXL = (XSS, DBP)
+SRC = (FTG, LBT)
+PDC = (CQN, VCG)
+BLD = (TDC, BCX)
+NHJ = (KTL, JDD)
+DGC = (VFM, ZZZ)
+LTX = (QTC, GRK)
+CCX = (BQJ, RXC)
+DRM = (DGB, PGX)
+VQQ = (TTC, FPT)
+BHC = (XTD, MHB)
+CDC = (DBP, XSS)
+SXH = (PNC, PNC)
+KBC = (KST, MGQ)
+DXT = (CKQ, MDP)
+PRP = (SMN, LKG)
+SGS = (NGJ, GKG)
+VBN = (LPN, MKF)
+BNF = (KGK, PGK)
+HLD = (FTB, HJH)
+FGT = (TCG, NTL)
+VBT = (DVS, QQM)
+XVT = (QLL, PRT)
+SBH = (BNB, JVH)
+VGB = (VSS, SKD)
+XJJ = (CXC, PKX)
+JKK = (BDB, SVN)
+BSN = (HVS, DVC)
+DBX = (QSR, HXJ)
+QSG = (KHJ, VMP)
+CPK = (CRD, VDP)
+JGD = (JMM, CBH)
+VGH = (CQM, DLP)
+GBQ = (HSQ, NKV)
+GRX = (LSN, SKB)
+FLM = (TTS, DGC)
+PPR = (XCX, RFH)
+VDP = (HVV, VDB)
+GKN = (PGK, KGK)
+XDA = (BNB, JVH)
+MNL = (PCJ, GNH)
+MGB = (PRB, DVG)
+FBB = (BVQ, GHQ)
+NTJ = (LXP, DJG)
+PQQ = (NVT, XQT)
+TQP = (TVG, FMV)
+LQK = (BPC, HSX)
+MTG = (TSM, PXB)
+VSF = (LXM, XVT)
+HJB = (BMG, PCX)
+VMJ = (GXL, SMK)
+CXB = (QLF, SJP)
+HCP = (SSF, KHN)
+QLH = (HSX, BPC)
+NFG = (TVG, FMV)
+PKB = (LHH, HKJ)
+BRG = (DJG, LXP)
+TLQ = (KXM, GBV)
+DDG = (DRM, VHC)
+BQM = (NVX, KLT)
+KTX = (LJP, DVH)
+XTS = (DHQ, BRJ)
+TFG = (VQV, HMK)
+JCD = (VSF, JJX)
+VFM = (MPF, VMM)
+LGJ = (NJC, NJC)
+PQB = (BGP, MXH)
+CBN = (LVX, FNT)
+FCL = (NQH, TXN)
+JNH = (RKP, QDF)
+LHT = (JKT, KKM)
+MJD = (PDC, PRV)
+QGT = (XNH, NMS)
+KST = (XRQ, VBN)
+KDV = (FPB, QGT)
+HFP = (NNK, MBP)
+BJK = (PPR, RHS)
+XXM = (MFD, CPK)
+QLT = (PQT, NGR)
+HMJ = (LHT, VMG)
+XDR = (TCG, NTL)
+NNK = (TFK, NDF)
+VJC = (NSR, NVG)
+MMM = (QLF, SJP)
+BNB = (XKX, JKM)
+LJG = (VJC, SFG)
+QQT = (SRF, XXM)
+JPM = (HSR, FVP)
+GNQ = (FBG, TPP)
+PJB = (VCD, DVP)
+NKP = (KLT, NVX)
+GJC = (LTB, BLD)
+MRF = (DHQ, BRJ)
+SRF = (CPK, MFD)
+FSS = (VXJ, DHG)
+XXZ = (TVJ, RVQ)
+NDD = (RGN, LSJ)
+TQD = (KHM, BXB)
+XJB = (PXB, TSM)
+LSJ = (XCH, KLM)
+JBJ = (JGD, HFH)
+DMS = (QNR, PFV)
+DLF = (MKC, MKJ)
+HNN = (FTT, GJC)
+VXM = (MQC, MMT)
+LMM = (TKV, BPL)
+BMG = (BJK, LPD)
+QGJ = (LSN, SKB)
+FRT = (NJX, KRF)
+SKN = (DHT, DBM)
+LBD = (JXX, MDN)
+KFK = (JKL, JCL)
+RRH = (BDM, QQP)
+NRL = (CHK, VXM)
+LCX = (VJS, JGT)
+CNR = (GBQ, QDP)
+TGN = (PQB, VDT)
+GRT = (DBJ, DLX)
+FDH = (NTR, NTR)
+CRD = (VDB, HVV)
+DMM = (PJQ, SKS)
+VHC = (PGX, DGB)
+FTD = (QDB, QHQ)
+NPC = (MGL, VGQ)
+PRV = (VCG, CQN)
+TSM = (PMC, HPD)
+CQM = (XXJ, NBN)
+BNR = (PML, QHD)
+NSP = (CBR, GQQ)
+TJK = (PRV, PDC)
+MST = (KNL, DVL)
+VMP = (JFF, PQG)
+TDF = (JNH, CLP)
+MQC = (HVJ, FLN)
+VPT = (BNX, JCC)
+GKP = (PHL, TFG)
+JJX = (XVT, LXM)
+MMT = (FLN, HVJ)
+CRP = (HFH, JGD)
+DBM = (KRP, NPC)
+LQV = (VGB, FDR)
+XRF = (GFV, PHK)
+RRQ = (TQF, HQM)
+RXF = (RCL, HQF)
+JRN = (PJB, SQQ)
+JTD = (SKN, HHJ)
+HTP = (JTR, VCL)
+JMM = (FTD, JJQ)
+MBL = (NND, TPT)
+RCL = (MNM, VHL)
+LGS = (QVF, GNK)
+CSC = (CNR, RQL)
+MFC = (BHP, TDF)
+HSX = (HSP, VBT)
+GBV = (RDN, XPS)
+VXJ = (QHV, LQP)
+JKM = (XJJ, GMC)
+MTS = (KRK, HJB)
+QDB = (DRK, SRC)
+GGJ = (DNF, PVP)
+XXT = (XNK, FBF)
+XSM = (XQT, NVT)
+QQM = (XJB, MTG)
+KDQ = (QLH, LQK)
+HNB = (TMH, SSP)
+FRJ = (VXJ, DHG)
+PQL = (LBN, CPB)
+SKS = (GHF, FJF)
+DLC = (JKQ, JKK)
+JMC = (GJG, XXZ)
+STP = (GFV, PHK)
+QNP = (LCX, XKH)
+KLF = (CJJ, LGS)
+XSA = (PQQ, XSM)
+KTV = (RGN, LSJ)
+FDR = (SKD, VSS)
+PCH = (GRT, TXJ)
+KTL = (XDR, FGT)
+LBB = (NRL, DSC)
+XKV = (JBJ, CRP)
+KHJ = (JFF, PQG)
+NGF = (XRB, DGT)
+DVH = (QLJ, SGP)
+MRM = (TXN, NQH)
+TGM = (LGJ, BXX)
+MKK = (RFX, FLK)
+RLT = (FBH, LGL)
+GXS = (HTP, BLC)
+XKX = (GMC, XJJ)
+VMV = (XPD, TJS)
+MGL = (LTX, TLF)
+NJC = (NKS, NKS)
+CLP = (QDF, RKP)
+SMK = (NKJ, GXX)
+KPM = (GVN, VRX)
+BCQ = (TBD, QSG)
+TPT = (LBF, DGP)
+CFA = (FRM, PQL)
+KVB = (TGS, KDV)
+BDM = (CGM, TCH)
+JJP = (CDC, NXL)
+PMC = (JXR, SNT)
+PGX = (HCP, NQN)
+LBC = (RDC, HMJ)
+MBV = (DBX, DDQ)
+KXV = (LGS, CJJ)
+DJT = (DLP, CQM)
+LDR = (LFT, HNB)
+GXL = (NKJ, GXX)
+SMN = (QXJ, DTC)
+DCJ = (GKP, FMB)
+GDN = (KTX, HFC)
+KGK = (PHN, KLN)
+VBJ = (FBB, FXS)
+DDQ = (QSR, HXJ)
+KJC = (CBG, DMM)
+BLC = (VCL, JTR)
+QNR = (LQV, TNH)
+KRF = (TRN, MHN)
+JFF = (QMC, XTQ)
+MPK = (PLV, XHM)
+PKC = (TTF, SNQ)
+VRN = (FBH, FBH)
+DVL = (VQQ, KSL)
+XTD = (KMX, DKL)
+VDB = (MXN, JPG)
+FMV = (RGR, KSV)
+HMN = (DDQ, DBX)
+TRN = (PKC, KPH)
+GKG = (QPN, GSF)
+MDP = (MRM, FCL)
+DHG = (QHV, LQP)
+BDB = (NSV, BKM)
+HPH = (DRR, DRR)
+BKX = (KNG, NQT)
+KVH = (KTP, MJT)
+VDN = (GLX, LTR)
+TFK = (CXB, MMM)
+CQD = (NTR, RKK)
+HHJ = (DBM, DHT)
+VHV = (NNK, MBP)
+FBF = (JNL, QFH)
+PKX = (BTD, VDN)
+PHK = (XBV, LBB)
+QMH = (KLG, HFL)
+SHL = (JCC, BNX)
+FNT = (JCT, FPX)
+HNF = (NCH, SGS)
+LBV = (LCX, XKH)
+MKJ = (SFD, VLF)
+CCL = (RRR, QLT)
+RSM = (HKJ, LHH)
+HFC = (LJP, DVH)
+MXH = (KTD, HFT)
+PVC = (LGJ, BXX)
+MNJ = (HNN, HDX)
+DHK = (DDG, RBC)
+JCL = (FRT, CVL)
+FSG = (NGP, MNJ)
+PHL = (HMK, VQV)
+GFV = (XBV, LBB)
+TXN = (BKX, VSR)
+GJQ = (DBB, MKK)
+XCX = (TKH, PLF)
+MHT = (KNF, MST)
+KDL = (FRJ, FSS)
+MNM = (JJP, HBF)
+XMG = (BJS, XKD)
+QHQ = (DRK, SRC)
+DVC = (CCX, XGP)
+QQS = (MHM, DPM)
+TVG = (KSV, RGR)
+CGM = (QTL, RRQ)
+QFR = (RHC, XKV)
+VLF = (XSP, SDS)
+DNF = (GHB, SGJ)
+QHV = (SNG, VVM)
+RVT = (HGJ, RTP)
+RGN = (XCH, KLM)
+QMC = (FLQ, CCL)
+TJP = (VDT, PQB)
+QKB = (TDK, CXJ)
+SND = (GKP, FMB)
+CPC = (QCS, VMD)
+KHN = (LLF, FRV)
+QLF = (BGG, QNT)
+VJS = (FDT, VDD)
+FNJ = (GPL, TKR)
+MXN = (GNQ, QKP)
+BQJ = (VMV, QFP)
+NPK = (NKS, DHS)
+HJA = (XMG, SVM)
+HQM = (FNJ, GJT)
+DVP = (DCJ, SND)
+BCX = (RKR, NTH)
+BHG = (XXM, SRF)
+HSQ = (GTC, NCP)
+TXM = (MNL, SHC)
+PQT = (CSC, XGC)
+NJF = (QKL, HDK)
+MGV = (VPT, SHL)
+TKR = (PGQ, JCD)
+LGL = (SBH, MPZ)
+PHN = (HRP, JPM)
+LBN = (GDN, DFX)
+JCC = (TSX, TLQ)
+DXJ = (SHX, CHB)
+KHM = (KDQ, JSJ)
+XRB = (BCQ, MLX)
+PCJ = (SFQ, JXK)
+DVS = (XJB, MTG)
+PCK = (CHB, SHX)
+TTC = (VJF, LBC)
+PKD = (VJC, SFG)
+GHM = (HPH, HPH)
+CHB = (PRJ, TXM)
+QSR = (KDL, SRR)
+TCG = (DHK, PTS)
+NGR = (CSC, XGC)
+VGQ = (LTX, TLF)
+JQR = (GMV, BGT)
+TQH = (CPC, XDD)
+KKM = (MDV, QPP)
+LSS = (CBR, GQQ)
+DVG = (KTV, NDD)
+TBD = (KHJ, VMP)
+PRD = (MDN, JXX)
+GPL = (PGQ, JCD)
+TKV = (GQC, DMS)
+RKC = (SRD, KJC)
+QSL = (DGL, FRH)
+JXR = (RMT, QFR)
+CFL = (MST, KNF)
+BJV = (RHV, KVB)
+PSR = (JDF, XKT)
+HPA = (RVQ, TVJ)
+QDF = (LDQ, XXN)
+GLB = (GRT, TXJ)
+BPC = (HSP, VBT)
+FLV = (SXH, PTR)
+JTR = (MTC, PDN)
+QCS = (CTF, SFM)
+SRR = (FSS, FRJ)
+DPM = (HFP, VHV)
+PDN = (PBM, TGR)
+VCD = (DCJ, SND)
+KBJ = (LMT, VMC)
+RHC = (CRP, JBJ)
+DGP = (DMD, PPS)
+HVV = (MXN, JPG)
+LTH = (DXT, CLD)
+XTV = (QSN, QLK)
+CBR = (MBV, HMN)
+CDR = (HNB, LFT)
+GHQ = (VSQ, QSH)
+TDC = (NTH, RKR)
+XTQ = (FLQ, CCL)
+GMC = (CXC, PKX)
+PGK = (PHN, KLN)
+NTH = (NGN, KVD)
+PKH = (PMJ, MFC)
+JDN = (HNF, BFD)
+FBH = (SBH, SBH)
+JDD = (FGT, XDR)
+HKJ = (XRF, STP)
+KLT = (MGS, JSK)
+GHD = (HJB, KRK)
+HRP = (FVP, HSR)
+PTR = (PNC, JDT)
+LJP = (SGP, QLJ)
+JVT = (TTK, KBC)
+ZZZ = (VMM, MPF)
+BTD = (GLX, LTR)
+GTC = (QKB, HMR)
+NDF = (CXB, MMM)
+DGB = (NQN, HCP)
+JSJ = (QLH, LQK)
+NBB = (KQV, QPH)
+XGC = (RQL, CNR)
+QHD = (GRX, QGJ)
+RFX = (FPJ, BNV)
+LPN = (NCB, SDH)
+NVG = (PCH, GLB)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/input/08_test.txt	Thu Dec 14 13:10:22 2023 +0100
@@ -0,0 +1,9 @@
+RL
+
+AAA = (BBB, CCC)
+BBB = (DDD, EEE)
+CCC = (ZZZ, GGG)
+DDD = (DDD, DDD)
+EEE = (EEE, EEE)
+GGG = (GGG, GGG)
+ZZZ = (ZZZ, ZZZ)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/2023/input/08_test2.txt	Thu Dec 14 13:10:22 2023 +0100
@@ -0,0 +1,5 @@
+LLR
+
+AAA = (BBB, BBB)
+BBB = (AAA, ZZZ)
+ZZZ = (ZZZ, ZZZ)