diff --git a/2023/day08_haunted_wasteland/Cargo.toml b/2023/day08_haunted_wasteland/Cargo.toml new file mode 100644 index 0000000..0477dc4 --- /dev/null +++ b/2023/day08_haunted_wasteland/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "day08_haunted_wasteland" +version = "0.1.0" +edition = "2021" +rust-version.workspace = true + +[dependencies] +log.workspace = true +env_logger.workspace = true +nom.workspace = true +num.workspace = true diff --git a/2023/day08_haunted_wasteland/README.md b/2023/day08_haunted_wasteland/README.md new file mode 100644 index 0000000..2c7722d --- /dev/null +++ b/2023/day08_haunted_wasteland/README.md @@ -0,0 +1,25 @@ +Very cheeky part 2. I basically winged it after seeing the example and +thinking that "surely that's the least common multiple". I looked at the input +and saw that the paths cycle (aka the end node cycles back to the start node) +and then I just prayged that the cycles are "clean". It worked, but solution +would definitely break on an input that's not this constrained. + +--- + +Being able to pass functions as arguments leads to some really nice code since +you can code what an end node is through a: +``` +is_end_node: fn(&str) -> bool, +``` +And use that as a break condition for the traversal. + +--- + +Imported a new crate called `num` for the `lcm` implementation. I had not +pulled in a new crate in a very long time. + +--- + +To have an iterator go back to the start when it reaches the end one can use +the `cycle` function. I am surprised I have not used this before. It made it +very easy to cycle through the instructions endlessly. diff --git a/2023/day08_haunted_wasteland/input b/2023/day08_haunted_wasteland/input new file mode 100644 index 0000000..4319a01 --- /dev/null +++ b/2023/day08_haunted_wasteland/input @@ -0,0 +1,768 @@ +LRLRLLRRLRRRLRLRRLRLLRRLRRRLRLRLRLRRLRLLRRRLRRRLLRRLRRLRLRRRLLLRRLRLRLRLRLRLLRRRLRLRRRLRRRLRRRLRRRLRRRLRRRLRRRLRRLRRRLLRLLRRLRRLRRLRRRLLRLRRLRLRLRRLLRLRRRLRRLLRLRLRRRLRRLRRLRRLRLLRLRRRLLLRRRLLLLRRLRRRLLLRRLLRLRLRLLLRRRLLRRRLLLRLRRLLRRRLRRRLRLLRRRLRLRLRLLRRLLRRLRRRLRLRRRLRRLRLRRLRRRR + +SGR = (JLL, VRV) +XDC = (TBG, KNF) +QRS = (BVR, VGS) +BHD = (SFQ, LFL) +KJN = (BVB, SNM) +MVR = (XNS, GXN) +KTX = (GHQ, QRL) +GLH = (GPF, PLR) +XKH = (BTC, CKN) +MXM = (HDB, BVC) +MRG = (KFG, SFF) +SBM = (PVH, CJK) +DPH = (TBV, QCV) +NKL = (TRR, GRQ) +BNL = (RBS, DMT) +KHB = (RQQ, HPL) +KSB = (HQM, NXH) +CKX = (XQT, KJK) +LFC = (RMT, LCM) +BFN = (FVH, DNL) +TNT = (HCH, CKX) +RQK = (BQB, JQS) +MKH = (MPH, VMJ) +CCJ = (HMF, DXJ) +XFT = (GNC, RQT) +DPD = (JJG, RSN) +LLH = (TMP, XVH) +GFT = (XJV, PVG) +QFL = (RBH, VLM) +QFF = (JVR, NJN) +SVT = (LSH, TSV) +FQG = (QTJ, JNM) +JVR = (CGX, BML) +SGL = (KLN, RFH) +HFX = (GJD, LMK) +MRD = (JLV, JLV) +TRF = (KXR, LNS) +VRH = (XJV, PVG) +PQX = (VDS, QXZ) +RMF = (HTT, TCG) +JJG = (VKL, FLQ) +TKQ = (HCH, CKX) +SKD = (XPX, BTV) +XGB = (GXT, TBL) +HDB = (DQC, GRK) +LNS = (HXJ, HLB) +XNC = (LXP, LPD) +HNL = (DPD, HBN) +KVJ = (JGP, LFC) +FNK = (SDF, SDF) +FPM = (DNG, PGL) +LLJ = (VKC, SGR) +KJX = (NKH, HKD) +HQM = (JFL, RFM) +NXV = (DHL, SMB) +KHM = (NSK, NRL) +KDG = (RTN, JFN) +HTT = (PTL, GQQ) +CKT = (KQT, RQS) +QQB = (TBX, CXG) +HHV = (NBD, KDG) +TSR = (JKF, QST) +PFS = (TJV, NDR) +DXJ = (HNL, SHS) +GRK = (XSH, CGM) +KPT = (LKJ, KVJ) +FBG = (CTQ, GGP) +SBD = (QKN, JKM) +JTB = (JRR, RCX) +CFF = (RNF, FGG) +TQH = (PJP, RVH) +RBH = (JKS, VXD) +LKJ = (JGP, LFC) +RVS = (QSC, NMX) +DCG = (SVV, KMP) +MBP = (NDP, BJS) +FVH = (KDB, GXQ) +PGL = (QCX, PPL) +MTZ = (TDF, DCG) +HKM = (VMJ, MPH) +MCL = (XPR, PGN) +LBV = (FFD, VVD) +QCV = (GPG, KFR) +QSC = (JPL, NNG) +FBH = (MRD, DGL) +MNG = (KLM, LFG) +XKR = (VNT, BFB) +RNG = (KFL, NQX) +RCK = (TDD, PQX) +KSN = (FFD, VVD) +NQX = (TNS, KCM) +KFG = (QLH, QSR) +LMK = (XDM, CJS) +JJC = (TSR, FQP) +KMR = (NBD, KDG) +XPM = (LXT, JCH) +VTP = (RNG, JLB) +KFL = (TNS, KCM) +JSB = (NDR, TJV) +QKA = (QQD, SSM) +NFP = (JPT, DPM) +DKP = (RTD, PCV) +BJT = (KJM, KJM) +BVC = (DQC, GRK) +QQD = (JRH, TCB) +KMP = (SLM, GDX) +GMJ = (DMV, CMS) +RTX = (SKV, LCK) +SFQ = (TMM, MGX) +NML = (XRT, GRM) +BGT = (GDB, VDT) +RGG = (NLQ, JNT) +XQV = (DKX, LGQ) +SGF = (LHD, NJL) +RKL = (JKK, NDZ) +HPL = (GNQ, FTF) +JLP = (RBV, TLD) +XSN = (HQM, NXH) +HRD = (DXJ, HMF) +GMV = (PQF, STD) +JCC = (CTK, XQD) +RXM = (LSM, BPH) +KRF = (XGB, CJN) +FFS = (NNK, DLC) +XJV = (LPM, QFL) +JHV = (CXG, TBX) +LJP = (BJQ, JTB) +TBX = (SRF, VNC) +LKM = (XBB, GJT) +NSV = (VBV, GBV) +VDT = (RBT, LLJ) +MGF = (MQB, LRM) +QQK = (BFC, MBP) +TLD = (RGG, HSX) +QFC = (QBB, VPV) +PJF = (NGG, MRG) +DLT = (TLM, JBR) +SRP = (QQK, FRH) +GNQ = (PCP, CFM) +VHR = (PBK, PBK) +RCX = (SDD, QXM) +JSJ = (LGJ, TJG) +JJP = (TCQ, NJQ) +HJL = (FNQ, JSD) +DLG = (XQJ, PFH) +QHK = (XKP, RTR) +GBV = (FKC, LSR) +QVX = (TFD, KFB) +GDX = (GHJ, LNX) +LSR = (SQD, VMT) +PPN = (KHB, FRV) +CKN = (CSD, QRD) +BVX = (RKM, LXN) +FPR = (KJM, RCK) +NLX = (XKR, PNK) +XSH = (PHB, NRD) +TXH = (KTD, BPD) +SSM = (JRH, TCB) +VTD = (MXM, JCV) +HND = (NKH, HKD) +CJN = (TBL, GXT) +VJJ = (PCM, QLC) +PGD = (BJM, NBR) +VVD = (GRR, FVM) +GNC = (PRJ, LJP) +DLP = (VXJ, TSB) +LJD = (BLF, BHD) +XQD = (DRT, VTP) +BFB = (CBK, CHB) +QBB = (FFS, PFR) +KDH = (TTK, MNG) +STD = (MQP, MJB) +RVH = (DLP, HVQ) +LRL = (JQP, DLT) +PFH = (GMJ, LVN) +JLV = (CHD, CHD) +QRL = (HVB, DKP) +SRR = (FQV, TQD) +VPV = (PFR, FFS) +JFN = (XQP, FGF) +MJP = (LRT, XKS) +SMB = (QHK, TSS) +GPZ = (PFH, XQJ) +MTB = (LCK, SKV) +XKP = (HMN, FGJ) +BQK = (MBG, JCQ) +BLR = (FMH, VJJ) +VMA = (DCG, TDF) +SDD = (VRK, NTJ) +JRN = (SRC, LKV) +BPM = (MXM, JCV) +PBR = (VBB, SRK) +FGH = (CMP, TFP) +BCD = (PBR, GBB) +TCG = (PTL, GQQ) +GKT = (RBF, SVS) +SLS = (CCT, MDM) +FHL = (NDG, LSS) +RPD = (SRQ, RDQ) +VDR = (SJR, CKP) +CTQ = (JHK, QFS) +MXD = (CJK, PVH) +NDR = (RMF, SCG) +NBD = (RTN, JFN) +RQS = (CQN, GMV) +BTV = (NQT, SXK) +PNK = (VNT, BFB) +LFL = (TMM, MGX) +KDV = (KTD, BPD) +HLS = (RRC, PNL) +TQD = (QFF, PFQ) +SQD = (XHT, MXH) +PGN = (GLH, GCQ) +NMX = (NNG, JPL) +BLF = (LFL, SFQ) +XBB = (BGQ, FCL) +QSR = (GNB, RPH) +KSG = (FHL, KKJ) +HFG = (KVL, KDH) +TQS = (CKN, BTC) +FRF = (DDX, DGP) +DVC = (MGF, CLJ) +BTC = (CSD, QRD) +QXZ = (SSM, QQD) +QCX = (KDV, TXH) +DHL = (TSS, QHK) +CGM = (PHB, NRD) +DQQ = (DDX, DGP) +VNL = (LPX, HTQ) +BPD = (KKP, PNH) +LHQ = (PFS, JSB) +RKQ = (LDR, KTV) +GSK = (DMT, RBS) +FKC = (SQD, VMT) +BFC = (BJS, NDP) +JBX = (XPR, PGN) +FGG = (MBR, FCR) +TXN = (TVL, XRX) +HMN = (BPQ, XSP) +CCT = (FGH, MPS) +KQT = (CQN, GMV) +CVG = (FRV, KHB) +LPM = (VLM, RBH) +PLR = (FVB, GSR) +KXR = (HLB, HXJ) +NSK = (JQK, DXL) +QGL = (TQD, FQV) +VBB = (BPM, VTD) +FQV = (PFQ, QFF) +BJS = (JRL, KMX) +DSL = (RVS, MST) +PCM = (RLL, LKK) +RPQ = (HND, KJX) +JPT = (QGJ, RDM) +BSR = (BPH, LSM) +AAA = (KPT, QLD) +RPH = (LBV, KSN) +CTJ = (TPQ, KTL) +KDB = (BGT, LRJ) +TNG = (VPF, FQG) +CQN = (PQF, STD) +KJM = (TDD, TDD) +HKV = (LPD, LXP) +FDQ = (KBM, NFP) +FLQ = (RNC, CTJ) +HKD = (CKT, DTR) +VXD = (SKK, BHJ) +SLH = (KHM, RJJ) +GHL = (NBR, BJM) +TCB = (NVB, CTH) +PRJ = (JTB, BJQ) +CMP = (HFG, BLT) +VKM = (PGL, DNG) +MBG = (KRS, PCL) +PPC = (HJL, GSP) +FTT = (FDQ, KVR) +GDT = (NML, HDD) +PXC = (XBB, GJT) +VRV = (DHS, FKR) +GDN = (KPT, QLD) +DXL = (FTT, LNK) +LPD = (RTX, MTB) +FCD = (FLK, JCC) +HSX = (JNT, NLQ) +ZZZ = (QLD, KPT) +CNV = (CHC, SHX) +TRP = (VJJ, FMH) +CKD = (JKK, JKK) +BVR = (DKQ, JHM) +TBG = (LVG, SHF) +GQQ = (MKH, HKM) +QRG = (TCQ, NJQ) +SBH = (DSL, LVD) +BTM = (LRL, NDV) +FRH = (MBP, BFC) +PCP = (XVB, LHQ) +RKA = (BGX, BCX) +VNP = (LXN, RKM) +KLM = (JXT, GMQ) +BJM = (XNC, HKV) +NRS = (KPP, KVM) +DJT = (DVC, FGT) +GPG = (BBK, XDC) +MLD = (NJL, LHD) +LSS = (SFX, RRT) +VMT = (XHT, MXH) +FCQ = (PPN, CVG) +LRT = (XMS, BRN) +QKN = (MVR, HSR) +XDR = (NQM, LQT) +LHD = (QRG, JJP) +VHZ = (HFX, CVR) +DRT = (JLB, RNG) +VMF = (KSP, SGX) +PTL = (MKH, HKM) +FGT = (CLJ, MGF) +TJV = (SCG, RMF) +JKK = (BGX, BCX) +TFP = (HFG, BLT) +DDX = (PTH, RCS) +MPS = (CMP, TFP) +QTJ = (TVK, TVK) +TVL = (XKH, TQS) +BRN = (KSQ, KRP) +FCR = (MXD, SBM) +TJG = (CFF, CSS) +XVH = (LHP, TBT) +KBL = (SHX, CHC) +GPF = (GSR, FVB) +XRX = (TQS, XKH) +FMT = (QGL, SRR) +JQK = (FTT, LNK) +XNS = (LLH, RNH) +FTF = (CFM, PCP) +NLH = (SGF, MLD) +CTK = (VTP, DRT) +XJX = (DCG, TDF) +NDZ = (BCX, BGX) +GPK = (RKX, RMP) +FGF = (RXM, BSR) +HVQ = (VXJ, TSB) +KDF = (TLF, DPH) +TFD = (HSN, SBH) +LXN = (JDK, LBM) +RJJ = (NRL, NSK) +DLC = (GKT, KCC) +JSR = (NQM, LQT) +DKX = (PXC, LKM) +NNK = (KCC, GKT) +CSD = (QQB, JHV) +LKV = (JFQ, VMM) +KVL = (TTK, MNG) +PTH = (GPK, SPN) +JHK = (VKM, FPM) +GXN = (LLH, RNH) +FVB = (XRL, JSJ) +RBS = (KMM, PPC) +BGQ = (SLH, HPV) +QQQ = (GDN, ZZZ) +KFR = (BBK, XDC) +TDF = (SVV, KMP) +RSN = (FLQ, VKL) +TMH = (HQG, KDF) +QRD = (JHV, QQB) +MGX = (MVB, SGL) +JBR = (PJF, QRB) +GCQ = (GPF, PLR) +VKL = (RNC, CTJ) +RFM = (FCD, VFT) +QSD = (KHP, VSF) +BQB = (NRS, NXG) +GMQ = (TLP, TXN) +XMS = (KSQ, KRP) +LQT = (PRL, VGG) +HDG = (MRD, DGL) +QND = (TKQ, TNT) +JKF = (CNV, KBL) +TRR = (XXS, SXL) +XRT = (RPQ, DKC) +LQQ = (RQK, BSB) +VDS = (QQD, SSM) +MQP = (BVX, VNP) +PHB = (PGD, GHL) +NNG = (CBC, XFT) +KJD = (PBM, HQK) +FFD = (GRR, FVM) +NNT = (BHD, BLF) +CDP = (TNG, MBH) +FQP = (JKF, QST) +PRL = (XML, XML) +DPM = (QGJ, RDM) +NHT = (PBK, JGV) +PVG = (LPM, QFL) +NJQ = (TFJ, KTX) +SLM = (LNX, GHJ) +XML = (XJX, XJX) +XDM = (BCC, NLX) +LRF = (TLC, BDQ) +TLF = (QCV, TBV) +SGX = (NKL, DPG) +TMM = (MVB, SGL) +SHS = (DPD, HBN) +CHD = (GDN, GDN) +HTQ = (NCV, MJP) +SHX = (NDF, VKQ) +GXT = (LRF, BMG) +RKM = (JDK, LBM) +XHB = (BNL, GSK) +VKQ = (VMF, MDF) +KCC = (SVS, RBF) +PPX = (NFL, QVP) +CBC = (GNC, RQT) +PRV = (DDB, SNX) +SVF = (GGP, CTQ) +NFL = (VSG, QRS) +LHN = (BJT, FPR) +MLC = (HTQ, LPX) +DNR = (GGR, LQQ) +DPG = (TRR, GRQ) +BVB = (GFT, VRH) +DTR = (RQS, KQT) +SRK = (VTD, BPM) +KLN = (PQC, FPF) +JFT = (JKM, QKN) +HKL = (DVC, FGT) +BQD = (BVB, SNM) +RLL = (FNK, PBQ) +PNH = (XSN, KSB) +DKQ = (SLS, QMV) +BSB = (BQB, JQS) +VGG = (XML, CPF) +FNC = (VFC, PRV) +BDQ = (NLH, BGC) +NVB = (DQQ, FRF) +NDF = (MDF, VMF) +NQM = (PRL, PRL) +JVL = (SRP, GSB) +NXG = (KPP, KVM) +MPH = (LXH, SXV) +JNM = (TVK, CSR) +VFT = (FLK, JCC) +RFH = (FPF, PQC) +XQT = (KSG, LFP) +KPP = (CJJ, SNK) +XXS = (TRB, SBR) +PCL = (JVL, NPD) +HBN = (RSN, JJG) +TLC = (NLH, BGC) +JGP = (RMT, LCM) +DRG = (TFD, KFB) +FNQ = (HVJ, BCD) +DMT = (PPC, KMM) +SVS = (MCL, JBX) +GSV = (SRC, LKV) +BHJ = (BFN, KLB) +VPF = (QTJ, QTJ) +LRJ = (VDT, GDB) +TBL = (LRF, BMG) +SVV = (GDX, SLM) +NXH = (RFM, JFL) +FLK = (XQD, CTK) +PFQ = (JVR, NJN) +MVB = (KLN, RFH) +RBF = (MCL, JBX) +NRD = (GHL, PGD) +PPL = (KDV, TXH) +SXV = (QQM, NGC) +LNK = (FDQ, KVR) +SFX = (FNC, GKD) +FMH = (PCM, QLC) +HVJ = (GBB, PBR) +CSR = (DLG, GPZ) +QVP = (VSG, QRS) +QST = (CNV, KBL) +NTJ = (SVT, FKX) +GRQ = (XXS, SXL) +HSR = (GXN, XNS) +XRL = (LGJ, TJG) +SDV = (PNL, RRC) +MXH = (SMD, GDT) +KRS = (JVL, NPD) +TVK = (DLG, DLG) +FPF = (BQD, KJN) +SGB = (BQK, SVR) +KNF = (SHF, LVG) +TPQ = (NXV, LRD) +HDD = (GRM, XRT) +BGX = (HCX, TMH) +TTK = (LFG, KLM) +RTD = (KPM, XHB) +XSD = (QBB, VPV) +SNM = (GFT, VRH) +LPX = (NCV, MJP) +DDB = (RMX, NJJ) +MJB = (BVX, VNP) +JKS = (SKK, BHJ) +MDF = (SGX, KSP) +KHP = (FTJ, RKQ) +FGJ = (XSP, BPQ) +LKK = (FNK, PBQ) +CFM = (LHQ, XVB) +KKP = (KSB, XSN) +LVG = (NSV, MCF) +RKX = (FCQ, SNH) +NLD = (GGR, LQQ) +QMV = (MDM, CCT) +TCQ = (KTX, TFJ) +LXT = (JSR, XDR) +TFJ = (GHQ, QRL) +TMP = (LHP, TBT) +MDM = (FGH, MPS) +KVM = (CJJ, SNK) +LXP = (RTX, MTB) +DHB = (CVR, HFX) +SCG = (HTT, TCG) +TLM = (PJF, QRB) +CJJ = (JLP, JQJ) +CHB = (QNV, RPD) +JGV = (DHB, VHZ) +VSG = (VGS, BVR) +SKV = (FHB, BDD) +TSS = (RTR, XKP) +VNT = (CBK, CHB) +TDD = (VDS, VDS) +NDV = (DLT, JQP) +MBH = (VPF, FQG) +KJK = (KSG, LFP) +LRD = (SMB, DHL) +SRF = (PNP, KJD) +JDK = (DRG, QVX) +CCP = (SKD, BVG) +BML = (QSD, NLB) +SJR = (DJT, HKL) +SRC = (JFQ, VMM) +CTH = (FRF, DQQ) +BCC = (XKR, PNK) +MBR = (MXD, SBM) +JPL = (CBC, XFT) +JCH = (JSR, XDR) +JDS = (SJR, CKP) +PBK = (DHB, DHB) +QRB = (NGG, MRG) +LVN = (DMV, CMS) +QLH = (GNB, RPH) +NQT = (QND, HKQ) +FHB = (LJD, NNT) +QXM = (VRK, NTJ) +RDQ = (HLS, SDV) +KTD = (PNH, KKP) +KRP = (TRP, BLR) +VNC = (PNP, KJD) +DHS = (BXD, XPM) +XPX = (NQT, SXK) +KCG = (RVH, PJP) +HCX = (KDF, HQG) +NBR = (HKV, XNC) +TSV = (QFC, XSD) +SRQ = (SDV, HLS) +LBM = (DRG, QVX) +SHF = (NSV, MCF) +RRC = (PFN, JJC) +HKQ = (TKQ, TNT) +KKJ = (LSS, NDG) +LSM = (HDG, FBH) +VFC = (DDB, SNX) +CGX = (NLB, QSD) +RQT = (LJP, PRJ) +CJS = (BCC, NLX) +NKH = (CKT, DTR) +TSB = (CDP, RRG) +HSN = (DSL, LVD) +LNX = (KRF, KJV) +LHP = (CCJ, HRD) +RQQ = (FTF, GNQ) +GNB = (LBV, KSN) +PMR = (CHD, QQQ) +DGQ = (KXR, LNS) +RRG = (TNG, MBH) +FRV = (HPL, RQQ) +RNC = (TPQ, KTL) +HQG = (TLF, DPH) +JRH = (CTH, NVB) +DMV = (DHN, BTM) +RBT = (SGR, VKC) +JRL = (GSV, JRN) +FVM = (NLD, DNR) +KTV = (TQH, KCG) +SDF = (CKD, CKD) +LRM = (SVF, FBG) +RRT = (FNC, GKD) +LGQ = (LKM, PXC) +BDD = (LJD, NNT) +BGC = (MLD, SGF) +MQB = (SVF, FBG) +DQC = (XSH, CGM) +QFS = (VKM, FPM) +QQM = (XQV, BKB) +CBK = (RPD, QNV) +VRK = (SVT, FKX) +PQF = (MQP, MJB) +VSF = (RKQ, FTJ) +DKC = (HND, KJX) +HQK = (HHV, KMR) +SVR = (MBG, JCQ) +JCV = (BVC, HDB) +RMX = (VHR, VHR) +QLC = (RLL, LKK) +NJL = (QRG, JJP) +NDP = (JRL, KMX) +DNG = (PPL, QCX) +MCF = (GBV, VBV) +NJJ = (VHR, NHT) +SBR = (VDR, JDS) +NJN = (BML, CGX) +TBT = (HRD, CCJ) +PVF = (CKD, RKL) +KPM = (GSK, BNL) +PFR = (DLC, NNK) +BMG = (BDQ, TLC) +DHN = (NDV, LRL) +LXH = (QQM, NGC) +CSS = (RNF, FGG) +PQC = (KJN, BQD) +BJQ = (RCX, JRR) +VMM = (MTC, PPX) +XKS = (XMS, BRN) +XQP = (RXM, BSR) +SFF = (QSR, QLH) +BXD = (LXT, JCH) +SKK = (KLB, BFN) +FKR = (XPM, BXD) +VBV = (LSR, FKC) +PNL = (PFN, JJC) +KMM = (GSP, HJL) +JRR = (SDD, QXM) +XHT = (GDT, SMD) +NCV = (XKS, LRT) +HXJ = (VNL, MLC) +CVR = (LMK, GJD) +BKB = (DKX, LGQ) +JCQ = (KRS, PCL) +LVD = (MST, RVS) +LBA = (XQJ, PFH) +GXQ = (LRJ, BGT) +PFN = (FQP, TSR) +PSK = (FMT, HVX) +GSP = (JSD, FNQ) +JLB = (NQX, KFL) +SNH = (CVG, PPN) +BPH = (HDG, FBH) +NRL = (JQK, DXL) +NLB = (VSF, KHP) +RNH = (TMP, XVH) +GSB = (QQK, FRH) +HLB = (MLC, VNL) +BCX = (HCX, TMH) +RMT = (SBD, JFT) +SNX = (RMX, NJJ) +HMF = (SHS, HNL) +HPV = (RJJ, KHM) +LCK = (BDD, FHB) +BLT = (KVL, KDH) +CKP = (DJT, HKL) +NGG = (KFG, SFF) +CPF = (XJX, MTZ) +PJP = (HVQ, DLP) +XSP = (XHD, SGB) +JQP = (JBR, TLM) +HVX = (SRR, QGL) +PNP = (HQK, PBM) +RTN = (FGF, XQP) +JQS = (NXG, NRS) +PVH = (DGQ, TRF) +XHD = (BQK, SVR) +CXG = (VNC, SRF) +MTC = (NFL, QVP) +QLD = (KVJ, LKJ) +RNF = (MBR, FCR) +JXT = (TXN, TLP) +LSH = (QFC, XSD) +XPR = (GCQ, GLH) +KSP = (NKL, DPG) +DGP = (PTH, RCS) +RDM = (LHN, QBH) +MST = (NMX, QSC) +GRR = (DNR, NLD) +BBK = (KNF, TBG) +PBM = (HHV, KMR) +SPN = (RKX, RMP) +KJV = (XGB, CJN) +QGJ = (LHN, QBH) +CLJ = (LRM, MQB) +LGJ = (CSS, CFF) +PBQ = (SDF, PVF) +VLM = (JKS, VXD) +TLP = (XRX, TVL) +LFG = (GMQ, JXT) +VKC = (VRV, JLL) +XQJ = (LVN, GMJ) +CHC = (NDF, VKQ) +VGS = (JHM, DKQ) +FCL = (SLH, HPV) +LMB = (FMT, HVX) +GJD = (XDM, CJS) +PCV = (XHB, KPM) +JNT = (PSK, LMB) +SXK = (QND, HKQ) +HCH = (XQT, KJK) +DGL = (JLV, PMR) +RCS = (GPK, SPN) +JHM = (SLS, QMV) +JFQ = (PPX, MTC) +KSQ = (TRP, BLR) +BVG = (BTV, XPX) +NDG = (RRT, SFX) +GKD = (PRV, VFC) +GJT = (BGQ, FCL) +GRM = (DKC, RPQ) +KBM = (JPT, DPM) +VMJ = (LXH, SXV) +GDB = (RBT, LLJ) +KTL = (LRD, NXV) +JMA = (CVR, HFX) +NTS = (BVG, SKD) +TBV = (GPG, KFR) +KFB = (HSN, SBH) +JLL = (FKR, DHS) +LDR = (TQH, KCG) +QBH = (BJT, FPR) +KLB = (DNL, FVH) +JQJ = (RBV, TLD) +GGP = (QFS, JHK) +GSR = (JSJ, XRL) +RTR = (HMN, FGJ) +SMD = (HDD, NML) +CJK = (TRF, DGQ) +LCM = (SBD, JFT) +FTJ = (KTV, LDR) +SNK = (JQJ, JLP) +TNS = (CCP, NTS) +FKX = (LSH, TSV) +JKM = (MVR, HSR) +RMP = (FCQ, SNH) +RBV = (RGG, HSX) +NGC = (XQV, BKB) +LFP = (KKJ, FHL) +SXL = (TRB, SBR) +NLQ = (PSK, LMB) +BPQ = (XHD, SGB) +QNV = (RDQ, SRQ) +HVB = (PCV, RTD) +GHJ = (KJV, KRF) +JFL = (VFT, FCD) +KMX = (JRN, GSV) +VXJ = (CDP, RRG) +DNL = (KDB, GXQ) +JSD = (BCD, HVJ) +TRB = (JDS, VDR) +KVR = (KBM, NFP) +NPD = (GSB, SRP) +XVB = (PFS, JSB) +GGR = (BSB, RQK) +CMS = (BTM, DHN) +GHQ = (HVB, DKP) +KCM = (CCP, NTS) +GBB = (SRK, VBB) diff --git a/2023/day08_haunted_wasteland/input.example1 b/2023/day08_haunted_wasteland/input.example1 new file mode 100644 index 0000000..9029a1b --- /dev/null +++ b/2023/day08_haunted_wasteland/input.example1 @@ -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) diff --git a/2023/day08_haunted_wasteland/input.example2 b/2023/day08_haunted_wasteland/input.example2 new file mode 100644 index 0000000..7d1b58d --- /dev/null +++ b/2023/day08_haunted_wasteland/input.example2 @@ -0,0 +1,5 @@ +LLR + +AAA = (BBB, BBB) +BBB = (AAA, ZZZ) +ZZZ = (ZZZ, ZZZ) diff --git a/2023/day08_haunted_wasteland/input.example3 b/2023/day08_haunted_wasteland/input.example3 new file mode 100644 index 0000000..5b3fa58 --- /dev/null +++ b/2023/day08_haunted_wasteland/input.example3 @@ -0,0 +1,10 @@ +LR + +11A = (11B, XXX) +11B = (XXX, 11Z) +11Z = (11B, XXX) +22A = (22B, XXX) +22B = (22C, 22C) +22C = (22Z, 22Z) +22Z = (22B, 22B) +XXX = (XXX, XXX) diff --git a/2023/day08_haunted_wasteland/src/main.rs b/2023/day08_haunted_wasteland/src/main.rs new file mode 100644 index 0000000..0d58707 --- /dev/null +++ b/2023/day08_haunted_wasteland/src/main.rs @@ -0,0 +1,166 @@ +use log::{debug, info}; +use nom::bytes::complete::tag; +use nom::character::complete::{alphanumeric1, newline}; +use nom::multi::separated_list1; +use nom::sequence::tuple; +use nom::IResult; +use num::integer::lcm; +use std::{ + collections::HashMap, + fs::File, + io::{self, BufRead, BufReader, Seek}, +}; + +#[derive(Debug)] +enum Instruction { + Left, + Right, +} + +type Network = HashMap; + +fn parse_input(input: &mut impl BufRead) -> (Vec, Network) { + fn node_parser(input: &str) -> IResult<&str, (&str, &str, &str)> { + tuple(( + alphanumeric1, + tag(" = ("), + alphanumeric1, + tag(", "), + alphanumeric1, + tag(")"), + ))(input) + .map(|(s, (node, _, node_l, _, node_r, _))| (s, (node, node_l, node_r))) + } + + let mut lines: String = Default::default(); + input.read_to_string(&mut lines).unwrap(); + + let (lines, instructions) = + tuple::<_, _, nom::error::Error<_>, _>((alphanumeric1, newline, newline))(lines.as_str()) + .map(|(s, (instructions, _, _))| { + ( + s, + instructions + .chars() + .map(|c| match c { + 'L' => Instruction::Left, + 'R' => Instruction::Right, + _ => unreachable!(), + }) + .collect::>(), + ) + }) + .unwrap(); + + let (_, node_mappings) = separated_list1(newline, node_parser)(lines).unwrap(); + + let mut network: Network = HashMap::new(); + node_mappings.iter().for_each(|(node, node_l, node_r)| { + network.insert(node.to_string(), (node_l.to_string(), node_r.to_string())); + }); + + (instructions, network) +} + +fn number_of_steps( + start_node: &str, + is_end_node: fn(&str) -> bool, + instructions: &[Instruction], + network: &Network, +) -> u64 { + let mut instruction_iterator = instructions.iter().cycle(); + let mut current_node = start_node; + let mut steps: u64 = 0; + + while !is_end_node(current_node) { + let next_nodes = network.get(current_node).unwrap(); + match instruction_iterator.next().unwrap() { + Instruction::Left => current_node = &next_nodes.0, + Instruction::Right => current_node = &next_nodes.1, + } + steps += 1; + } + + steps +} + +fn part1(input: &mut impl BufRead) -> String { + let (instructions, network) = parse_input(input); + + debug!("{:?}", instructions); + debug!("{:?}", network); + + number_of_steps("AAA", |node| node == "ZZZ", &instructions, &network).to_string() +} + +fn part2(input: &mut impl BufRead) -> String { + let (instructions, network) = parse_input(input); + + network + .keys() + .filter(|node| node.ends_with('A')) + .map(|node| number_of_steps(node, |node| node.ends_with('Z'), &instructions, &network)) + .fold(1, lcm) + .to_string() +} + +fn main() -> io::Result<()> { + env_logger::init(); + + let f = File::open("input")?; + let mut reader = BufReader::new(f); + + info!("Part 1 answer: {}", part1(&mut reader)); + + reader.rewind().unwrap(); + + info!("Part 2 answer: {}", part2(&mut reader)); + + Ok(()) +} + +#[cfg(test)] +mod tests { + use crate::*; + + fn init() { + let _ = env_logger::builder().is_test(true).try_init(); + } + + #[test] + fn check_answers() { + init(); + + let f = File::open("input").unwrap(); + let mut reader = BufReader::new(f); + + assert_eq!(part1(&mut reader), "20659"); + reader.rewind().unwrap(); + assert_eq!(part2(&mut reader), "15690466351717"); + } + + #[test] + fn part1_tests() { + init(); + + let f = File::open("input.example1").unwrap(); + let mut reader = BufReader::new(f); + + assert_eq!(part1(&mut reader), "2"); + + let f = File::open("input.example2").unwrap(); + let mut reader = BufReader::new(f); + + assert_eq!(part1(&mut reader), "6"); + } + + #[test] + fn part2_tests() { + init(); + + let f = File::open("input.example3").unwrap(); + let mut reader = BufReader::new(f); + + assert_eq!(part2(&mut reader), "6"); + } +} diff --git a/Cargo.lock b/Cargo.lock index d36ac71..a855610 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -162,6 +162,16 @@ dependencies = [ "rand", ] +[[package]] +name = "day08_haunted_wasteland" +version = "0.1.0" +dependencies = [ + "env_logger", + "log", + "nom", + "num", +] + [[package]] name = "day08_matchsticks" version = "0.1.0" @@ -500,6 +510,31 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-complex" version = "0.4.4" @@ -519,6 +554,29 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" diff --git a/Cargo.toml b/Cargo.toml index 83a03dc..6a32a56 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,3 +17,4 @@ serde_json = "1.0.108" generator = "0.7.5" ndarray = "0.15.6" regex = "1.10.2" +num = "0.4.1"