diff --git a/data/day03/example01.txt b/data/day03/example01.txt new file mode 100644 index 0000000..9919ffa --- /dev/null +++ b/data/day03/example01.txt @@ -0,0 +1,6 @@ +vJrwpWtwJgWrhcsFMMfFFhFp +jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL +PmmdzqPrVvPwwTWBwg +wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn +ttgJtRGJQctTZtZT +CrZsJsPPZsGzwwsLwLmpwMDw \ No newline at end of file diff --git a/data/day03/input.txt b/data/day03/input.txt new file mode 100644 index 0000000..456a3cc --- /dev/null +++ b/data/day03/input.txt @@ -0,0 +1,300 @@ +fBDGBcBrGDvjPtPtPV +QhzJLlLJZgLZzNTgZClQHvRvHFvrjrvnNjHnFjPF +ChldsCZhsQzsCGrrSfMfGpfrdM +MJbgcgJlvMSbfjMSbllmCrntwmFrrFwgtCtFFG +vPhddVZZhmnmdnHmHn +vNBZppZQhjSzfScjDN +jwhqbZRvbzvbqqpqzqHHCCCzsLmmQVtmJVJtLWLPrVLLVrmp +dGMfMGMdBBMSTfdMGTNlcZGGPSmQJVVWsJQPLmPLVPtmWPLW +llMBBcfBnBcZMGgqvCDbjbwgCHjvzH +RSDprRrwgVVRwrGqrJsNFJslgglmmNszzN +LLnWjcHWnCTmpClhHp +MpfMZWjtLMjpjtBPnLPndMBGRqwbwBwvrGwGrGVbVvwD +PQNGshQWtwWNcjssJHHJdlBLBlLrRDFFCrdwSlLB +mbzqZqsgMzfnbmbfgpZvZBLrLlSCrprDlLCrdFBlDL +MfvZzqMmsVnVzzTTbMzfvnctjhcHPQJJjNTGWjQJJHWP +MdLWQdMZrPQWsPdMQPLSqGpHGbGqpqqqVzpm +BhgFhVgnlgBNFtNwzpbTGbTTHpwwbF +tCfvvCfgvBjnfflftCvjWZVddMQZsMMsRdMZMP +lTLdHVlqmqWdvjvJttvFlJtC +ngbMTgGhQpgrGtvCzcCJccCrcj +npgwnDpSDbgbbnGGDQnMDSMgZZWVqNTNPRRdwLLNLqmPZTLP +RRSFZvRdrdbSvSVLRZrSGZZrHcHPfPPwJJVJmPHmJfHVThPm +WnLjBQBCQWqCQwpPmHTcfQpm +gBDttlnqLqlvzzlGRRlr +wGpdGdddMPDWgFJGBzmMlntTbZMtZbnT +qNSqQrrqSjQVrsvTtzNnnZTnfNztZw +rcVrjjsswVvRRHsFJLCDCpCddGCCcG +jLMhCPWLCSWSrRLPWmPPLSCLtcTvHHDhZcfHHltlfZtlfgfH +rBBNrbVdtZlvVcZc +FppGdpFsnsqGJnsFzGdJszbdwSLRSRPrSRjqrMqCwQMWQqRS +jTjZwnpjMDfZnmZfsRhGGztqCzwsdGws +JHrWcNrNNrJHLHlzsCtzGRRRHv +rNLrVBJFLmfCnbTpVQ +LGWJvDFssFmMBhThMvnB +CprbCNZpwfpwfrbZJMQMTQcVVgBZcVQBZc +ptNwfwzHzqzlttbrlpCCqzwtFLGSWFsPDLWFHSDjJWSDLFDs +MZJjSsCsMsZSSdZJhdjZtCbPHljqlLPlPRRDLqHHqLbB +mmwmVpGrnngmggGwnccPbDBPLLLllLBcFRFb +GQzVTQTTVzVrQrmvpTnmrQmMvZRhZZCZSZfCsfttSJddNC +gHZZQRdVgRQWWRPHWPnttDTmqQqDQnStzNqD +bscfjslJJspBLsslNStSmTmLmmDTzNnS +JJCrbbhBsplrrChpBbfjlpbbFWWVggPPhZVRRFPdVMddPnMg +FtLfHNhFJCClJlst +jnDQqnDSDSRqwBwnjdFlZbsrTZdsJsGCbw +zDFSmjSDVqnRMHmphPhfWPgW +rSpRtSPWpStVqrwSSdrrhZvnBBnDBvsqjlBqvvnnzl +LFNLLFfFFhMFbcbmbHbHgTNcvZvBZMsvBnJBzsZvjJvZlvnZ +gmFLhTTbFmmQrrSWWpwWVtwQ +DzmDJGSccGJPcdcJPJqwplhjBHmHVwwtBthV +grMMvRsNRnWCFrgZRrZFhpVVlHVnhpVjVtljhhhf +FFZFZTsvCMSQTdGcTHzT +TLsGTnZncjVmVLgm +DvRwMcHMvMbwBVlCBlzlMjCC +FdRtRHDwQvPnTfPqcFPP +rZNdpBSldLLCJZbbCT +WQcQwqsmQmmqJgTRLRCqLq +znQcwsmPcmnCzQmfGGnzHSDFlNptNthPSdllhFPplS +vWCWvVhhjPNjNNvWVNbnbHnrbGrmlPqnqqbw +JdZSLMgsdgQMcQssQnnDqmDqlDqnDlwrHc +tdgQSSdpQtSMSNWpWRfRCwjpjV +qhdJFpChSJhDFDrqbpJbddSHPPRnGGBfBrHfZRnjRnlBZH +zsMVzmwmtLMtmQTzvwlRcZnZZljvvfGcBjcZ +ttQzMtVgMWVMQsmtJgqJgCJbqhgbBSBN +BWvdCmZBrNRrGSSfTzQJJRTz +gMblllMgLVswbgwMsLjgLLnlVtfHfttSQttTJTSQGfGPTPTB +LMgnMgscgqbFBqvBNFBmNm +VlcczDZjjVbznwLnwpTH +NfJPJNfJdJMSHSHnjBRSnbbL +NddqPttjsdZDqhcqlFcD +NVrNBBFFFrvJJrVTFTNvWBCbCCgWGqDqhqghCLqbqtCC +mfZVPZPcqtLbcqgc +fwZlwzfRfQQPMZBBwwBjFSjTVrBT +GWWNMfWWwGWMtjJnVnJzlzVsvLnsVn +ZpRqHTBddsvtPLqVPP +bpSDgStgTbdFTpDdRmfwfmfGFcMQGWMcjQ +gCgGBgfCbRLbBLGnGBBfRGwprctZFMvtFtvSNNTZZtMvLc +DhJhDzzQlDdshVJlDdhqzqzQZFpppFMNtMZMtFFVvtpSMpFV +qQdsDHWWslnNgHmBbHBf +MRvnJFZVnvzJrWWSqMSPTSNqNj +GlcbDpCHCCczdsDppcccBGccqjwTTwQPPSjNjWSWSwwsPsws +GbdlBbgdVtngtzVg +GqTSRpgJgDNSNJqJlSTJlJCBmmcnjCjLFcMFmnGsmBsM +HPhfPrWdfrQPPPhQWHbLFFWFCmFjMBFFsLBFwj +fdzVbvfshrbzvfbfdVPvQtqqJgqgDpNTgqZZtglZtZDD +wsPhrDMfrwdvHdTFrrtH +lnQbNBbqVBqHGJSddvTlJJJJ +cjnHznzbQmgzqQjBWwZwRjDRfWWhWsWD +SsScnttbbSzRRMMMLpsBLP +dDJGgjGJVMSBBBMj +JGDNCfgfSChDJrgqdgqJqGbNbbcbNtzWFctbzzlWtFFn +dtsBsCMtwSVBlLZZZnMgcMZZ +brppQHGznLZgJzJJ +fprvRpNHpNnvbGDBCBPwBWFWBFBvtB +qjgjSgHNlSGHnjfSVDvDPRDDtcdDcGtD +FMTnnLQZtRZDbcZv +zhBLzrCwnCsTCMCQTFLwwCzpHgNlNmHqhlqSpWllmlllhh +bJqqFdfbGdfPNsJsdSRCFLRHLDDBHDnShL +lQWlWQpwQjlpwrjrwTSCTLMCCNTHRDDDDRRB +wtWgQmQQWtwWwrljNPfGPzJmbbfzmzZf +MjppbDGmNNblCpzsNZzhNPgHtzzs +qvdrqrQVVWLfqWfRRPRwZPPwggpf +cqdcdpqSrrSvrvWvvvrSbcGTTTbGlFFCCcnnGbTb +HLNfNGttHVFBHWSr +RZCLsbCbLbLhwzDgbZCbRZhhnpSnnWpWplFFnDnqlBFVpSVB +MzbhhzwcLGGfGMvMTv +PdBlpdVJlmftGbTzwbtRTGGL +NQNMgWNNQNScDhsSHSWhsNgbRCLwGnnwqLwLHbbCGGTjTR +MvhRMMRvQshgSNDWFrfBfJFZrFPJJJPBBp +qdtnQqWtnjfGGzsnGQmWWfqQNbRTgggRFNbCFNSSFlSJsrTr +PZBBbPMvVcMpSRSlSCpCSgCT +MvHZhwMVLDHDcZMvLQfwGWqwWjqjGbmnQq +NFPmjNhGthGNpddddFpzBbqPczSqPDzzDgbgLZ +VJWvwQrlLHWrvlQZDgZSSDSDBqbb +WfHwMWfvRvMWrWJsrfMRWGFmGGLttMNpjCpTdmFFht +DppfNpLwhTBRDbblgWNgCdgCvs +nLcLqFJrHJmLcFmqMFCdzdHdsgvdzvbvWPWs +nVFqrrQcSVmFjrmJnrFrSjTtRGRLBwfRTfZwhBQhRGGw +sHrZdHGpHhsrLpsssGLzhrdtWdJTMWJvffVdmnbfJVnW +cggRDCCjlPQCgDRnfbTtfMJfWVTm +cCDwQNlwQPjgCFDljwpSLFzGFzZhzsstSpGz +dGTGpGdPZZCpnnLRpgzgzn +lflshFjFcrNdBjMjMnmL +hDfrldDfbVPbQCtHHZ +cSRZmtFZScfjZtLbmCNMqhMVQCjwqqCwVB +pddczHpHHzgWdGdsvPrPzcvrJMNwJCQwJhNwBhCJBVMpCVJB +cgrWcHdnPHHznlmftmtLnRDD +PZFMMVJVZmVJVHMNJNVfNdNNSnSWsSRhgRRQnWSsRnSWmszc +llljlTwlprClTbTpwLlgQqhcnwnczhcgSqsQRR +TpCtGtrTBDZVZHNQZQdB +SggjglBBlzbDgdpFJddZpF +CCNLsfNfrcMLsTLPfPmndmTwmZtZJZJdJplp +sfWCqcvMrlMfMLsLNfhVGvjjjSzSzVQhQvVH +NTBhNhfBvfflsbSmcl +nrMZRnHHwBMZRsSsgSsGrbmdms +nPPFVwVWJqJBVJLT +vvWqWJWJvzfFZZJvWQzqZvdPPHjSfHjssHsbsfbjSHRR +DCwtDVjMCrltCnCrDCDmbTssPHLTLldssdSldSRp +nMcGtDmBmMGrGvvvvFhjFZgWcN +tGWWWfWpMDjMZbTbnqTC +JFscJzFPDJDJZnrJ +sBFPcBsSPBvmSPwFzSSQfpwWfDpgNNfWtfgpftfg +BvTsJJzQJLMlbhmbFlNmTl +PjGnpdpGcgDmhvnvmvlbmq +dRtDGGgcDtjRcwdgQLVLRMJsszJVLRQv +FGbPPfFSchBGSvGGWsjSTLVQLLVTsQlj +dDzPnCrRCrrWHHTTHsdVjs +wrwCgzMrNprCwRJJwnnbFmmpGZtcvcbFfPFmFG +fbrJjmmmZgmZLJZsBBWlCBGnCWdnfF +RVMDDNDHPNvvRvDtHMcctMqFslqWPnClddlClFlnBqCG +MDDvHzHVQMMDtTHJLrnggSZLTJZgTL +dgBBCBBdvbmrRczFMHMSrqjjSPzn +tZTwQlLVwnQLQQFJVPzjDSSzJFPD +fhWhQpTTZQlWfQWpWQWQLhBgchhRCsdbvNnbgRsmRR +LttflLnGrnMsmmHgWTbdMW +vBSWzZRDccWBFBmJsmPJmgbsgB +FppcFWRNRZLLppGrGrqr +JJClRmLlFGvMTlFLLfPFQQcDpQcjFcjqBc +zgHSZhggggtwSZhrDgsZgbjVQcVcjPNqcpQQqBjNQzNp +hZnsShSWGDMMMRnv +RbDbslClhsfNCbsMjbNrjNMfpTTTTJSzHTpLVzLLVWVzJz +ggFGgmqFZBnnSzTWPpHBLzdT +vmWZWGwcZZqthjDrbclNCjlD +dCHwnVBBCBnVHddqnQRdbbbrgTsfWwjcWlsfwDDg +hhlFpMtGJlZmDjfWfscjWDGD +hFNFvZmppmSlNJMmNFztmzFhdVPPHQQqqHPvLBQnBQQPQPnC +WfzsplQpvQgfwzlbllPGtPJTTwtGGZBTTGJB +VrmMjmFDjNjjDFBhHTcZtBRRGcGV +mqrFmmLrjmjZnmqLrmQsfvbsfsSSlpWqgglp +lsQVfDpfflpGGmQRRgdQbdfbWdqnjnHnqZHJTqqrWjqqcWnZ +PPFhFFtwzqjHgjWTWF +SwMwMhNMlMsgfQfl +cSttSDQQCgVvQQSvsstthQcslLLgLgLnpglffjfFlLFblnlH +rTTwTbdBpTHJfZZJ +BddPBzwMBzqRqddRGbVShvVhVQvQscvGtV +sSpsHqHMspqMqWsspwsSWsbBPvjrFbddrGTvZLFjdZTZGLLG +NccDncRVNDVJLvLPPJTJGvJL +mRCDNNhgDnghNRQNggNRcNlMtpMPMMtHtShlSSMtlhHW +QrjSFQWzDdCHtpFlbBbVns +PhJwNLfNqgfdLlZHpZJJpptBBb +qmwhfhhfMNWSmSdQCddv +VfRMdbshRmJBqbmDBH +CWwWCWTCrzFpzWwCWFzgppqHDtZBfqDmQtBftBDFqBtq +WlzrWWGWPrpGCGdfSsRGVnGVdNnR +lhLTfppGRhhbZntsbTqMbq +jrHWBHrMgjHPWMgWBJWBWjstPvwFFbbbvtvFqbPtvqws +rBJJJVWjBjLphcMhSVRV +fjrBPBjWVPWPrwtjPpRQZZVdZQddFdHFTZdT +GqlllsGLgMCqGqgTFbmHdTmRzgTm +qHchGscqGClHGhNwhjJJNWpwPB +JzrrJZqLFrnMzVjNNnNnNDwdGHGlHlHbpTZDlmpTHb +gQfQcRWPWgQSStCtfcsPsPmhsGdDhdGDHTwHpDlHwhTG +fvWQgCtfWgtttcPQcPBtjVdBMJMLJBFJMJVzNrJr +cMzNjGGNQFVzNNQVjNdqRLbFDqRpgLRDpDHD +TwtwWJJBJSvmJCWSvTTmTbBpfpRZSfDqqSqDgHLgqdDDqD +vtvmPrtWQMrbhMrG +NqCPqJNJQQQQGCtGPmMTrTpHlNdmpTrwdN +bzhZRDbnZHrmmcwRfM +vWhsnVWWswhSFvDSDsnhbDsLPqqPFjQjgFgtjqqCLJPgQQ +nqpfqfcnclcNcjjQ +BLQJQmLPPvdtTFNjlFNwPs +DgDgLLCQBBmpVSMrgfqnpp +njCnCwwcVCBWjrrhWrHdzJqmhl +QNGptTTQGLTdhqmdJBHT +GtLvDDvLMvppGGVZMssfCBMfcfMf +npPQGpDnsbJhvldphHFfpl +mgqZcqzczzzcqmRzrbrzBvfBLvlhhftFWlhlFtLBvv +cgjmTgbbMgmzqRRwGDDVQVGVSPwTJV +VhPNvgVhbjPsNvsChTZlHtlwZccZMhwlcm +fpznDWDzDfRqffpnrmcRmwlTMZrHTBHB +fWdQLFSnDzpndqzzqgsVvPsJLMsPCgvjPP +RFRDQVvqVMZGBVzqgqPNJNmNhqqPjnPS +rcLLCWrtwlWrWlTbTtlLWrWtjPPgdwgjmNmShpJnjSpSjgSg +LbLTnbbTHsWlfbtZRZGQHHZZDQMVFz +dwcLLSLVdwLdvdfZNJgQZWfffVJQ +CTMlCRCCCTCtBmCFMQJNNNbNfWvQjvZggT +mRnnnpFlvhnlMmBmFMCMCcdHrwzqszprdcwzLDwrSz +JSHLHRMlzJHcGMpwCffZctZmgfqqZm +vnTWvQrnrQjNnBWvnvDnVgqtVWwVgfFmqWfqZFWZ +rdQDBdBrQQhmBNjDTmrTnzPzPPLHSSHzHHRHRLdGLl +GvMRRwGwRFmZRnmbMhZMGcpgZBpdgBJcTsjsBstdds +SNlPzzlPDDQSDDDqfllqDLBpTgWBgWdTpcWjJQsWjjTp +rScrCqPCSLDNrqlFmRVRRrbhmRmFRw +dbtgMNlNSMQPSLNdvVQgSfcHHfJfHJtfmmHTqZffJH +wssswnzwChsrGCCwGCjzCsHFHbzZffbFBcffbHHTBJTZ +rsDRGDwjhWbrbRhGCGLdLNlNQVVDPSlMVMvv +BgPccPPRlZZmTMTZzZTC +jjNjntVtQnWHrJjFPnnqDqJTJTzqJmDDCqChzS +FnQHQjHVNnWVvQpgLPGRdcLpbfLLBl +JLMhFJfHHLJChRvfjLJJnFRpPrpPSrNnrTrTTPntTptrpw +QgcBCqcGBBGzGrNQNSwSrPPTsr +zzWdmzcWcdHCJCRRCF +GSRcjdjGcBnFWbnVLFQR +pCNqTqhDsMsMmNtNCZmMMtdCbVFzbFwnFFnWWFnzVLTQWQLF +qNJpMdCsDNsNNvGPlSPPJjfBBB +lsHjgmFsnFTwHgSPDRSrDqnqrrnr +NmZWcZmzNMZWJbbWvJMJJMzBBBrRrdRfDfppBNqSrrrPBP +JZQZzQtWJhmltVwVCjwGjs +DslBHDpdDlslgffFWnGqHfzH +JNMMCCCCSMvzzGfMzP +hNtCJTwRwZQbwrplpDjlpz +vwvJwLBzwhhwvzwrgwshLwVWWgFfmlSFVRDfWFSVFVfF +mNqbdPnNdpdjnMqSFFMDfSFVMDFRSV +ddpTPTqmbNjjNqndZzvLzJZzHCrrCCzsJH +SLjjlGMVpLpNSTDspsrHpFFwRrZgRfwpfgFZ +nQtWPzbPNQtbdzPtbBCQJNPcwFvZJZFFJrwRwrHcfcfrgF +NQCnqPBWddbPnbCdWdWQnmdVhsMMDsslmSSmMLlVTTDVMm +FZmcqBChfFmfsDjjnNMNjSDgNs +RZwzdvdZRvTRRlvWSgDjStnpntDwNMtD +vHTGRvvvZHlQPRQTbPTVfLJPqcLJBhfmFVJPCF +dStFcccjFjqGFrFHmSHFBjBvzhpprWZpppbppDvzhsvDhT +VMVLNfCCCRTTDtDDDTRz +QLJwMMLnLNVLdtGGgmdScBnB +nTCWnTnrllglrNgNTZFgSZbddHtdHLLwtMLQtfbM +BJGqppPCJVmqqhBJCdwwpLSLHddfHSLHtw +qmzBhczVGsqVBqnFcCjRWNrNlrgD +phrHLNtnMpslNFfwVGwFZSBfFTTz +cmJJDmmbCnCCfBSJGVBwfBfz +DdqdDbcqCPcCQRWmQPqNHhnRMntNNMNhlsLsML +gHHWJWMWsHWgWSnPwVnVNGGDbnwwTl +QjThjhFqqhmQTCVPfDVqPbDVVl +mpFLLrZjjBcmLFmmFtLBJMddMgSdHTscvcJzRHRs +gRdwcCddwghzddzzzsGfZsGnqlqVVhjGDj +DMBNpMDHrNrNLFMmpQJHZGnPjFPFlZjlfGVljGVf +SpbQNmHMzgcRwSSD +drqcMpNbpFpmjzfz +HLGZGsnGLwllzHGGgGnGsBFfmJtmtjfJDSBSJJJB +ZZwQwHTgZnwLGTTnQTHVlgbWCQNhzNcMqbrzcNNQdNcr +TDScznfzNlpbbrtsvjdcbh +BBHqFGWGFmVWqVBBWMtvCLvsLdvrvjLjdLbsvm +tPZHGFJPJqVwMWHJVRRSZNfQnzfpnTpNfl +FWNZgWCngsNwJwlQlrRTRhSjSS +GGLcVVcVmppMmpTjTRHlbRbSrVBh +rvmdzPcdzmzMrCNNPJFntFsCtD +MtfLBzSLmMtfBMQzMmzmSlfdTDvGCZGCndZnZgWDwGCZ +HhqrrpppcqhdbjPvbgGvTCnWDbTWZT +cNjsdqPqchJBlmzlVQLtBJ +DwwVFZlDBsZFDvLPdpjLjSVHjpLc +nMnztWhhfPSffcddGpgp +tQnrQzhzNtzbNrBwPJwTslTvNFFP +LWMvHJJrJwtzvgwMwVdGfcpNfdDVDWfdBB +jZPFmjnbmhPfTVfVHdhTTV +qqQCmCmbqCQqjQsQvrQSHSJrzz +wNzmDRwmgcGphZcPvLLZHjjFLF +JlbsClVVqDqFZjJD +WSlnCbttftsCsWftbCCrTffbpdzMwgMgSpRmdwdRzggmDGGg +gCCRBClgfCgFFTltTGgBqTsQhzLzQQNPnvrNzHrrfPzHLr +DMjqWSVwDwDwZDHZNvLQnrnrPrNv +bcmWJqdVcbtgBglbGTCl +SFDcrFHtlqhqqLdzTTwdJLPNDL +vBWsWvsmgvvvdPwNnn +smfRbpsWMBmsmMsBBBNbtSFttjCHSScbhHtHhHjb +SQpgGgMNvggQGMvQcgnHWmldnHWTWndnSHHF +DwbDPzthtttljTzTFBlmzl +DstCswftDbZbCChPPRrfwsfPQlLccJQLvVGNGNVpMNvZcvgG +HdqfjjLfHqFSHddVWNBjsWhWRRJtBNBs +gPMQHpmrcmnbRQNRRJsWttWW +pmbcZwbrPPrnTPMFFdDwqHwvHDvzDq +FFsVtFGVGvWVhlfVhzlsFvHbPwPmwHLTSbLjcLtbSbLm +rZrpJwCqnnJHmqcbcTLTbS +RCZZQMQpzvRhswVg \ No newline at end of file diff --git a/src/days/day01/mod.rs b/src/days/day01/mod.rs index a800391..e23294b 100644 --- a/src/days/day01/mod.rs +++ b/src/days/day01/mod.rs @@ -1,7 +1,6 @@ use itertools::Itertools; use std::num::ParseIntError; -use anyhow::Result; use thiserror::Error; use super::template::{DayTrait, ResultType}; @@ -14,13 +13,13 @@ impl DayTrait for Day { DAY_NUMBER } - fn part1(&self, lines: &str) -> Result { + fn part1(&self, lines: &str) -> anyhow::Result { let vector = Day::parse(lines)?; let max = vector.iter().max().ok_or(CalorieError::Empty)?; Ok(ResultType::IntResult(*max)) } - fn part2(&self, lines: &str) -> Result { + fn part2(&self, lines: &str) -> anyhow::Result { let vector = Day::parse(lines)?; let sum = vector.iter().sorted_by(|a, b| Ord::cmp(b, a)).take(3).sum(); Ok(ResultType::IntResult(sum)) diff --git a/src/days/day02/mod.rs b/src/days/day02/mod.rs index 909da92..4546648 100644 --- a/src/days/day02/mod.rs +++ b/src/days/day02/mod.rs @@ -1,7 +1,6 @@ use std::cmp::Ordering; use super::template::{DayTrait, ResultType}; -use anyhow::Result; use thiserror::Error; const DAY_NUMBER: usize = 2; @@ -13,11 +12,11 @@ impl DayTrait for Day { DAY_NUMBER } - fn part1(&self, lines: &str) -> Result { + fn part1(&self, lines: &str) -> anyhow::Result { let sum = lines .split("\n") .map(RPS::parse_line) - .collect::>>()? + .collect::, _>>()? .into_iter() .map(|(first, second)| second.asses_pair(&first)) .sum(); @@ -25,11 +24,11 @@ impl DayTrait for Day { Ok(ResultType::IntResult(sum)) } - fn part2(&self, lines: &str) -> Result { + fn part2(&self, lines: &str) -> anyhow::Result { let sum = lines .split("\n") .map(Strategy::parse_line) - .collect::>>()? + .collect::, _>>()? .into_iter() .map(|(first, second)| second.fullfill(&first).asses_pair(&first)) .sum(); @@ -55,7 +54,7 @@ enum RPS { } impl RPS { - pub fn parse_line(line: &str) -> Result<(Self, Self)> { + pub fn parse_line(line: &str) -> Result<(Self, Self), RPSError> { let mut parts = line.split(" "); let (Some(first), Some(second)) = (parts.next(), parts.next()) else { Err(RPSError::IllegalLine(line.to_owned()))? @@ -119,7 +118,7 @@ enum Strategy { } impl Strategy { - pub fn parse_line(line: &str) -> Result<(RPS, Self)> { + pub fn parse_line(line: &str) -> Result<(RPS, Self), RPSError> { let mut parts = line.split(" "); let (Some(first), Some(second)) = (parts.next(), parts.next()) else { Err(RPSError::IllegalLine(line.to_owned()))? diff --git a/src/days/day03/mod.rs b/src/days/day03/mod.rs new file mode 100644 index 0000000..66d9d41 --- /dev/null +++ b/src/days/day03/mod.rs @@ -0,0 +1,144 @@ +use itertools::Itertools; +use thiserror::Error; + +use super::template::{DayTrait, ResultType}; + +const DAY_NUMBER: usize = 3; + +pub struct Day; + +impl DayTrait for Day { + fn get_day_number(&self) -> usize { + DAY_NUMBER + } + + fn part1(&self, lines: &str) -> anyhow::Result { + let sum = lines + .split('\n') + .map(|rucksack| find_double(rucksack).and_then(priority)) + .collect::, _>>()? + .iter() + .sum(); + Ok(ResultType::IntResult(sum)) + } + + fn part2(&self, lines: &str) -> anyhow::Result { + let sum = lines + .split('\n') + .chunks(3) + .into_iter() + .map(|chunk| find_badge(&chunk.collect::>()).and_then(priority)) + .collect::, _>>()? + .iter() + .sum(); + Ok(ResultType::IntResult(sum)) + } +} + +#[derive(Debug, Error)] +enum RucksackError { + #[error("No double item found")] + NoDoubleFound, + + #[error("Not a valid char: {0}")] + InvalidChar(char), + + #[error("Need at least two elves for common item")] + NeedAtLeastTwo, + + #[error("No common badge was found")] + NoBadgeFound, +} + +fn priority(c: char) -> Result { + match c { + 'a'..='z' => Ok(c as i64 - 'a' as i64 + 1), + 'A'..='Z' => Ok(c as i64 - 'A' as i64 + 27), + _ => Err(RucksackError::InvalidChar(c)), + } +} + +fn find_double(content: &str) -> Result { + let length = content.len() / 2; + let part1 = &content[..length]; + let part2 = &content[length..]; + + for c in part1.chars() { + if part2.contains(c) { + return Ok(c); + } + } + + Err(RucksackError::NoDoubleFound)? +} + +fn find_badge<'a>(elves: &[&str]) -> Result { + if elves.len() < 2 { + return Err(RucksackError::NeedAtLeastTwo); + }; + for c in elves[0].chars() { + let mut found = true; + for other in &elves[1..] { + if !other.contains(c) { + found = false; + } + } + if found { + return Ok(c); + } + } + Err(RucksackError::NoBadgeFound) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::common::file::read_data; + use anyhow::Result; + + #[test] + fn test_rucksack() -> Result<(), RucksackError> { + let input = "vJrwpWtwJgWrhcsFMMfFFhFp"; + let expected = 16; + let result = find_double(input).and_then(priority)?; + assert_eq!(result, expected); + + Ok(()) + } + + #[test] + fn test_part1() -> Result<()> { + let day = Day {}; + let lines = read_data(day.get_day_number(), "example01.txt")?; + let expected = ResultType::IntResult(157); + let result = day.part1(&lines)?; + assert_eq!(result, expected); + + Ok(()) + } + + #[test] + fn test_find_badge() -> Result<(), RucksackError> { + let input = vec![ + "vJrwpWtwJgWrhcsFMMfFFhFp", + "jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL", + "PmmdzqPrVvPwwTWBwg", + ]; + let expected = 18; + let result = find_badge(&input).and_then(priority)?; + assert_eq!(result, expected); + + Ok(()) + } + + #[test] + fn test_part2() -> Result<()> { + let day = Day {}; + let lines = read_data(day.get_day_number(), "example01.txt")?; + let expected = ResultType::IntResult(70); + let result = day.part2(&lines)?; + assert_eq!(result, expected); + + Ok(()) + } +} diff --git a/src/days/day__/mod.rs b/src/days/day__/mod.rs index 0c2270b..000bcc4 100644 --- a/src/days/day__/mod.rs +++ b/src/days/day__/mod.rs @@ -1,5 +1,3 @@ -use anyhow::Result; - use super::template::{DayTrait, ResultType}; const DAY_NUMBER: usize = 0; @@ -11,11 +9,11 @@ impl DayTrait for Day { DAY_NUMBER } - fn part1(&self, _lines: &str) -> Result { + fn part1(&self, _lines: &str) -> anyhow::Result { Ok(ResultType::NoResult) } - fn part2(&self, _lines: &str) -> Result { + fn part2(&self, _lines: &str) -> anyhow::Result { Ok(ResultType::NoResult) } } diff --git a/src/days/mod.rs b/src/days/mod.rs index 9f4042e..b6e99dd 100644 --- a/src/days/mod.rs +++ b/src/days/mod.rs @@ -1,5 +1,6 @@ mod day01; mod day02; +mod day03; mod template; pub use template::DayTrait; @@ -9,12 +10,13 @@ pub mod day_provider { use super::*; use thiserror::Error; - const MAX_DAY: usize = 2; + const MAX_DAY: usize = 3; pub fn get_day(day_num: usize) -> Result, ProviderError> { match day_num { 1 => Ok(Box::new(day01::Day)), 2 => Ok(Box::new(day02::Day)), + 3 => Ok(Box::new(day03::Day)), _ => Err(ProviderError::InvalidNumber(day_num)), } } diff --git a/src/main.rs b/src/main.rs index fc7054f..26e9200 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,39 +5,84 @@ mod macros; use anyhow::Result; use common::file::read_data; use days::{day_provider, DayTrait, ResultType}; -use std::env; +use std::{ + env, + time::{Duration, Instant}, +}; use thiserror::Error; -fn output(day: usize, part: usize, result: ResultType) -> () { +fn output(day: usize, part: usize, result: ResultType, time: Duration) -> () { match result { ResultType::IntResult(value) => { - println!("Day {:02} part {}: {}", day, part, value); + println!( + "Day {:02} part {}: {} ({})", + day, + part, + value, + time.as_secs_f64() + ); } ResultType::StringResult(value) => { - println!("Day {:02} part {}: {}", day, part, value); + println!( + "Day {:02} part {}: {} ({})", + day, + part, + value, + time.as_secs_f32() + ); } ResultType::LinesResult(value) => { - println!("Day {:02} part {}: {}", day, part, value[0]); + println!( + "Day {:02} part {}: {} ({})", + day, + part, + value[0], + time.as_secs_f32() + ); for line in &value[1..] { println!(" part : {}", line); } } - ResultType::NoResult => { - println!("Day {:02} part {}: (None)", day, part); - } + ResultType::NoResult => {} } } -fn run(day: Box, part1: bool, part2: bool) -> Result<()> { - let lines = read_data(day.get_day_number(), "input.txt")?; - if part1 { - output(day.get_day_number(), 1, day.part1(&lines)?); - } - if part2 { - output(day.get_day_number(), 2, day.part2(&lines)?); - } +fn run_part(day: &Box, is_part1: bool, lines: &str) -> Result { + let now = Instant::now(); + let result = if is_part1 { + day.part1(lines)? + } else { + day.part2(lines)? + }; - Ok(()) + if matches!(result, ResultType::NoResult) { + Ok(Duration::ZERO) + } else { + let elapsed = now.elapsed(); + output( + day.get_day_number(), + if is_part1 { 1 } else { 2 }, + result, + elapsed, + ); + Ok(elapsed) + } +} + +fn run(day: &Box, part1: bool, part2: bool) -> Result { + let lines = read_data(day.get_day_number(), "input.txt")?; + let elapsed1 = if part1 { + run_part(day, true, &lines)? + } else { + Duration::ZERO + }; + let elapsed2 = if part2 { + run_part(day, false, &lines)? + } else { + Duration::ZERO + }; + + Ok(elapsed1 + elapsed2) } #[derive(Debug, Error)] @@ -52,9 +97,12 @@ enum ParamError { fn run_on_parameters(params: &[String]) -> Result<()> { match params.len() { 0 => { + let mut runtime = Duration::ZERO; for day in day_provider::get_all_days() { - run(day, true, true)?; + runtime += run(&day, true, true)?; } + println!(); + println!("Runtime: {}", runtime.as_secs_f32()); } 1 => { let mut parts = params[0].split("/"); @@ -64,12 +112,13 @@ fn run_on_parameters(params: &[String]) -> Result<()> { if let Some(part_str) = parts.next() { match part_str.parse::()? { - 1 => run(day, true, false)?, - 2 => run(day, false, true)?, + 1 => run(&day, true, false)?, + 2 => run(&day, false, true)?, p => Err(ParamError::UnknownPart(p))?, - } + }; } else { - run(day, true, true)?; + let runtime = run(&day, true, true)?; + println!("Runtime: {}", runtime.as_secs_f32()); } } }