diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..9569962 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,159 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'utils'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=utils" + ], + "filter": { + "name": "utils", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'solver_base'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=solver_base" + ], + "filter": { + "name": "solver_base", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'day_1'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=day_1" + ], + "filter": { + "name": "day_1", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'day_2'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=day_2" + ], + "filter": { + "name": "day_2", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'day_3'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=day_3" + ], + "filter": { + "name": "day_3", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in library 'day_4'", + "cargo": { + "args": [ + "test", + "--no-run", + "--lib", + "--package=day_4" + ], + "filter": { + "name": "day_4", + "kind": "lib" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'advent_of_code_2024'", + "cargo": { + "args": [ + "build", + "--bin=advent_of_code_2024", + "--package=advent_of_code_2024" + ], + "filter": { + "name": "advent_of_code_2024", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'advent_of_code_2024'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=advent_of_code_2024", + "--package=advent_of_code_2024" + ], + "filter": { + "name": "advent_of_code_2024", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 4fe9fdc..f127223 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,8 @@ version = "0.1.0" dependencies = [ "day_1", "day_2", + "day_3", + "day_4", "solver_base", "utils", ] @@ -36,6 +38,14 @@ dependencies = [ "utils", ] +[[package]] +name = "day_4" +version = "0.1.0" +dependencies = [ + "solver_base", + "utils", +] + [[package]] name = "solver_base" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9a5f85c..11a4eb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,8 @@ members = [ "crates/solver_base", "crates/day_1", "crates/day_2", - "crates/day_3" + "crates/day_3", + "crates/day_4" ] [dependencies] @@ -18,6 +19,8 @@ utils = { workspace = true } solver_base = { workspace = true } day_1 = { workspace = true } day_2 = { workspace = true } +day_3 = { workspace = true } +day_4 = { workspace = true } [workspace.dependencies] @@ -25,4 +28,5 @@ utils = { path = "crates/utils" } solver_base = { path = "crates/solver_base" } day_1 = { path = "crates/day_1" } day_2 = { path = "crates/day_2" } -day_3 = { path = "crates/day_3" } \ No newline at end of file +day_3 = { path = "crates/day_3" } +day_4 = { path = "crates/day_4" } \ No newline at end of file diff --git a/crates/day_1/src/day_1.rs b/crates/day_1/src/day_1.rs index d37b8b1..3d60944 100644 --- a/crates/day_1/src/day_1.rs +++ b/crates/day_1/src/day_1.rs @@ -114,6 +114,7 @@ impl Solver for Day1 match self.data_set { DataSet::Test => format!("{}/data/day1_test_input", dir), + DataSet::TestAlt => panic!("Day 1: There is no TestAlt input file!"), //format!("{}/data/day2_test_input", dir), DataSet::Full => format!("{}/data/day1_input", dir), }; diff --git a/crates/day_2/src/day_2.rs b/crates/day_2/src/day_2.rs index 40ae22f..e5cdc4e 100644 --- a/crates/day_2/src/day_2.rs +++ b/crates/day_2/src/day_2.rs @@ -53,6 +53,7 @@ impl Solver for Day2 match self.data_set { DataSet::Test => format!("{}/data/day2_test_input", dir), + DataSet::TestAlt => panic!("Day 2: There is no TestAlt input file!"), //format!("{}/data/day2_test_input", dir), DataSet::Full => format!("{}/data/day2_input", dir), }; diff --git a/crates/day_3/data/day3_input b/crates/day_3/data/day3_input new file mode 100644 index 0000000..2c7dd0f --- /dev/null +++ b/crates/day_3/data/day3_input @@ -0,0 +1,6 @@ +%why();how()*-],+!mul(696,865)why()from()how():,;{where()mul(170,685)who()how()*from(881,957)?&select()mul(894,569):mul(648,114);[:from(657,891)how()mul(740,402)what()&/,do()~^why()who(762,850)mul(80,670)what()^mul(627,741),[?<'when()?-{/mul(609,307)mul(432,475)why()>/mul(325,720)how(555,834)-]~]who()from()mul(823,923)<##how()how()*mul(716,717)'[!:mul(694,196)mul(721,78),*mul(239,457)^who()%~who(),:mul(490,688)(select(140,964)~) where()mul(478,704)when()mul(707,387)?*from()[mul(867,836)how()from()%+?mul(574,230);select()&where()&(&!,mul(817,18)~@mul(995,936){:~#}[{what()how(933,435)%mul(698,758)-mul(155,15)^'who();{;when(538,128)what()([mul(987,654)/>@'mul(547,334)#who()who()mul(481,545)[select()}<*@what()@where()mul(297,163)>~;?mul(569,963) who()%;$?)mul(829,771)'^;^$$<}when()mul(551,298)-![>#%mul(269,961);;$%(select()don't()how()+(mul(490,391)why()where()}}]<])-mul(665,733)* ;select()% ;what()who()!mul(651,691)':mul(972,924)mul(898,314)'/when()><}$)select(196,43)when()mul(622,9)mul(790,299<]~>*from()mul(898,775)mul(433,345)?+mul(936,855)>who()@what()mul(110,344)%mul(375,719)?}'{&where(279,765)mul(846,455)^,{~#<{^;mul(266,935how())~:]-? who()mul(516,281)$~mul(443,485){(mul(798,807)%mul(289,360):*why()~{$!*?'do()?how()mul(316,376)*what()where()[mul(829,9)%$!what()$ &mul(140,439)[why() don't()where(451,986)%]from()mul(335,971),where()^,+mul(109,542);]-when()how()*~mul(209,405)who()$mul(132,427)when()#/>$]mul(773,709)]select()@<^mul(976,853)@where()mul(999,764)who()?^@mul(117,681)/{mul(940,729);})}mul(892,189)why()>,how() &mul(22,503)%+#mul(740,5)mul(848,467),where()>~#^[mul(827,812)!#?'what()$why()what()mul(365,268)$select()+mul(208,463)mul(676,938) +;select()why()^mul(356,375)where()mul(644,829)select()+(&what()&]do()mul(371,455)#}when() select()$mul(652,219)how()/%; >#,'+mul(512,393)where()(+@do()!#where(387,495)select()} why(),where();mul(239,141)+where(){$<;*select()+,mul(96,709)#[how()* +mul(912,58)/,how()mul(683,735)$from()]mul(373,231)from()[why()*how()}%when()+mul(136,796){>don't() ;}<>mul(259,152)mul(263,197)select()where()~(}[:&[mul(77,351)^from()from()who(241,994)select()}&mul(171,570)%mul(468,387)[:when()@>what()^who()[mul(985,798)>&when(578,541):*select()?;mul(686,290)~mul(37,211)?/}*-from()>mul(783,730)({]@why()from()when()&mul(419,383]#%why()where()$who())<~#mul(577,971)*;$& !what() ^mul(912,199)how()don't();when()#mul(294,64)select()where(),'mul(928,320)!+mul(356,471)!where()~]%?]@;mul(118,693)$(mul(300,429)%<[mul(921,437)>how()where(){when()(mul(954,689);how()+$mul(339-,,:mul(368,675)mul~how(81,849)from()?%where();;}where()do(){),>:(#{@where()mul(210,692)!{when(386,55)? mul(930,193) '?mul(346,981)&+-mul(118,871)when()who())when(356,533)mul(953,458)[}why()[{<&where()where()when()@&>where()mul(20,206)#when()select()from()why()$mul(900,802)~(;+(what()mul(995,20)$>'mul(652,338)>mul(363,197)', *?mul(574,101)(when()mul(49,923),;[@:)$select()from()when()@mul(228,113),when();&~/!from()mul(8,372)'}mul(994,769(:@from()<}#why()mul(143,743)>^:!who()$%~?mul(117,918)/@from(),$why()(mul(93,84) mul(672,287)*mul(37,58){^when()~!do()when()!:who(100,513)what()-when()}mul(882,415)-why()~>where()'what()from(838,518)]what()do()@who()]~&mul(29,312)when()why()mul(510[^{*how(663,533)~[*&%mul(664,861)?;$*%+{/mulwho(),what()from()who()!,:where();mul(302,326)when()mul(83,497from()mul(35,835)[mul(429,210){#mul(481,597)+how()&++^+mul(945,205)%don't()^mul(687,611)from()~>why() ,when(140,559)mul(164,17)]~}}-who() mul(520,959)select()select() select()*:mul(575,641)how()mul(842,465)mul(322,73)/&'mul(110,310)>why()from()why(498,7)mul(571,479&from()]%%mul(438,202)who(364,547)from()&; mul(248,502)~{what(),[- select()mul(914,662*{%<~when()mul(508,814)do()%*how()who()from()why(640,284) mul(373,756)'>from()when(904,81)}mul(377,402)mul(352,617)where()select(668,44)+$!mul(977,96)mul(925,147)% select()mul(757,594)mul(667,169) when()who()who()who()mul(12,935)where())%what()what()$from(964,723)mul(84,767)^from() @mul(137^mul(543,4)who()how()};>/do()+select()@}&:+}mul(604,839)from()when()~why()~what()}mul(351,200)where()<)what()}mul(433,87)/$ how()-}mul(666,797)#@+who()how()why()?from()mul(772,579),why()why()from()-{;-}mul(602,921)^>mul(471,330)what()};%when()';:*&mul(438,87)^{( where()!$*from()mul(130,21)from()-[mul(797,649)'{from()/when()mul(897,988) ;when()%!'mulwhy(596,766)$'?how()mul(582,139)} ^><;how(171,166)mul(893,362)where()-'from()how(),mul(371,80):'who(808,795)$mul(72,103)[mul(492,476)(when()~select()~[who()#why()mul(21,185),'?/mul(801,258))mul(548,942) +?-$mul(975 &+#select(489,349)*who())who();)mul(124,21)#from()where()+)/*~ -mul(632,17)%$ don't()mul(939,610)from()(!when()^!^mul(154,101)select()#;mul(338,243)~what()how()&; mul(691,416)*who()@what()mul~where()$<]mul(709,640)? ,/^%where()#*mul(36,427)-where()><#select()mul(457,45)@,*who()when()mul(468,642)where(),how()#'mul(209,501)^;@<+mul(598,391){)(>*mul(760,765)!#}who(894,980)when()what()'%[mul(259,651)^]:mul(955,578)from();({>what()select()*;when()mul(145,399){~what()from()where()who()?-]do();%mul(123,308)mul(488,897)?>';$;where()/mul(249,145)>;select()select()}!]^?mul(204,865)$mul(80,588)-] ;(who()how()*mul(434,798)##)mul(44,74)-mul(520,141)/?(^>+/( who()mul(371,961)#who() ?mul(254,744)-who()*mul(499,955)how()from() >?mul(553,995)>)&-select()>mul(625,699)-,;mul(488,493)?mul(315,42)from()/,:$,,*when()mul(887,391)(#%{ mul(613,520)/'?where()why()mul(709,981)~' how())[mul(460,872) when()%@/?mul(319,730)*) #mul(819,598):; #%mul(186,374)%+{mul(252,553)+}*;]:select()[how()mul(54,460)('mul(767,516)what()!&@[- /~-mul(420,721)where(167,817)}mul(393,198)/what()~^:from()'mul(776,849)<{:/ {?:what()select()mul(503,698)(>~when()what()[,mul(325,23)mul(650,340))mul(206,125)*~%^[&how()<;]/^when()%@(mul(793,635)-*~%how()how()where():mul(91,355)how()[mul(816,280)who(847,273)mul(456,335)%^}#+[mul(111,198)/^mul(104,459))when()%/]{[;why()!mul(915,477)$where()#>where()why()what()what()))mul(842,405)@^$who(){'mul(84,674){&} mul(146,155)mul(833,727);{/;@what()mul(532,66)select()['-]!who()what()'mul(415,148)~<-!{^mul(14,736)where()do()@who()%@>'mul(935,316)how()[<;where()@why()>)what()mul(476,701)?~select()': ^from(639,569);mul(797&+>(%];@};+#!/usr/bin/perl[*/>mul(36,243) +/select()->)*how(386,454)from()mul(300,315)from()#!select()- @-<;mul(363,667)@!<*#*/(^mul(834,851)$ where()@mul(872{{#>$']&how()mul(198,844)'%&# )~;'mul(99,189)!why()when()select()where();mul(834,111)who()mul(679,451):mul(39,313)%{mul(173,934))';'mul(798,4)&?select()who()[select()-mul(311,962)mul(698,905);/{>)?select()where()?mul(803,359)}*'[when())('don't()/<{{)mul(43,610)select()(why(267,624)!'mul(151,244@how()+!>?+who()-%don't()#%,<{what()}from()mul(146,224)mul(863,863):{>where()'+&mul(882,828) what(324,690)from()mul(774,186),+]}:where(824,437)!how()~when()mul(871,259)~(?/],mul(114,251)who()) ?%/when()mul(840@mul(198,246)/};{mul(500,813)/(,@[why()?mul(565,846),&&,#mul(148where()who()where()),?%~'$mul(189,297)&} ['}?}what(),mul(248,226)how()mul(945,791)']*mul(820,292)[>/]do()}what()@why()$^what()-?mulwhere()mul(143,508)do())<$&$'mul(717,939)where() ?mul~@mul?$/!@-~mul(271,138)why()-mul(335,285)when()mul(726,957)select()how():select();mul(231,539)-$ mul(726,673){}mul(78,339)mul@<:mul(119,156)[how()@from()!!$select()mul(828,590)mul(182,837)from()mul(683,176)mul(892{!% who()+!^!mul(403,141)}(}{&mul(324,188)%how()mul(97,443)do()how() [mul(292,615)mul(32,672)<(>)^?$##mul(552,878)mul(190~[select(31,208)how(488,878),mul(803,157)from()]how()&mul(126,470+(*&mul(684,992)when()^[mul(292,454)<}}& ]%# mul(628,183){where()why()!where()where(637,929)^+]do()[mul(673,37)mul(26,197)why()^where()where()>who()when()[-mul(732,481)%/how()~:mul(920,980)'>@)select()[when()mul(832,2)^select()>,*!@where()#(mul(806,526),#}'-/~how()mul(373,273)%why()/mul(948,279) %/$mul(673,973){>?&how()?[(mul(93,63) [select()mul(9,899)]mul(348,281)who()mul(703,726)who()%}/!)select():*%mul(638,192):~who()mul(344,465)~+%where()mul(505,323)[); <[(don't()from(930,874)where()^' %where()mul(860,614)mul(970,547)where()mul(856,910)$^}who()/{-<]mul(685,705-[{when():why()why()%^>mul(133,409)where())-mul(494,959)-where())(mul(391,829) why()['-from(),:mul(773,546)^mul(209,866)'>!who()/~ *[mul(96,420):!where()when()>@]mul(963,114) mul(19,791)<>[what()/[(}mul(514,90)!who())from(){why()mul(421,374)']{$}?(when(){mul(290,986)mul(761,102)[where()*what(72,427)&do()@?'where()mul(14,42)!{select(286,515)#why()mul(229,685)who(){&[mul(395,229)where(254,749)]where()~mul(180,611)-[don't()select()<'where()where()*/mul(854,240)how(565,94)(@}@#select()!mul(369,579)(-when()-from()*mul(878,354)from()why()%%>select(315,631)!(mul(44,680)''&~mul(755,993)}?< (mul(164,540)&?(;mul(49,686)how()[mul(892%*why(),-mul(499,202)mul(802,67)@why()how()?>*]-$mul(754,607)why()how()'from()how()}mul(316,411),where()mul(160,695)#from()who()!](^'!mul(72,797)^^how();where())mul(117,420)mul(222,643)what()+*&,^#-who();mul(582,187)^'(what()/mul(762,337)why()[)%:&^'mul(200,220)#what()[~(mul(869,922)-~mul(174,220)[)#how()+when()>'mul(336,741){[^]+!{^]?mul(72,869)why()mul(968,607)([~!-[/how()%when()mul(315,514)/*<#/?mul(287,442)< ;)*:~?why()mul(932,398); mul(339,6)what()what()%'!$-mul(541,481)*:%mul(278,722) '/mul(221,745)when()?why()'how()&select()mul(863,756)why())?mul(853,974)'~#*when()mul[^},mul(426,383);mul(363,22)+mul(48,755)'[?!+,}select()+mul(450,379) from()where()@![-#mul(504,685)what()!({how()/where()select()select(75,232)(mul(57,262)select()(mul(101,248)$~what()select()who() /!mul(963,497)*where()!~%how()>where()%select(185,346)mul(656,42)@?)$-mul(685,559)how(){^how()from()):]+mul(20,248)'-don't()mul(795,333)^}when();?!)#~+mul(391,920)select()why(998,378)when()((why()why()mul(270,352)[-&>/:why()~,mul(152,35):select()select()select(781,981)mul(262,158)@&%{mul(34,360)where()from(),what()mul(187what()mul(729,608)%mul(339,440)**'!!mul(979,318)''+mul(836,175),<^:(!%{:~mul(829,318)*&?-/[/why()why()~do()~select();(-[mul(558,465)from()who()who()//)-mul(339,776)';}what()from(837,48)how()don't()]where()mul(154,719)#{{mul(308,919)@~*)mul(354,252)select(481,19)who()from(447,581)&%what()>when()mul(261,491)mul(148,283)select()mul(891,12)!$mul(705,454)<$)how()~mul(569,693why()mul(66,218)<^mul(31,825):*what()why()[;#mul(436,424)%how()>[how(727,535)%!do(),~~/mul(269,856)mul(857,460)>%?]/mul(792,512)&},*#mul(744,858);+[#!)(%-?mul(330,415)do()where()mul(527,833):where()+>-!mul(223,83)#![ how()!/mul(549,333),mul(595,422)~mul(980,75)<%^<^~%$mul(403,977)who()![<~what()])/from()mul(862,856)#^&?select()> &+mul^)<^-{when()~{%mul(245,795))who())mul(998,777):@%how()mul(855,136where()<(]@what()#:how()>!mul(385,193)~-what()^why(){mul(844,123)what()#)&?mul(268,192)~&;how()when()>([)mul(316,777)mul(517,887)>(+,what(){mul(488,952)^?- mul(910,954)!%%mul(489,386)mul(665,70)%~when(620,413)/-{%mul(359-?+where()select()~mul(280,485)select()^:mul(821,371)who()}, why(){what(698,375)##^#?}mul(49,637)where()/+[^@)$?mul(60,27)-:>why()#;$do()what(),&@-mul(197,825)when(177,701)-[@^why()#mul(113,357)#}why()/mul(779,647)/why()%from()mul(475,558)@?}who()what()~#; @mul(449,48)why();)[]#,>mul(909,644)%~>don't():##[:mul(203,56)[who()mul(5,956)~select()mul(542,429)!'mul(334,58)@:']/:^mul(315,673)mul(266,818)where():why()'do()-}why()?>when()''$#mul(356,845): mul(75,208)*'*mul(197,931)from()>)&#+]mul(773,636)why()where()^}where()mul(895,801)from()(/^who()}why()[~don't()>!,why():,@where()}mul(630,443):~}$-':<;mul(200,170'[where()how()+};where()mul(79,420)[+@#/select()!;mul(976,90)},}[~>mul(718,701)select()who(46,555)where()^@]?mul(709,96)why()when()'!(where()[mul(918,71)select()?~,how()*{mul(791,355)(mul;,;[mul(909,333)^~mul(152,45)why(935,832)@$;&}mul(202,733)@mul(631,457)$^:+from()select()+'select()mul(35,298)%,~:; mul(459,590)[how()*!]/!select()don't()mul(127,226)when()[why()mul(921;!& what()+>@&what()where()mul(926,614)mul}{'(mul(74,647)&from()?+*~*;*mul(42,7)how();-mul(991,55)where()}-:who()]why()&mul(803,14)^'how(301,29)select()mul(904,721)how()+from(209,448)}-:& ,(mul(786,950)when()}from()how();@-how()mul(44,272):>mul(780,770)mul(983,607)}mul(537,296)why(){mul(183,498) $mul(447,332)mul(857,945)&mul(211,6)-]%&mul(217,55)]where()*select()how():#$mul(610,760)]when()!%[$'mul(812,579)#select()*+how() %mul(650,756)&!,don't()&mul(467,791)<$]?where()mul(708,303)@mul(664,527)[?'mul(459,591)*}%who())select()~:mul(237,606)how()>mul(133,311)mul(554,252)?when(493,438)'^{(do()<{ mul(286,334)(-;how()where()how();;mul(388,580)>select()from()mul(120,119)?*&select()who()mul(375,829)why()+%from()why(),*}+mul(378,224)#mul(330,898)mul(551,592)why()>don't()++'$}mul(660,503)+/ who()why():*mul(978,917)+;[select()-( }mul(848,970)mul(48,20)/$,mul(942,625)+mul(220,813)who()select()~&mul(916,14):!!from(),how()~where()what(647,454)mul(31,90)]/&)<}mul(689,827)@[mul(626,927)'&;))![where()mul(608,109)*mul(317,649)why()'mul(547,176)-who()]@#:mul(465,974)&;[mul(801,152)%[~$who()(mul(229,210)}({)who()how()^where(480,366)^/mul(218,42)&*select(905,451)when()]who()):from()how()do()&what()@from()@select()&, + mul_ops: Vec, pub final_result: i32, } @@ -26,18 +30,49 @@ impl Day3 { pub fn new() -> Day3 { - Day3 { data_set: DataSet::Test, run_mode: RunMode::FirstCase, do_debug_prints: false, final_result: 0 } + Day3 { data_set: DataSet::Test, run_mode: RunMode::FirstCase, do_debug_prints: false, tokens: vec![], mul_ops: vec![], final_result: 0 } } fn solve_first_case(self: &mut Self) -> String { - + let mut parser = Parser::new(self.tokens.clone()); + self.mul_ops = parser.process(); + + if self.do_debug_prints + { + println!("Day 3, DEBUG: Mul operations: {:#?}", self.mul_ops); + } + + let mut sum = 0; + for op in &self.mul_ops + { + sum += op.result(); + } + + self.final_result = sum; self.final_result.to_string() } fn solve_second_case(self: &mut Self) -> String { + let mut parser = Parser::new(self.tokens.clone()); + self.mul_ops = parser.process(); + + if self.do_debug_prints + { + println!("Day 3, DEBUG: Mul operations: {:#?}", self.mul_ops); + } + + let mut sum = 0; + for op in &self.mul_ops + { + if op.is_enabled + { + sum += op.result(); + } + } + self.final_result = sum; self.final_result.to_string() } @@ -55,6 +90,7 @@ impl Solver for Day3 fn init(self: &mut Self, data_set: DataSet, run_mode: RunMode, enable_debug_prints: bool) { + self.data_set = data_set; self.run_mode = run_mode; self.do_debug_prints = enable_debug_prints; @@ -62,14 +98,25 @@ impl Solver for Day3 let data_filename = match self.data_set { - DataSet::Test => format!("{}/data/test_input", dir), - DataSet::Full => format!("{}/data/input", dir), + DataSet::Test => format!("{}/data/day3_test_input", dir), + DataSet::TestAlt => format!("{}/data/day3_test_input_2", dir), + DataSet::Full => format!("{}/data/day3_input", dir), }; - let _data = utils::load_data(&data_filename); + let data = utils::load_data(&data_filename); - // TODO: Day3::init + let mut lex = Lexer::new(&data); + self.tokens = lex.process(); + + if self.do_debug_prints + { + println!("Day 4, DEBUG: tokens: "); + for t in &self.tokens + { + println!("\t{}, ", t); + } + } } diff --git a/crates/day_3/src/lexer.rs b/crates/day_3/src/lexer.rs new file mode 100644 index 0000000..ef08b79 --- /dev/null +++ b/crates/day_3/src/lexer.rs @@ -0,0 +1,216 @@ +/****************************************************************************** +* @file lexer.rs +* @author Joey Pollack +* @date 2024/12/04 (y/m/d) +* @modified 2024/12/04 (y/m/d) +* @copyright Joseph R Pollack +* @brief lexer for day 3 +******************************************************************************/ + +use std::fmt::{self, Display}; + +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +// TOKEN +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Token +{ + Do, + Dont, + Mul, + OpenParen, + CloseParen, + Comma, + Number(i32), + Junk(u8), +} + +impl Display for Token +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + match self + { + Token::Do => write!(f, "Do"), + Token::Dont => write!(f, "Dont"), + Token::Mul => write!(f, "Mul"), + Token::OpenParen => write!(f, "OpenParen"), + Token::CloseParen => write!(f, "CloseParen"), + Token::Comma => write!(f, "Comma"), + Token::Number(v) => write!(f, "Number({})", v), + Token::Junk(v) => write!(f, "Junk({})", *v as char), + } + } +} + +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +// LEXER +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +#[derive(Clone, Debug)] +pub struct Lexer +{ + source: Vec, + current_idx: usize, + jump_stack: Vec, + + tokens: Vec, +} + +impl Lexer +{ + pub fn new(src: &str) -> Lexer + { + Lexer { + source: src.as_bytes().into_iter().map(|x| *x).collect(), + current_idx: 0, + jump_stack: vec![], + tokens: vec![] + } + } + + pub fn process(self: &mut Lexer) -> Vec + { + while !self.at_end() + { + match self.source[self.current_idx] + { + b'd' => self.do_dont_token(), + b'm' => self.mul_token(), + b'(' => self.tokens.push(Token::OpenParen), + b')' => self.tokens.push(Token::CloseParen), + b',' => self.tokens.push(Token::Comma), + b'0'..=b'9' => self.number_token(), + _ => self.tokens.push(Token::Junk(self.source[self.current_idx])), + } + + self.next(); + } + + self.tokens.clone() + } + + // TOKEN HELPERS + fn do_dont_token(self: &mut Lexer) + { + if self.current() != b'd' + { + return; + } + + if self.peek_next() != b'o' + { + return; + } + self.push_current(); + self.next(); + + if self.peek_next() != b'n' + { + self.tokens.push(Token::Do); + return; + } + self.next(); + + if self.peek_next() != b'\'' + { + self.pop_current(); + return; + } + self.next(); + + if self.peek_next() != b't' + { + self.pop_current(); + return; + } + self.next(); + + self.tokens.push(Token::Dont); + } + + fn mul_token(self: &mut Lexer) + { + if self.current() != b'm' + { + return; + } + + if self.peek_next() != b'u' + { + return; + } + self.push_current(); + self.next(); + + if self.peek_next() != b'l' + { + self.pop_current(); + return; + } + self.next(); + + self.tokens.push(Token::Mul); + } + + fn number_token(self: &mut Lexer) + { + let mut num_digits = 1; + let mut digits: String = "".to_string(); + let temp = self.current(); + digits.push(temp as char); + while Lexer::is_numeric(self.peek_next()) + { + num_digits += 1; + self.next(); + let t2 = self.current() as char; + digits.push(t2); + } + + if num_digits > 3 + { + println!("Day 3, WARNING: found a number larger than 3 digits (didn't think that was supposed to happen): {}, at pos: {}", digits, self.current_idx); + } + + self.tokens.push(Token::Number(digits.parse().expect(&format!("Day 3, Lexer: Failed to parse what should have been a number: {}", digits)))); + } + + // CONTROL METHODS + fn current(self: &Lexer) -> u8 + { + self.source[self.current_idx] + } + + fn next(self: &mut Lexer) + { + self.current_idx += 1; + } + + fn peek_next(self: &Lexer) -> u8 + { + self.source[self.current_idx + 1] + } + + fn at_end(self: &Lexer) -> bool + { + self.source.len() <= self.current_idx + } + + fn push_current(self: &mut Lexer) + { + self.jump_stack.push(self.current_idx); + } + + fn pop_current(self: &mut Lexer) + { + self.current_idx = *self.jump_stack.last().expect("Day3, Lexer ERROR: attempt to pop_current but the stack is empty"); + self.jump_stack.pop(); + } + + // GENERAL HELPERS + fn is_numeric(val: u8) -> bool + { + val >= b'0' && val <= b'9' + } + + +} \ No newline at end of file diff --git a/crates/day_3/src/lib.rs b/crates/day_3/src/lib.rs index 96b85f1..aca00bf 100644 --- a/crates/day_3/src/lib.rs +++ b/crates/day_3/src/lib.rs @@ -1,2 +1,4 @@ -pub mod day_3; \ No newline at end of file +pub mod day_3; +pub mod lexer; +pub mod parser; \ No newline at end of file diff --git a/crates/day_3/src/parser.rs b/crates/day_3/src/parser.rs new file mode 100644 index 0000000..63b0c66 --- /dev/null +++ b/crates/day_3/src/parser.rs @@ -0,0 +1,230 @@ +/****************************************************************************** +* @file parser.rs +* @author Joey Pollack +* @date 2024/12/04 (y/m/d) +* @modified 2024/12/04 (y/m/d) +* @copyright Joseph R Pollack +* @brief Parser for day 3 +******************************************************************************/ + +use std::{fmt::{self, Display}, mem}; + +use crate::lexer::Token; + + +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +// MUL STRUCT +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +#[derive(Copy, Clone, Debug)] +pub struct Mul +{ + pub oper_first: i32, + pub oper_second: i32, + pub is_enabled: bool, +} + +impl Display for Mul +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result + { + let status = if self.is_enabled { "ENABLED" } else { "DISABLED" }; + write!(f, "MUL({}, {})[{}]", self.oper_first, self.oper_second, status) + } +} + +impl Mul +{ + fn new(first: i32, second: i32, enabled: bool) -> Mul + { + Mul { oper_first: first, oper_second: second, is_enabled: enabled } + } + + pub fn result(self: &Mul) -> i32 + { + self.oper_first * self.oper_second + } +} + + +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +// PARSER +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +pub struct Parser +{ + tokens: Vec, + current_idx: usize, + mul_enabled: bool, + jump_stack: Vec, + + pub enable_debug_prints: bool +} + +impl Parser +{ + pub fn new(tokens: Vec) -> Parser + { + Parser { tokens, current_idx: 0, mul_enabled: true, jump_stack: vec![], enable_debug_prints: false } + } + + pub fn process(self: &mut Parser) -> Vec + { + let mut mul_operations: Vec = vec![]; + + while !self.at_end() + { + match self.current() + { + Token::Mul => + { + if let Some(operation) = self.parse_mul() + { + mul_operations.push(operation); + } + else + { + self.next(); + } + }, + + Token::Do => + { + let es: Vec> = vec![ + mem::discriminant(&Token::Do), + mem::discriminant(&Token::OpenParen), + mem::discriminant(&Token::CloseParen) + ]; + + if self.match_seq(es) + { + self.mul_enabled = true; + } + else + { + self.next(); + } + }, + + Token::Dont => + { + let es: Vec> = vec![ + mem::discriminant(&Token::Dont), + mem::discriminant(&Token::OpenParen), + mem::discriminant(&Token::CloseParen) + ]; + + if self.match_seq(es) + { + self.mul_enabled = false; + } + else + { + self.next(); + } + }, + + _ => self.next(), + } + + } + + mul_operations + } + + // Attempt to parse a mul instruction + // Does not consume the tokens if it fails + fn parse_mul(self: &mut Parser) -> Option + { + let expected_sequence = + [ + mem::discriminant(&Token::Mul), + mem::discriminant(&Token::OpenParen), + mem::discriminant(&Token::Number(0)), + mem::discriminant(&Token::Comma), + mem::discriminant(&Token::Number(0)), + mem::discriminant(&Token::CloseParen) + ]; + + let mut values: Vec = vec![]; + + self.push_current(); + for et in expected_sequence + { + let current = self.current(); + if mem::discriminant(¤t) != et + { + self.pop_current(); + return None; + } + + match current + { + Token::Number(val) => values.push(val), + _ => () + } + + self.next(); + } + + if values.len() != 2 + { + println!("Day 3, ERROR: Found too many numbers in Mul expression somehow... {:#?}", values); + self.pop_current(); + return None; + } + + Some(Mul::new(values[0], values[1], self.mul_enabled)) + } + + // Returns true if the given sequence of tokens occurs next. + // Only consumes the tokens if the sequence does occur. + fn match_seq(self: &mut Parser, expected_sequence: Vec>) -> bool + { + self.push_current(); + for et in expected_sequence + { + let current = self.current(); + if mem::discriminant(¤t) != et + { + self.pop_current(); + return false; + } + + self.next(); + } + + return true; + } + + + // CONTROL METHODS + fn current(self: &Parser) -> Token + { + self.tokens[self.current_idx] + } + + fn next(self: &mut Parser) + { + self.current_idx += 1; + } + + fn _peek_next(self: &Parser) -> Token + { + self.tokens[self.current_idx + 1] + } + + fn push_current(self: &mut Parser) + { + self.jump_stack.push(self.current_idx); + } + + fn pop_current(self: &mut Parser) + { + self.current_idx = *self.jump_stack.last().expect("Day 3, Parser ERROR: Attempt to pop but stack is empty"); + self.jump_stack.pop(); + } + + fn at_end(self: &Parser) -> bool + { + self.tokens.len() <= self.current_idx + } +} \ No newline at end of file diff --git a/crates/day_4/Cargo.toml b/crates/day_4/Cargo.toml new file mode 100644 index 0000000..01d1a73 --- /dev/null +++ b/crates/day_4/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "day_4" +description = "Day 4 of the Advent of Code 2024" +version = "0.1.0" +edition = "2021" + +[dependencies] +solver_base = { workspace = true } +utils = { workspace = true } \ No newline at end of file diff --git a/crates/day_4/build.rs b/crates/day_4/build.rs new file mode 100644 index 0000000..4cd9495 --- /dev/null +++ b/crates/day_4/build.rs @@ -0,0 +1,33 @@ + +use std::{env, fs, path::Path}; + +fn main() +{ + // let out_dir = env::var("OUT_DIR").unwrap(); + // let cwd = env::var("CARGO_MANIFEST_DIR").unwrap(); + // println!("CWD: {}\n", cwd); + // let data_dir = cwd + "\\data"; + // let data_path = Path::new(&data_dir); + // println!("Data path: {}", data_path.to_string_lossy()); + + // let data_path = Path::new("data/test_input"); + + // let out_dir = env::var("OUT_DIR").unwrap(); + // panic!("out_dir: {}", out_dir); + let out_path = format!("../../target/{}", &env::var("PROFILE").unwrap()); + let out_path = Path::new(&out_path); + //let out_path = Path::new(&out_dir).join(&env::var("PROFILE").unwrap()); + let out_path_data = out_path.join(Path::new("data")); + + if !out_path_data.exists() + { + fs::create_dir(&out_path_data).expect(&format!("Could not create data directory at: {}", out_path_data.to_string_lossy())); + } + + for file in fs::read_dir("data").unwrap() + { + let file = file.unwrap(); + let dest = out_path.join(file.path()); + fs::copy(file.path(), &dest).expect(&format!("Could not copy file {} to {}", file.path().to_string_lossy(), dest.to_string_lossy())); + } +} \ No newline at end of file diff --git a/crates/day_4/src/day_4.rs b/crates/day_4/src/day_4.rs new file mode 100644 index 0000000..8e7d859 --- /dev/null +++ b/crates/day_4/src/day_4.rs @@ -0,0 +1,94 @@ + +/****************************************************************************** +* @file day_4.rs +* @author Joey Pollack +* @date 2024/12/04 (y/m/d) +* @modified 2024/12/04 (y/m/d) +* @copyright Joseph R Pollack +* @brief Advent of Code 2024 day 4 problems +******************************************************************************/ + +use ::solver_base::solver_base::{Solver, DataSet, RunMode}; +use utils::utils; + +pub struct Day4 +{ + data_set: DataSet, + run_mode: RunMode, + do_debug_prints: bool, + pub final_result: i32, +} + +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +// DAY 4 IMPL +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +impl Day4 +{ + pub fn new() -> Day4 + { + Day4 { data_set: DataSet::Test, run_mode: RunMode::FirstCase, do_debug_prints: false, final_result: 0 } + } + + fn solve_first_case(self: &mut Self) -> String + { + + self.final_result.to_string() + } + + fn solve_second_case(self: &mut Self) -> String + { + + + self.final_result.to_string() + } +} + +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +// SOLVER TRAIT IMPL +//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| +impl Solver for Day4 +{ + fn print_test() + { + println!("DAY 4 TEST PRINT"); + } + + fn init(self: &mut Self, data_set: DataSet, run_mode: RunMode, enable_debug_prints: bool) + { + self.data_set = data_set; + self.run_mode = run_mode; + self.do_debug_prints = enable_debug_prints; + + let dir = utils::get_working_dir(); + let data_filename = + match self.data_set + { + DataSet::Test => format!("{}/data/day4_test_input", dir), + DataSet::TestAlt => panic!("Day 4: There is no TestAlt input file!"), //format!("{}/data/day2_test_input", dir), + DataSet::Full => format!("{}/data/day4_input", dir), + }; + + + let _data = utils::load_data(&data_filename); + + // TODO: Day4::init + + } + + fn solve(self: &mut Self) -> String + { + match self.run_mode + { + RunMode::FirstCase => + { + self.solve_first_case() + }, + + RunMode::SecondCase => + { + self.solve_second_case() + } + } + } + +} \ No newline at end of file diff --git a/crates/day_4/src/lib.rs b/crates/day_4/src/lib.rs new file mode 100644 index 0000000..d5217ed --- /dev/null +++ b/crates/day_4/src/lib.rs @@ -0,0 +1,2 @@ + +pub mod day_4; \ No newline at end of file diff --git a/crates/solver_base/src/solver_base.rs b/crates/solver_base/src/solver_base.rs index c2f6128..1867014 100644 --- a/crates/solver_base/src/solver_base.rs +++ b/crates/solver_base/src/solver_base.rs @@ -11,6 +11,7 @@ pub enum RunMode pub enum DataSet { Test, + TestAlt, Full, } diff --git a/src/main.rs b/src/main.rs index 0d0c1e7..0ce3638 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ use day_1::day_1::Day1; use day_2::day_2::Day2; +use day_3::day_3::Day3; use solver_base::solver_base::{Solver, DataSet, RunMode}; fn main() @@ -36,4 +37,15 @@ fn main() let day2_result = day_2.solve(); println!("Day2 Part 2 Final Result: {}", day2_result); + // DAY 3 + let mut day_3 = Day3::new(); + day_3.init(DataSet::Full, RunMode::FirstCase, false); + let day3_result = day_3.solve(); + println!("Day3 Part 1 Final Result: {}", day3_result); + + let mut day_3 = Day3::new(); + day_3.init(DataSet::Full, RunMode::SecondCase, false); + let day3_result = day_3.solve(); + println!("Day3 Part 2 Final Result: {}", day3_result); + }