diff --git a/.gitattributes b/.gitattributes index 1ff0c42..b7d4ef6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,63 +1,63 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index eaa9902..43d9deb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,363 +1,363 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Oo]ut/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd diff --git a/AdventOfCode.sln b/AdventOfCode.sln index a6ac603..e1a6b57 100644 --- a/AdventOfCode.sln +++ b/AdventOfCode.sln @@ -1,25 +1,25 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.4.33110.190 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdventOfCode", "AdventOfCode\AdventOfCode.csproj", "{CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {1FDE3D49-4BB6-48E2-B2CE-617A7B97684B} - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33110.190 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AdventOfCode", "AdventOfCode\AdventOfCode.csproj", "{CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CAAB9EC2-0787-4CBC-87E3-4529BFB56B3F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {1FDE3D49-4BB6-48E2-B2CE-617A7B97684B} + EndGlobalSection +EndGlobal diff --git a/AdventOfCode/AdventOfCode.csproj b/AdventOfCode/AdventOfCode.csproj index 3d8672d..4f8869c 100644 --- a/AdventOfCode/AdventOfCode.csproj +++ b/AdventOfCode/AdventOfCode.csproj @@ -1,81 +1,83 @@ - - - - Exe - net9.0 - enable - enable - - - - - - PreserveNewest - - - - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + Exe + net9.0 + enable + enable + + + + + + PreserveNewest + + + + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AdventOfCode/Problems/.gitignore b/AdventOfCode/Problems/.gitignore index 0b956fc..6735430 100644 --- a/AdventOfCode/Problems/.gitignore +++ b/AdventOfCode/Problems/.gitignore @@ -1,2 +1,2 @@ -*/*/*.txt +*/*/*.txt */*/*.csv \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2015/Day10/LookAndSay.cs b/AdventOfCode/Problems/AOC2015/Day10/LookAndSay.cs index 3eef30e..8ba9adf 100644 --- a/AdventOfCode/Problems/AOC2015/Day10/LookAndSay.cs +++ b/AdventOfCode/Problems/AOC2015/Day10/LookAndSay.cs @@ -1,58 +1,58 @@ -using AdventOfCode.Runner.Attributes; - -using System.Text; - -namespace AdventOfCode.Problems.AOC2015.Day10; - -[ProblemInfo(2015, 10, "Evles Look, Elves Say")] -internal class LookAndSay : Problem -{ - private string _input = string.Empty; - - public override void CalculatePart1() - { - Part1 = Run(40); - } - - public override void CalculatePart2() - { - Part2 = Run(50); - } - - public override void LoadInput() - { - _input = "3113322113"; - } - - public int Run(int iter) - { - var value = new StringBuilder(_input); - for (int i = 0; i < iter; i++) - CalculateNext(ref value); - - return value.Length; - } - - private static void CalculateNext(ref StringBuilder input) - { - var next = new StringBuilder(); - var len = input.Length; - var curCount = 1; - var curChar = input[0]; - for (int i = 1; i < len; i++) - { - var c = input[i]; - if (c != curChar) - { - next.Append(curCount).Append(curChar); - curChar = c; - curCount = 1; - continue; - } - curCount++; - } - next.Append(curCount).Append(curChar); - - input = next; - } +using AdventOfCode.Runner.Attributes; + +using System.Text; + +namespace AdventOfCode.Problems.AOC2015.Day10; + +[ProblemInfo(2015, 10, "Evles Look, Elves Say")] +internal class LookAndSay : Problem +{ + private string _input = string.Empty; + + public override void CalculatePart1() + { + Part1 = Run(40); + } + + public override void CalculatePart2() + { + Part2 = Run(50); + } + + public override void LoadInput() + { + _input = "3113322113"; + } + + public int Run(int iter) + { + var value = new StringBuilder(_input); + for (int i = 0; i < iter; i++) + CalculateNext(ref value); + + return value.Length; + } + + private static void CalculateNext(ref StringBuilder input) + { + var next = new StringBuilder(); + var len = input.Length; + var curCount = 1; + var curChar = input[0]; + for (int i = 1; i < len; i++) + { + var c = input[i]; + if (c != curChar) + { + next.Append(curCount).Append(curChar); + curChar = c; + curCount = 1; + continue; + } + curCount++; + } + next.Append(curCount).Append(curChar); + + input = next; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2015/Day5/NiceList.cs b/AdventOfCode/Problems/AOC2015/Day5/NiceList.cs index 65b8782..44a6ff2 100644 --- a/AdventOfCode/Problems/AOC2015/Day5/NiceList.cs +++ b/AdventOfCode/Problems/AOC2015/Day5/NiceList.cs @@ -1,110 +1,110 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2015.Day5; - -[ProblemInfo(2015, 5, "Doesn't He Have Intern-Elves For This?")] -public class NiceList : Problem -{ - private string[] _inputData = Array.Empty(); - - public override void LoadInput() - { - _inputData = ReadInputLines(); - } - - public override void CalculatePart1() - { - for (int i = 0; i < _inputData.Length; i++) - { - if (IsNice(_inputData[i])) - Part1++; - } - } - - public override void CalculatePart2() - { - for (int i = 0; i < _inputData.Length; i++) - { - if (IsNice2(_inputData[i])) - { - Part2++; - } - } - } - - private static bool IsNice2(string value) - { - var pairs = new Dictionary>(); - var separatedPair = false; - - for (int i = 1; i < value.Length; i++) - { - var c = value[i]; - var curIndex = i - 1; - var pair = value[curIndex..(i + 1)]; - if (pairs.ContainsKey(pair)) - { - if (pairs[pair].Contains(curIndex - 1)) - continue; - pairs[pair].Add(curIndex); - } - else - { - pairs.Add(pair, new List() { curIndex }); - } - - if (i == 1) - continue; - if (value[i - 2] == c) - separatedPair = true; - } - - return separatedPair && pairs.Any(p => p.Value.Count >= 2); - } - - private static bool IsNice(string value) - { - var vowelCount = 0; - var doubleLetters = false; - for (int i = 0; i < value.Length; i++) - { - char c = value[i]; - if (IsVowel(c)) - vowelCount++; - if (i == 0) - continue; - var lastChar = value[i - 1]; - if (IsIllegal(c, lastChar)) - return false; - if (IsDouble(c, lastChar)) - doubleLetters = true; - } - return doubleLetters && vowelCount >= 3; - } - - private static bool IsVowel(char c) - { - return c switch - { - 'a' or 'e' or 'i' or 'o' or 'u' => true, - _ => false - }; - } - - private static bool IsDouble(char c, char lastChar) - { - return c == lastChar; - } - - private static bool IsIllegal(char c, char lastChar) - { - return (lastChar, c) switch - { - ('a', 'b') => true, - ('c', 'd') => true, - ('p', 'q') => true, - ('x', 'y') => true, - _ => false - }; - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2015.Day5; + +[ProblemInfo(2015, 5, "Doesn't He Have Intern-Elves For This?")] +public class NiceList : Problem +{ + private string[] _inputData = Array.Empty(); + + public override void LoadInput() + { + _inputData = ReadInputLines(); + } + + public override void CalculatePart1() + { + for (int i = 0; i < _inputData.Length; i++) + { + if (IsNice(_inputData[i])) + Part1++; + } + } + + public override void CalculatePart2() + { + for (int i = 0; i < _inputData.Length; i++) + { + if (IsNice2(_inputData[i])) + { + Part2++; + } + } + } + + private static bool IsNice2(string value) + { + var pairs = new Dictionary>(); + var separatedPair = false; + + for (int i = 1; i < value.Length; i++) + { + var c = value[i]; + var curIndex = i - 1; + var pair = value[curIndex..(i + 1)]; + if (pairs.ContainsKey(pair)) + { + if (pairs[pair].Contains(curIndex - 1)) + continue; + pairs[pair].Add(curIndex); + } + else + { + pairs.Add(pair, new List() { curIndex }); + } + + if (i == 1) + continue; + if (value[i - 2] == c) + separatedPair = true; + } + + return separatedPair && pairs.Any(p => p.Value.Count >= 2); + } + + private static bool IsNice(string value) + { + var vowelCount = 0; + var doubleLetters = false; + for (int i = 0; i < value.Length; i++) + { + char c = value[i]; + if (IsVowel(c)) + vowelCount++; + if (i == 0) + continue; + var lastChar = value[i - 1]; + if (IsIllegal(c, lastChar)) + return false; + if (IsDouble(c, lastChar)) + doubleLetters = true; + } + return doubleLetters && vowelCount >= 3; + } + + private static bool IsVowel(char c) + { + return c switch + { + 'a' or 'e' or 'i' or 'o' or 'u' => true, + _ => false + }; + } + + private static bool IsDouble(char c, char lastChar) + { + return c == lastChar; + } + + private static bool IsIllegal(char c, char lastChar) + { + return (lastChar, c) switch + { + ('a', 'b') => true, + ('c', 'd') => true, + ('p', 'q') => true, + ('x', 'y') => true, + _ => false + }; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day1/FuelCaluclation.cs b/AdventOfCode/Problems/AOC2019/Day1/FuelCaluclation.cs index 2a10c32..aa505d2 100644 --- a/AdventOfCode/Problems/AOC2019/Day1/FuelCaluclation.cs +++ b/AdventOfCode/Problems/AOC2019/Day1/FuelCaluclation.cs @@ -1,41 +1,41 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2019.Day1 -{ - [ProblemInfo(2019, 1, "The Tyranny of the Rocket Equation")] - public class FuelCaluclation : Problem - { - private int[] _input = Array.Empty(); - - public static int GetFuelRequirement(int[] input) - { - var curFuel = input.Sum(i => GetFuelCost(i)); - return curFuel; - } - - public static int GetFuelCost(int mass) - { - var curCost = mass / 3 - 2; - if (curCost <= 0) - return 0; - return curCost + GetFuelCost(curCost); - } - - public static int GetCost(int mass) => mass / 3 - 2; - - public override void LoadInput() - { - _input = InputParsing.ParseIntArray(GetInputFile()); - } - - public override void CalculatePart1() - { - Part1 = _input.Sum(i => GetCost(i)); - } - - public override void CalculatePart2() - { - Part2 = GetFuelRequirement(_input); - } - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2019.Day1 +{ + [ProblemInfo(2019, 1, "The Tyranny of the Rocket Equation")] + public class FuelCaluclation : Problem + { + private int[] _input = Array.Empty(); + + public static int GetFuelRequirement(int[] input) + { + var curFuel = input.Sum(i => GetFuelCost(i)); + return curFuel; + } + + public static int GetFuelCost(int mass) + { + var curCost = mass / 3 - 2; + if (curCost <= 0) + return 0; + return curCost + GetFuelCost(curCost); + } + + public static int GetCost(int mass) => mass / 3 - 2; + + public override void LoadInput() + { + _input = InputParsing.ParseIntArray(GetInputFile()); + } + + public override void CalculatePart1() + { + Part1 = _input.Sum(i => GetCost(i)); + } + + public override void CalculatePart2() + { + Part2 = GetFuelRequirement(_input); + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day2/IntCode.cs b/AdventOfCode/Problems/AOC2019/Day2/IntCode.cs index 6722026..d37e366 100644 --- a/AdventOfCode/Problems/AOC2019/Day2/IntCode.cs +++ b/AdventOfCode/Problems/AOC2019/Day2/IntCode.cs @@ -1,72 +1,72 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2019.Day2 -{ - [ProblemInfo(2019, 2, "Program Alarm")] - public class IntCode : Problem - { - private int[] _inputPart1 = Array.Empty(); - private int[] _inputPart2 = Array.Empty(); - - public static int ExecuteCode(int[] code, int noun, int verb) - { - int[] memory = code; - memory[1] = noun; - memory[2] = verb; - var curAddr = 0; - - while (true) - { - var opCode = memory[curAddr]; - - if (opCode == 99) //Halt - return memory[0]; - - //Working Adresses - int a = memory[curAddr + 1], b = memory[curAddr + 2], c = memory[curAddr + 3]; - - if (a > memory.Length || b > memory.Length || c > memory.Length) - { - Console.WriteLine("ERROR: Out of Bounds"); - return 0; - } - - if (opCode == 1) //Add - memory[c] = memory[a] + memory[b]; - if (opCode == 2) //Multiply - memory[c] = memory[a] * memory[b]; - - curAddr += 4; - } - } - - public override void LoadInput() - { - _inputPart1 = InputParsing.ParseIntCsv(GetInputFile("input.csv")); - _inputPart2 = InputParsing.ParseIntCsv(GetInputFile("input.csv")); - } - - public override void CalculatePart1() - { - Part1 = ExecuteCode(_inputPart1, 12, 2); - } - - public override void CalculatePart2() - { - int targetOutput = 19690720; - for (int n = 0; n < 100; n++) - { - for (int v = 0; v < 100; v++) - { - var curInput = new int[_inputPart2.Length]; - Array.Copy(_inputPart2, curInput, _inputPart2.Length); - if (ExecuteCode(curInput, n, v) == targetOutput) - { - Part2 = 100 * n + v; - return; - } - } - } - } - } -} +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2019.Day2 +{ + [ProblemInfo(2019, 2, "Program Alarm")] + public class IntCode : Problem + { + private int[] _inputPart1 = Array.Empty(); + private int[] _inputPart2 = Array.Empty(); + + public static int ExecuteCode(int[] code, int noun, int verb) + { + int[] memory = code; + memory[1] = noun; + memory[2] = verb; + var curAddr = 0; + + while (true) + { + var opCode = memory[curAddr]; + + if (opCode == 99) //Halt + return memory[0]; + + //Working Adresses + int a = memory[curAddr + 1], b = memory[curAddr + 2], c = memory[curAddr + 3]; + + if (a > memory.Length || b > memory.Length || c > memory.Length) + { + Console.WriteLine("ERROR: Out of Bounds"); + return 0; + } + + if (opCode == 1) //Add + memory[c] = memory[a] + memory[b]; + if (opCode == 2) //Multiply + memory[c] = memory[a] * memory[b]; + + curAddr += 4; + } + } + + public override void LoadInput() + { + _inputPart1 = InputParsing.ParseIntCsv(GetInputFile("input.csv")); + _inputPart2 = InputParsing.ParseIntCsv(GetInputFile("input.csv")); + } + + public override void CalculatePart1() + { + Part1 = ExecuteCode(_inputPart1, 12, 2); + } + + public override void CalculatePart2() + { + int targetOutput = 19690720; + for (int n = 0; n < 100; n++) + { + for (int v = 0; v < 100; v++) + { + var curInput = new int[_inputPart2.Length]; + Array.Copy(_inputPart2, curInput, _inputPart2.Length); + if (ExecuteCode(curInput, n, v) == targetOutput) + { + Part2 = 100 * n + v; + return; + } + } + } + } + } +} diff --git a/AdventOfCode/Problems/AOC2019/Day3/CrossedWires.cs b/AdventOfCode/Problems/AOC2019/Day3/CrossedWires.cs index b232fc9..c1a6133 100644 --- a/AdventOfCode/Problems/AOC2019/Day3/CrossedWires.cs +++ b/AdventOfCode/Problems/AOC2019/Day3/CrossedWires.cs @@ -1,319 +1,319 @@ -using AdventOfCode.Runner.Attributes; - -using System.Drawing; - -namespace AdventOfCode.Problems.AOC2019.Day3 -{ - [ProblemInfo(2019, 3, "Crossed Wires")] - public class CrossedWires : Problem - { - private string[] _inputLines = Array.Empty(); - - public struct WireSegment - { - public Point min, max; - public Point start, end; - - public int Length; - - public bool Vertical => min.X == max.X; - - public WireSegment(Point a, Point b) - { - start = a; - end = b; - if (a.X == b.X) //Vertical - { - if (a.Y < b.Y) - { - min = a; - max = b; - } - else - { - min = b; - max = a; - } - Length = Math.Abs(b.Y - a.Y); - } - else - { - if (a.X < b.X) - { - min = a; - max = b; - } - else - { - min = b; - max = a; - } - Length = Math.Abs(b.X - a.X); - } - } - - public WireSegment CreateRelative(Point offset) - { - return new WireSegment(end, new Point(end.X + offset.X, end.Y + offset.Y)); - } - - public bool ContainsPoint(Point point) - { - if (Vertical) - { - if (min.X == point.X) - { - return min.Y <= point.Y && max.Y >= point.Y; - } - else - return false; - } - else - { - if (min.Y == point.Y) - { - return min.X <= point.X && max.X >= point.X; - } - else - return false; - } - } - - public bool Contains(WireSegment other) - { - if (Vertical != other.Vertical) - return false; - if (Vertical) - { - return min.Y <= other.min.Y && max.Y >= other.max.Y; - } - else - { - return min.X <= other.min.X && max.X >= other.max.X; - } - } - - public WireSegment GetOverlap(WireSegment other) - { - if (Vertical) - { - if (other.Contains(this)) - return this; - else if (Contains(other)) - return other; - if (max.Y >= other.min.Y && min.Y <= other.min.Y && max.Y <= other.max.Y) - { - return new WireSegment(other.min, max); - } - else if (max.Y >= other.max.Y && min.Y >= other.min.Y && min.Y <= other.max.Y) - return new WireSegment(min, other.max); - else - throw new Exception("No Overlap"); - } - else - { - if (other.Contains(this)) - return this; - else if (Contains(other)) - return other; - if (max.X >= other.min.X && min.X <= other.min.X && max.X <= other.max.X) - { - return new WireSegment(other.min, max); - } - else if (max.X >= other.max.X && min.X >= other.min.X && min.X <= other.max.X) - return new WireSegment(min, other.max); - else - throw new Exception("No Overlap"); - } - } - - public bool Intersect(WireSegment other, out Point intersection) - { - if (Vertical) - { - if (!other.Vertical)//Other Horizontal - { - var potInt = new Point(min.X, other.min.Y); - if (potInt == default) - { - intersection = default; - return false; - } - if (ContainsPoint(potInt) && other.ContainsPoint(potInt)) - { - intersection = potInt; - return true; - } - else - { - intersection = default; - return false; - } - } - else //Both - { - if (min.X != other.min.X) - { - intersection = default; - return false; - } - else - { - var overlap = GetOverlap(other); - if (ManhattanMagnitude(overlap.min) < ManhattanMagnitude(overlap.max)) - intersection = overlap.min == default ? overlap.max : overlap.min; - else - intersection = overlap.max == default ? overlap.min : overlap.max; - if (intersection == default) - return false; - return true; - } - } - } - else - { - if (!other.Vertical) //Other Horizontal - { - if (min.Y != other.min.Y) - { - intersection = default; - return false; - } - var overlap = GetOverlap(other); - if (ManhattanMagnitude(overlap.min) < ManhattanMagnitude(overlap.max)) - intersection = overlap.min == default ? overlap.max : overlap.min; - else - intersection = overlap.max == default ? overlap.min : overlap.max; - if (intersection == default) - return false; - return true; - } - else - return other.Intersect(this, out intersection); - } - } - - public override string ToString() - { - return $"{start} > {end}"; - } - } - - public static int StepsToPoint(List wires, Point p) - { - var steps = 0; - for (int i = 0; i < wires.Count; i++) - { - if (wires[i].ContainsPoint(p)) - { - if (wires[i].Vertical) - steps += Math.Abs(wires[i].start.Y - p.Y); - else - steps += Math.Abs(wires[i].start.X - p.X); - break; - } - else - steps += wires[i].Length; - } - return steps; - } - - public static int SolveWires(string[] wires) - { - var (wireSegmentsA, wireSegmentsB) = CreateWirePair(wires); - - int shortestWire = int.MaxValue; - for (int i = 0; i < wireSegmentsA.Count; i++) - { - for (int j = 0; j < wireSegmentsB.Count; j++) - { - if (wireSegmentsA[i].Intersect(wireSegmentsB[j], out var intersection)) - { - var len = StepsToPoint(wireSegmentsA, intersection) + StepsToPoint(wireSegmentsB, intersection); - if (len < shortestWire) - shortestWire = len; - } - } - } - return shortestWire; - } - - public static int SolveClosestDistane(string[] wires) - { - var (wireSegmentsA, wireSegmentsB) = CreateWirePair(wires); - - int lastIntersection = int.MaxValue; - for (int i = 0; i < wireSegmentsA.Count; i++) - { - for (int j = 0; j < wireSegmentsB.Count; j++) - { - if (wireSegmentsA[i].Intersect(wireSegmentsB[j], out var intersection)) - { - var dist = ManhattanMagnitude(intersection); - if (dist < lastIntersection) - lastIntersection = dist; - } - } - } - return lastIntersection; - } - - private static (List A, List B) CreateWirePair(string[] wires) - { - var wireA = wires[0].Split(','); - var wireSegmentsA = CreateWire(wireA); - - var wireB = wires[1].Split(','); - var wireSegmentsB = CreateWire(wireB); - - return (wireSegmentsA, wireSegmentsB); - } - - private static List CreateWire(string[] wires) - { - var wireSegments = new List(); - - for (int i = 0; i < wires.Length; i++) - { - var curSegment = wires[i]; - var offset = GetOffset(curSegment); - if (i == 0) - wireSegments.Add(new WireSegment(new Point(0, 0), offset)); - else - wireSegments.Add(wireSegments.Last().CreateRelative(offset)); - } - return wireSegments; - } - - public static int ManhattanMagnitude(Point point) => Math.Abs(point.X) + Math.Abs(point.Y); - - public static Point GetOffset(string move) - { - int x = 0, y = 0; - if (move[0] == 'R') - x = int.Parse(move.Remove(0, 1)); - else if (move[0] == 'L') - x = -int.Parse(move.Remove(0, 1)); - else if (move[0] == 'U') - y = int.Parse(move.Remove(0, 1)); - else if (move[0] == 'D') - y = -int.Parse(move.Remove(0, 1)); - return new Point(x, y); - } - - public override void LoadInput() - { - _inputLines = ReadInputLines(); - } - - public override void CalculatePart1() - { - Part1 = SolveClosestDistane(_inputLines); - } - - public override void CalculatePart2() - { - Part2 = SolveWires(_inputLines); - } - } +using AdventOfCode.Runner.Attributes; + +using System.Drawing; + +namespace AdventOfCode.Problems.AOC2019.Day3 +{ + [ProblemInfo(2019, 3, "Crossed Wires")] + public class CrossedWires : Problem + { + private string[] _inputLines = Array.Empty(); + + public struct WireSegment + { + public Point min, max; + public Point start, end; + + public int Length; + + public bool Vertical => min.X == max.X; + + public WireSegment(Point a, Point b) + { + start = a; + end = b; + if (a.X == b.X) //Vertical + { + if (a.Y < b.Y) + { + min = a; + max = b; + } + else + { + min = b; + max = a; + } + Length = Math.Abs(b.Y - a.Y); + } + else + { + if (a.X < b.X) + { + min = a; + max = b; + } + else + { + min = b; + max = a; + } + Length = Math.Abs(b.X - a.X); + } + } + + public WireSegment CreateRelative(Point offset) + { + return new WireSegment(end, new Point(end.X + offset.X, end.Y + offset.Y)); + } + + public bool ContainsPoint(Point point) + { + if (Vertical) + { + if (min.X == point.X) + { + return min.Y <= point.Y && max.Y >= point.Y; + } + else + return false; + } + else + { + if (min.Y == point.Y) + { + return min.X <= point.X && max.X >= point.X; + } + else + return false; + } + } + + public bool Contains(WireSegment other) + { + if (Vertical != other.Vertical) + return false; + if (Vertical) + { + return min.Y <= other.min.Y && max.Y >= other.max.Y; + } + else + { + return min.X <= other.min.X && max.X >= other.max.X; + } + } + + public WireSegment GetOverlap(WireSegment other) + { + if (Vertical) + { + if (other.Contains(this)) + return this; + else if (Contains(other)) + return other; + if (max.Y >= other.min.Y && min.Y <= other.min.Y && max.Y <= other.max.Y) + { + return new WireSegment(other.min, max); + } + else if (max.Y >= other.max.Y && min.Y >= other.min.Y && min.Y <= other.max.Y) + return new WireSegment(min, other.max); + else + throw new Exception("No Overlap"); + } + else + { + if (other.Contains(this)) + return this; + else if (Contains(other)) + return other; + if (max.X >= other.min.X && min.X <= other.min.X && max.X <= other.max.X) + { + return new WireSegment(other.min, max); + } + else if (max.X >= other.max.X && min.X >= other.min.X && min.X <= other.max.X) + return new WireSegment(min, other.max); + else + throw new Exception("No Overlap"); + } + } + + public bool Intersect(WireSegment other, out Point intersection) + { + if (Vertical) + { + if (!other.Vertical)//Other Horizontal + { + var potInt = new Point(min.X, other.min.Y); + if (potInt == default) + { + intersection = default; + return false; + } + if (ContainsPoint(potInt) && other.ContainsPoint(potInt)) + { + intersection = potInt; + return true; + } + else + { + intersection = default; + return false; + } + } + else //Both + { + if (min.X != other.min.X) + { + intersection = default; + return false; + } + else + { + var overlap = GetOverlap(other); + if (ManhattanMagnitude(overlap.min) < ManhattanMagnitude(overlap.max)) + intersection = overlap.min == default ? overlap.max : overlap.min; + else + intersection = overlap.max == default ? overlap.min : overlap.max; + if (intersection == default) + return false; + return true; + } + } + } + else + { + if (!other.Vertical) //Other Horizontal + { + if (min.Y != other.min.Y) + { + intersection = default; + return false; + } + var overlap = GetOverlap(other); + if (ManhattanMagnitude(overlap.min) < ManhattanMagnitude(overlap.max)) + intersection = overlap.min == default ? overlap.max : overlap.min; + else + intersection = overlap.max == default ? overlap.min : overlap.max; + if (intersection == default) + return false; + return true; + } + else + return other.Intersect(this, out intersection); + } + } + + public override string ToString() + { + return $"{start} > {end}"; + } + } + + public static int StepsToPoint(List wires, Point p) + { + var steps = 0; + for (int i = 0; i < wires.Count; i++) + { + if (wires[i].ContainsPoint(p)) + { + if (wires[i].Vertical) + steps += Math.Abs(wires[i].start.Y - p.Y); + else + steps += Math.Abs(wires[i].start.X - p.X); + break; + } + else + steps += wires[i].Length; + } + return steps; + } + + public static int SolveWires(string[] wires) + { + var (wireSegmentsA, wireSegmentsB) = CreateWirePair(wires); + + int shortestWire = int.MaxValue; + for (int i = 0; i < wireSegmentsA.Count; i++) + { + for (int j = 0; j < wireSegmentsB.Count; j++) + { + if (wireSegmentsA[i].Intersect(wireSegmentsB[j], out var intersection)) + { + var len = StepsToPoint(wireSegmentsA, intersection) + StepsToPoint(wireSegmentsB, intersection); + if (len < shortestWire) + shortestWire = len; + } + } + } + return shortestWire; + } + + public static int SolveClosestDistane(string[] wires) + { + var (wireSegmentsA, wireSegmentsB) = CreateWirePair(wires); + + int lastIntersection = int.MaxValue; + for (int i = 0; i < wireSegmentsA.Count; i++) + { + for (int j = 0; j < wireSegmentsB.Count; j++) + { + if (wireSegmentsA[i].Intersect(wireSegmentsB[j], out var intersection)) + { + var dist = ManhattanMagnitude(intersection); + if (dist < lastIntersection) + lastIntersection = dist; + } + } + } + return lastIntersection; + } + + private static (List A, List B) CreateWirePair(string[] wires) + { + var wireA = wires[0].Split(','); + var wireSegmentsA = CreateWire(wireA); + + var wireB = wires[1].Split(','); + var wireSegmentsB = CreateWire(wireB); + + return (wireSegmentsA, wireSegmentsB); + } + + private static List CreateWire(string[] wires) + { + var wireSegments = new List(); + + for (int i = 0; i < wires.Length; i++) + { + var curSegment = wires[i]; + var offset = GetOffset(curSegment); + if (i == 0) + wireSegments.Add(new WireSegment(new Point(0, 0), offset)); + else + wireSegments.Add(wireSegments.Last().CreateRelative(offset)); + } + return wireSegments; + } + + public static int ManhattanMagnitude(Point point) => Math.Abs(point.X) + Math.Abs(point.Y); + + public static Point GetOffset(string move) + { + int x = 0, y = 0; + if (move[0] == 'R') + x = int.Parse(move.Remove(0, 1)); + else if (move[0] == 'L') + x = -int.Parse(move.Remove(0, 1)); + else if (move[0] == 'U') + y = int.Parse(move.Remove(0, 1)); + else if (move[0] == 'D') + y = -int.Parse(move.Remove(0, 1)); + return new Point(x, y); + } + + public override void LoadInput() + { + _inputLines = ReadInputLines(); + } + + public override void CalculatePart1() + { + Part1 = SolveClosestDistane(_inputLines); + } + + public override void CalculatePart2() + { + Part2 = SolveWires(_inputLines); + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day4/SecureContainer.cs b/AdventOfCode/Problems/AOC2019/Day4/SecureContainer.cs index 4273046..33d60c2 100644 --- a/AdventOfCode/Problems/AOC2019/Day4/SecureContainer.cs +++ b/AdventOfCode/Problems/AOC2019/Day4/SecureContainer.cs @@ -1,147 +1,147 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2019.Day4 -{ - [ProblemInfo(2019, 4, "Secure Container")] - public class SecureContainer : Problem - { - public static bool IsValidPassword(int[] password) - { - if (password.Length != 6) - return false; - return HasRepeating(password) && IsAssending(password); - } - - public static bool HasRepeating(int[] password) - { - for (int i = 0; i < password.Length - 1; i++) - { - if (password[i] == password[i + 1]) - return true; - } - return false; - } - - public static bool HasDoubles(int[] password) - { - bool foundDouble = false; - for (int i = 0; i < 6; i++) - { - int c = 0; - for (int j = 0; j < 6; j++) - { - if (password[j] == password[i]) - c++; - else - { - if (c != 0) - { - if (c == 2) - foundDouble = true; - c = 0; - } - } - } - if (c == 2) - foundDouble = true; - } - return foundDouble; - } - - public static bool IsAssending(int[] password) - { - for (int i = 1; i < 6; i++) - { - if (password[i] < password[i - 1]) - { - return false; - } - } - return true; - } - - public static int CountPasswordsPart1(int lower, int upper) - { - int passwordCount = 0; - int[] curPassword = lower.ToIntArray(); - CleanPassword(ref curPassword); - while (curPassword.ToInt() <= upper) - { - if (IsValidPassword(curPassword)) - { - passwordCount++; - } - curPassword[^1]++; - Propagate(ref curPassword, curPassword.Length - 1); - CleanPassword(ref curPassword); - } - return passwordCount; - } - - public static int CountPasswordsPart2(int lower, int upper) - { - int passwordCount = 0; - int[] curPassword = lower.ToIntArray(); - CleanPassword(ref curPassword); - while (curPassword.ToInt() <= upper) - { - if (HasDoubles(curPassword)) - { - passwordCount++; - } - curPassword[^1]++; - Propagate(ref curPassword, curPassword.Length - 1); - CleanPassword(ref curPassword); - } - return passwordCount; - } - - public static void CleanPassword(ref int[] password) - { - for (int i = 1; i < 6; i++) - { - if (password[i] < password[i - 1]) - { - password[i] += password[i - 1] - password[i]; - if (password[i] == 10) - { - Propagate(ref password, i); - password[i] = password[i - 1]; - } - } - } - } - - public static void Propagate(ref int[] password, int digit) - { - for (int i = digit; i >= 0; i--) - { - if (i == 0 && password[i] == 10) - { - password[i] = 9; - break; - } - - if (password[i] == 10) - { - password[i] = 0; - password[i - 1]++; - } - } - } - - public override void LoadInput() - { - } - - public override void CalculatePart1() - { - Part1 = CountPasswordsPart1(147981, 691423); - } - - public override void CalculatePart2() - { - Part2 = CountPasswordsPart2(147981, 691423); - } - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2019.Day4 +{ + [ProblemInfo(2019, 4, "Secure Container")] + public class SecureContainer : Problem + { + public static bool IsValidPassword(int[] password) + { + if (password.Length != 6) + return false; + return HasRepeating(password) && IsAssending(password); + } + + public static bool HasRepeating(int[] password) + { + for (int i = 0; i < password.Length - 1; i++) + { + if (password[i] == password[i + 1]) + return true; + } + return false; + } + + public static bool HasDoubles(int[] password) + { + bool foundDouble = false; + for (int i = 0; i < 6; i++) + { + int c = 0; + for (int j = 0; j < 6; j++) + { + if (password[j] == password[i]) + c++; + else + { + if (c != 0) + { + if (c == 2) + foundDouble = true; + c = 0; + } + } + } + if (c == 2) + foundDouble = true; + } + return foundDouble; + } + + public static bool IsAssending(int[] password) + { + for (int i = 1; i < 6; i++) + { + if (password[i] < password[i - 1]) + { + return false; + } + } + return true; + } + + public static int CountPasswordsPart1(int lower, int upper) + { + int passwordCount = 0; + int[] curPassword = lower.ToIntArray(); + CleanPassword(ref curPassword); + while (curPassword.ToInt() <= upper) + { + if (IsValidPassword(curPassword)) + { + passwordCount++; + } + curPassword[^1]++; + Propagate(ref curPassword, curPassword.Length - 1); + CleanPassword(ref curPassword); + } + return passwordCount; + } + + public static int CountPasswordsPart2(int lower, int upper) + { + int passwordCount = 0; + int[] curPassword = lower.ToIntArray(); + CleanPassword(ref curPassword); + while (curPassword.ToInt() <= upper) + { + if (HasDoubles(curPassword)) + { + passwordCount++; + } + curPassword[^1]++; + Propagate(ref curPassword, curPassword.Length - 1); + CleanPassword(ref curPassword); + } + return passwordCount; + } + + public static void CleanPassword(ref int[] password) + { + for (int i = 1; i < 6; i++) + { + if (password[i] < password[i - 1]) + { + password[i] += password[i - 1] - password[i]; + if (password[i] == 10) + { + Propagate(ref password, i); + password[i] = password[i - 1]; + } + } + } + } + + public static void Propagate(ref int[] password, int digit) + { + for (int i = digit; i >= 0; i--) + { + if (i == 0 && password[i] == 10) + { + password[i] = 9; + break; + } + + if (password[i] == 10) + { + password[i] = 0; + password[i - 1]++; + } + } + } + + public override void LoadInput() + { + } + + public override void CalculatePart1() + { + Part1 = CountPasswordsPart1(147981, 691423); + } + + public override void CalculatePart2() + { + Part2 = CountPasswordsPart2(147981, 691423); + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day5/ChanceOfAsteroids.cs b/AdventOfCode/Problems/AOC2019/Day5/ChanceOfAsteroids.cs index 2170772..90e4954 100644 --- a/AdventOfCode/Problems/AOC2019/Day5/ChanceOfAsteroids.cs +++ b/AdventOfCode/Problems/AOC2019/Day5/ChanceOfAsteroids.cs @@ -1,30 +1,30 @@ -using AdventOfCode.Day_5; -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2019.Day5; - -[ProblemInfo(2019, 5, "Sunny with a Chance of Asteroids")] -internal class ChanceOfAsteroids : Problem -{ - private IntCodeV2 _cpu = new IntCodeV2(); - private int[] _baseInput = Array.Empty(); - - public override void CalculatePart1() - { - var output = new int[1]; - _cpu.ExecuteCode(_baseInput, new int[] { 1 }, output); - Part1 = output[0]; - } - - public override void CalculatePart2() - { - var output = new int[1]; - _cpu.ExecuteCode(_baseInput, new int[] { 5 }, output); - Part2 = output[0]; - } - - public override void LoadInput() - { - _baseInput = InputParsing.ParseIntCsv(GetInputFile("input.csv")); - } +using AdventOfCode.Day_5; +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2019.Day5; + +[ProblemInfo(2019, 5, "Sunny with a Chance of Asteroids")] +internal class ChanceOfAsteroids : Problem +{ + private IntCodeV2 _cpu = new IntCodeV2(); + private int[] _baseInput = Array.Empty(); + + public override void CalculatePart1() + { + var output = new int[1]; + _cpu.ExecuteCode(_baseInput, new int[] { 1 }, output); + Part1 = output[0]; + } + + public override void CalculatePart2() + { + var output = new int[1]; + _cpu.ExecuteCode(_baseInput, new int[] { 5 }, output); + Part2 = output[0]; + } + + public override void LoadInput() + { + _baseInput = InputParsing.ParseIntCsv(GetInputFile("input.csv")); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day5/IntCodeV2.cs b/AdventOfCode/Problems/AOC2019/Day5/IntCodeV2.cs index bca3eda..9e19eb3 100644 --- a/AdventOfCode/Problems/AOC2019/Day5/IntCodeV2.cs +++ b/AdventOfCode/Problems/AOC2019/Day5/IntCodeV2.cs @@ -1,233 +1,233 @@ -namespace AdventOfCode.Day_5 -{ - public class IntCodeV2 - { - public struct Instruction - { - public int opcode; - public int paramCount; - public Func action; - - public Instruction(int opcode, int paramCount, Func action) - { - this.opcode = opcode; - this.paramCount = paramCount; - this.action = action; - } - } - - public bool IsHalted { get; private set; } - public bool IsRunning { get; private set; } - public bool PersistentMode { get; private set; } - public bool SuspendOnWrite { get; private set; } - - private Dictionary _instructions; - private int _instructionPointer; - private int[]? _inputBuffer; - private int _inputCounter = 0; - private int[]? _outputBuffer; - private int _outputCounter = 0; - private int[] memory = Array.Empty(); - - public IntCodeV2(bool persistentMode = false, bool suspendOnOutput = false) - { - _instructions = new Dictionary(); - PersistentMode = persistentMode; - SuspendOnWrite = suspendOnOutput; - IsHalted = false; - //Add - _instructions.Add(1, new Instruction(1, 3, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? p1 : mem[p1]; - var v2 = mode[1] == 1 ? p2 : mem[p2]; - var v3 = mode[0] == 1 ? mem[p3] : p3; - mem[v3] = v1 + v2; - - return true; - })); - //Multiply - _instructions.Add(2, new Instruction(2, 3, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? p1 : mem[p1]; - var v2 = mode[1] == 1 ? p2 : mem[p2]; - var v3 = mode[0] == 1 ? mem[p3] : p3; - mem[v3] = v1 * v2; - return true; - })); - //Halt - _instructions.Add(99, new Instruction(99, 0, (mem, mode, p1, p2, p3) => - { - IsHalted = true; - IsRunning = false; - return false; - })); - //Read Input - _instructions.Add(3, new Instruction(3, 1, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? mem[p1] : p1; - mem[v1] = ReadInput(); - //Console.WriteLine($"Input Read: {mem[v1]}"); - return true; - })); - //Write Output - _instructions.Add(4, new Instruction(4, 1, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? p1 : mem[p1]; - WriteOutput(v1); - if (SuspendOnWrite) - IsRunning = false; - return true; - })); - //Jump if True - _instructions.Add(5, new Instruction(5, 2, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? p1 : mem[p1]; - var v2 = mode[1] == 1 ? p2 : mem[p2]; - if (v1 != 0) - { - _instructionPointer = v2; - return false; - } - return true; - })); - //Jump if False - _instructions.Add(6, new Instruction(6, 2, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? p1 : mem[p1]; - var v2 = mode[1] == 1 ? p2 : mem[p2]; - if (v1 == 0) - { - _instructionPointer = v2; - return false; - } - return true; - })); - //Less than - _instructions.Add(7, new Instruction(7, 3, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? p1 : mem[p1]; - var v2 = mode[1] == 1 ? p2 : mem[p2]; - var v3 = mode[0] == 1 ? mem[p3] : p3; - if (v1 < v2) - mem[v3] = 1; - else - mem[v3] = 0; - return true; - })); - //Equals - _instructions.Add(8, new Instruction(8, 3, (mem, mode, p1, p2, p3) => - { - var v1 = mode[2] == 1 ? p1 : mem[p1]; - var v2 = mode[1] == 1 ? p2 : mem[p2]; - var v3 = mode[0] == 1 ? mem[p3] : p3; - if (v1 == v2) - mem[v3] = 1; - else - mem[v3] = 0; - return true; - })); - } - - private int ReadInput() - { - _inputCounter = Math.Min(_inputCounter, (_inputBuffer?.Length ?? 1) - 1); - if (_inputBuffer != null && _inputCounter < _inputBuffer.Length) - return _inputBuffer[_inputCounter++]; - else - { - Console.Write("Input: "); - return int.Parse(Console.ReadLine()!); - } - } - - private void WriteOutput(int output) - { - _outputCounter = Math.Min(_outputCounter, (_outputBuffer?.Length ?? 1) - 1); - if (_outputBuffer != null && _outputCounter < _outputBuffer.Length) - _outputBuffer[_outputCounter++] = output; - else - Console.WriteLine(output); - } - - public void ExecuteCode(int[] code, int[]? input = null, int[]? output = null) - { - LoadCode(code); - SetIO(input, output); - IsHalted = false; - Run(); - } - - public static (int[] opModes, int opcode) ParseInstruction(int instruction) - { - var opModes = new int[3]; - var arr = instruction.ToIntArray(); - switch (arr.Length) - { - case 1: - return (opModes, arr[0]); - - case 2: - return (opModes, (arr[^2] * 10) + arr[^1]); - } - var opcode = (arr[^2] * 10) + arr[^1]; - for (int i = 1; i <= 3; i++) - { - if (arr.Length < i + 2) - opModes[^i] = 0; - else - opModes[^i] = arr[^(i + 2)]; - } - - return (opModes, opcode); - } - - public void ResetIO() - { - _inputCounter = _outputCounter = 0; - } - - public void SetInputIndex(int index) - { - _inputCounter = index; - } - - public void SetIO(int[]? inputBuffer, int[]? outputBuffer) - { - ResetIO(); - _inputBuffer = inputBuffer ?? Array.Empty(); - _outputBuffer = outputBuffer ?? Array.Empty(); - } - - public void Run() - { - IsRunning = true; - while (IsRunning) - { - var (modes, opcode) = ParseInstruction(memory[_instructionPointer]); - var curInstruction = _instructions[opcode]; - int[] parameters = new int[3]; - for (int i = 0; i < 3; i++) - { - if (i >= curInstruction.paramCount) - parameters[i] = 0; - else - parameters[i] = memory[_instructionPointer + i + 1]; - } - - if (curInstruction.action(memory, modes, parameters[0], parameters[1], parameters[2])) - _instructionPointer += curInstruction.paramCount + 1; - - if (IsHalted) - IsRunning = false; - } - } - - public IntCodeV2 LoadCode(int[] code) - { - memory = new int[code.Length]; - code.CopyTo(memory, 0); - _instructionPointer = 0; - return this; - } - } +namespace AdventOfCode.Day_5 +{ + public class IntCodeV2 + { + public struct Instruction + { + public int opcode; + public int paramCount; + public Func action; + + public Instruction(int opcode, int paramCount, Func action) + { + this.opcode = opcode; + this.paramCount = paramCount; + this.action = action; + } + } + + public bool IsHalted { get; private set; } + public bool IsRunning { get; private set; } + public bool PersistentMode { get; private set; } + public bool SuspendOnWrite { get; private set; } + + private Dictionary _instructions; + private int _instructionPointer; + private int[]? _inputBuffer; + private int _inputCounter = 0; + private int[]? _outputBuffer; + private int _outputCounter = 0; + private int[] memory = Array.Empty(); + + public IntCodeV2(bool persistentMode = false, bool suspendOnOutput = false) + { + _instructions = new Dictionary(); + PersistentMode = persistentMode; + SuspendOnWrite = suspendOnOutput; + IsHalted = false; + //Add + _instructions.Add(1, new Instruction(1, 3, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? p1 : mem[p1]; + var v2 = mode[1] == 1 ? p2 : mem[p2]; + var v3 = mode[0] == 1 ? mem[p3] : p3; + mem[v3] = v1 + v2; + + return true; + })); + //Multiply + _instructions.Add(2, new Instruction(2, 3, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? p1 : mem[p1]; + var v2 = mode[1] == 1 ? p2 : mem[p2]; + var v3 = mode[0] == 1 ? mem[p3] : p3; + mem[v3] = v1 * v2; + return true; + })); + //Halt + _instructions.Add(99, new Instruction(99, 0, (mem, mode, p1, p2, p3) => + { + IsHalted = true; + IsRunning = false; + return false; + })); + //Read Input + _instructions.Add(3, new Instruction(3, 1, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? mem[p1] : p1; + mem[v1] = ReadInput(); + //Console.WriteLine($"Input Read: {mem[v1]}"); + return true; + })); + //Write Output + _instructions.Add(4, new Instruction(4, 1, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? p1 : mem[p1]; + WriteOutput(v1); + if (SuspendOnWrite) + IsRunning = false; + return true; + })); + //Jump if True + _instructions.Add(5, new Instruction(5, 2, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? p1 : mem[p1]; + var v2 = mode[1] == 1 ? p2 : mem[p2]; + if (v1 != 0) + { + _instructionPointer = v2; + return false; + } + return true; + })); + //Jump if False + _instructions.Add(6, new Instruction(6, 2, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? p1 : mem[p1]; + var v2 = mode[1] == 1 ? p2 : mem[p2]; + if (v1 == 0) + { + _instructionPointer = v2; + return false; + } + return true; + })); + //Less than + _instructions.Add(7, new Instruction(7, 3, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? p1 : mem[p1]; + var v2 = mode[1] == 1 ? p2 : mem[p2]; + var v3 = mode[0] == 1 ? mem[p3] : p3; + if (v1 < v2) + mem[v3] = 1; + else + mem[v3] = 0; + return true; + })); + //Equals + _instructions.Add(8, new Instruction(8, 3, (mem, mode, p1, p2, p3) => + { + var v1 = mode[2] == 1 ? p1 : mem[p1]; + var v2 = mode[1] == 1 ? p2 : mem[p2]; + var v3 = mode[0] == 1 ? mem[p3] : p3; + if (v1 == v2) + mem[v3] = 1; + else + mem[v3] = 0; + return true; + })); + } + + private int ReadInput() + { + _inputCounter = Math.Min(_inputCounter, (_inputBuffer?.Length ?? 1) - 1); + if (_inputBuffer != null && _inputCounter < _inputBuffer.Length) + return _inputBuffer[_inputCounter++]; + else + { + Console.Write("Input: "); + return int.Parse(Console.ReadLine()!); + } + } + + private void WriteOutput(int output) + { + _outputCounter = Math.Min(_outputCounter, (_outputBuffer?.Length ?? 1) - 1); + if (_outputBuffer != null && _outputCounter < _outputBuffer.Length) + _outputBuffer[_outputCounter++] = output; + else + Console.WriteLine(output); + } + + public void ExecuteCode(int[] code, int[]? input = null, int[]? output = null) + { + LoadCode(code); + SetIO(input, output); + IsHalted = false; + Run(); + } + + public static (int[] opModes, int opcode) ParseInstruction(int instruction) + { + var opModes = new int[3]; + var arr = instruction.ToIntArray(); + switch (arr.Length) + { + case 1: + return (opModes, arr[0]); + + case 2: + return (opModes, (arr[^2] * 10) + arr[^1]); + } + var opcode = (arr[^2] * 10) + arr[^1]; + for (int i = 1; i <= 3; i++) + { + if (arr.Length < i + 2) + opModes[^i] = 0; + else + opModes[^i] = arr[^(i + 2)]; + } + + return (opModes, opcode); + } + + public void ResetIO() + { + _inputCounter = _outputCounter = 0; + } + + public void SetInputIndex(int index) + { + _inputCounter = index; + } + + public void SetIO(int[]? inputBuffer, int[]? outputBuffer) + { + ResetIO(); + _inputBuffer = inputBuffer ?? Array.Empty(); + _outputBuffer = outputBuffer ?? Array.Empty(); + } + + public void Run() + { + IsRunning = true; + while (IsRunning) + { + var (modes, opcode) = ParseInstruction(memory[_instructionPointer]); + var curInstruction = _instructions[opcode]; + int[] parameters = new int[3]; + for (int i = 0; i < 3; i++) + { + if (i >= curInstruction.paramCount) + parameters[i] = 0; + else + parameters[i] = memory[_instructionPointer + i + 1]; + } + + if (curInstruction.action(memory, modes, parameters[0], parameters[1], parameters[2])) + _instructionPointer += curInstruction.paramCount + 1; + + if (IsHalted) + IsRunning = false; + } + } + + public IntCodeV2 LoadCode(int[] code) + { + memory = new int[code.Length]; + code.CopyTo(memory, 0); + _instructionPointer = 0; + return this; + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day6/OrbitMap.cs b/AdventOfCode/Problems/AOC2019/Day6/OrbitMap.cs index 62b6d56..c6dd112 100644 --- a/AdventOfCode/Problems/AOC2019/Day6/OrbitMap.cs +++ b/AdventOfCode/Problems/AOC2019/Day6/OrbitMap.cs @@ -1,119 +1,119 @@ -namespace AdventOfCode.Problems.AOC2019.Day6 -{ - public class OrbitMap - { - public CelestialObject root; - public Dictionary objectMap; - - public OrbitMap(string[] orbits) - { - objectMap = new Dictionary(); - GenerateOrbits(orbits); - } - - public void GenerateOrbits(string[] orbits) - { - for (int i = 0; i < orbits.Length; i++) - { - var bodies = orbits[i].Split(')'); - if (bodies[0] == "COM") - root = CreateObject("COM"); - - var parent = GetOrCreateObject(bodies[0]); - var child = GetOrCreateObject(bodies[1]); - - parent.AddChild(child); - } - } - - public CelestialObject GetOrCreateObject(string name) - { - if (objectMap.ContainsKey(name)) - return objectMap[name]; - else - return CreateObject(name); - } - - public CelestialObject CreateObject(string name) - { - var o = new CelestialObject(name); - objectMap.Add(name, o); - return o; - } - - public int CalculateOrbits() - { - return root.GetOrbitCount(); - } - - public List FindPathTo(string name) - { - var path = new List(); - root.FindPathTo(name, path); - return path; - } - - public int GetDepthOf(string name) => root.GetDepth(name); - - public class CelestialObject - { - public string Name { get; set; } - public int ChildCount => children.Count; - - public List children; - - public CelestialObject(string name) - { - children = new List(); - Name = name; - } - - public void AddChild(CelestialObject child) - { - children.Add(child); - } - - public int GetOrbitCount(int depth = 0) - { - var count = 0; - for (int i = 0; i < children.Count; i++) - { - count += children[i].GetOrbitCount(depth + 1); - } - return depth + count; - } - - public bool FindPathTo(string name, List path) - { - if (name == Name) - return true; - for (int i = 0; i < ChildCount; i++) - { - if (children[i].FindPathTo(name, path)) - { - path.Add(children[i]); - return true; - } - } - return false; - } - - public int GetDepth(string name, int depth = 0) - { - if (name == Name) - return depth; - var d = 0; - for (int i = 0; i < ChildCount; i++) - { - d += children[i].GetDepth(name, depth + 1); - } - return d; - } - - public override string ToString() - { - return Name; - } - } - } +namespace AdventOfCode.Problems.AOC2019.Day6 +{ + public class OrbitMap + { + public CelestialObject root; + public Dictionary objectMap; + + public OrbitMap(string[] orbits) + { + objectMap = new Dictionary(); + GenerateOrbits(orbits); + } + + public void GenerateOrbits(string[] orbits) + { + for (int i = 0; i < orbits.Length; i++) + { + var bodies = orbits[i].Split(')'); + if (bodies[0] == "COM") + root = CreateObject("COM"); + + var parent = GetOrCreateObject(bodies[0]); + var child = GetOrCreateObject(bodies[1]); + + parent.AddChild(child); + } + } + + public CelestialObject GetOrCreateObject(string name) + { + if (objectMap.ContainsKey(name)) + return objectMap[name]; + else + return CreateObject(name); + } + + public CelestialObject CreateObject(string name) + { + var o = new CelestialObject(name); + objectMap.Add(name, o); + return o; + } + + public int CalculateOrbits() + { + return root.GetOrbitCount(); + } + + public List FindPathTo(string name) + { + var path = new List(); + root.FindPathTo(name, path); + return path; + } + + public int GetDepthOf(string name) => root.GetDepth(name); + + public class CelestialObject + { + public string Name { get; set; } + public int ChildCount => children.Count; + + public List children; + + public CelestialObject(string name) + { + children = new List(); + Name = name; + } + + public void AddChild(CelestialObject child) + { + children.Add(child); + } + + public int GetOrbitCount(int depth = 0) + { + var count = 0; + for (int i = 0; i < children.Count; i++) + { + count += children[i].GetOrbitCount(depth + 1); + } + return depth + count; + } + + public bool FindPathTo(string name, List path) + { + if (name == Name) + return true; + for (int i = 0; i < ChildCount; i++) + { + if (children[i].FindPathTo(name, path)) + { + path.Add(children[i]); + return true; + } + } + return false; + } + + public int GetDepth(string name, int depth = 0) + { + if (name == Name) + return depth; + var d = 0; + for (int i = 0; i < ChildCount; i++) + { + d += children[i].GetDepth(name, depth + 1); + } + return d; + } + + public override string ToString() + { + return Name; + } + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day6/UniversalOrbits.cs b/AdventOfCode/Problems/AOC2019/Day6/UniversalOrbits.cs index 27b06b1..69837bb 100644 --- a/AdventOfCode/Problems/AOC2019/Day6/UniversalOrbits.cs +++ b/AdventOfCode/Problems/AOC2019/Day6/UniversalOrbits.cs @@ -1,53 +1,53 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2019.Day6; - -[ProblemInfo(2019, 6, "Universal Orbit Map")] -internal class UniversalOrbits : Problem -{ - private OrbitMap? _map; - - public override void CalculatePart1() - { - if (_map == null) - return; - Part1 = _map.CalculateOrbits(); - } - - public override void CalculatePart2() - { - if (_map == null) - return; - - var pathToYOU = _map.FindPathTo("YOU"); - var pathToSAN = _map.FindPathTo("SAN"); - string pivot = ""; - int dist = 0; - - HashSet pathYOU = new(pathToYOU.Select(o => o.Name)); - - for (int i = 0; i < pathToSAN.Count; i++) - { - if (pathYOU.Contains(pathToSAN[i].Name)) - { - pivot = pathToSAN[i].Name; - dist = i; - break; - } - } - for (int i = 0; i < pathToYOU.Count; i++) - { - if (pathToYOU[i].Name == pivot) - { - dist += i; - break; - } - } - Part2 = dist - 2; - } - - public override void LoadInput() - { - _map = new OrbitMap(ReadInputLines()); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2019.Day6; + +[ProblemInfo(2019, 6, "Universal Orbit Map")] +internal class UniversalOrbits : Problem +{ + private OrbitMap? _map; + + public override void CalculatePart1() + { + if (_map == null) + return; + Part1 = _map.CalculateOrbits(); + } + + public override void CalculatePart2() + { + if (_map == null) + return; + + var pathToYOU = _map.FindPathTo("YOU"); + var pathToSAN = _map.FindPathTo("SAN"); + string pivot = ""; + int dist = 0; + + HashSet pathYOU = new(pathToYOU.Select(o => o.Name)); + + for (int i = 0; i < pathToSAN.Count; i++) + { + if (pathYOU.Contains(pathToSAN[i].Name)) + { + pivot = pathToSAN[i].Name; + dist = i; + break; + } + } + for (int i = 0; i < pathToYOU.Count; i++) + { + if (pathToYOU[i].Name == pivot) + { + dist += i; + break; + } + } + Part2 = dist - 2; + } + + public override void LoadInput() + { + _map = new OrbitMap(ReadInputLines()); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day7/AmplificationCircuit.cs b/AdventOfCode/Problems/AOC2019/Day7/AmplificationCircuit.cs index 0ed64e3..ecc1fde 100644 --- a/AdventOfCode/Problems/AOC2019/Day7/AmplificationCircuit.cs +++ b/AdventOfCode/Problems/AOC2019/Day7/AmplificationCircuit.cs @@ -1,161 +1,161 @@ -using AdventOfCode.Day_5; -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2019.Day7 -{ - [ProblemInfo(2019, 7, "Amplification Circuit")] - public class AmplificationCircuit : Problem - { - private int[] _code = Array.Empty(); - - public static int RunPhase(IntCodeV2 cpu, int[] code, int[] phaseSettings) - { - if (HasDuplicateValues(phaseSettings)) - return int.MinValue; - int[] outputBuffer = { 0 }; - int[] inputBuffer; - //Amp A - inputBuffer = new int[] { phaseSettings[0], outputBuffer[0] }; - cpu.ExecuteCode(code, inputBuffer, outputBuffer); - //Amp B - inputBuffer = new int[] { phaseSettings[1], outputBuffer[0] }; - cpu.ExecuteCode(code, inputBuffer, outputBuffer); - //Amp C - inputBuffer = new int[] { phaseSettings[2], outputBuffer[0] }; - cpu.ExecuteCode(code, inputBuffer, outputBuffer); - //Amp D - inputBuffer = new int[] { phaseSettings[3], outputBuffer[0] }; - cpu.ExecuteCode(code, inputBuffer, outputBuffer); - //Amp E - inputBuffer = new int[] { phaseSettings[4], outputBuffer[0] }; - cpu.ExecuteCode(code, inputBuffer, outputBuffer); - return outputBuffer[0]; - } - - public static int RunFeedback(int[] code, int[] phaseSettings) - { - if (HasDuplicateValues(phaseSettings)) - return int.MinValue; - var ampA = new IntCodeV2(true, true).LoadCode(code); - var ampB = new IntCodeV2(true, true).LoadCode(code); - var ampC = new IntCodeV2(true, true).LoadCode(code); - var ampD = new IntCodeV2(true, true).LoadCode(code); - var ampE = new IntCodeV2(true, true).LoadCode(code); - var outputA = new int[] { 273 }; - var outputB = new int[] { 0 }; - var outputC = new int[] { 0 }; - var outputD = new int[] { 0 }; - var outputE = new int[] { 0 }; - var inputA = new int[] { phaseSettings[0], outputE[0] }; - var inputB = new int[] { phaseSettings[1], outputA[0] }; - var inputC = new int[] { phaseSettings[2], outputB[0] }; - var inputD = new int[] { phaseSettings[3], outputC[0] }; - var inputE = new int[] { phaseSettings[4], outputD[0] }; - ampA.SetIO(inputA, outputA); - ampB.SetIO(inputB, outputB); - ampC.SetIO(inputC, outputC); - ampD.SetIO(inputD, outputD); - ampE.SetIO(inputE, outputE); - int iter = 0; - while (!ampE.IsHalted) - { - //Console.WriteLine($"Iteration {iter}"); - inputA[1] = outputE[0]; - - ampA.Run(); - inputB[1] = outputA[0]; - ampB.Run(); - inputC[1] = outputB[0]; - ampC.Run(); - inputD[1] = outputC[0]; - ampD.Run(); - inputE[1] = outputD[0]; - ampE.Run(); - - //Console.WriteLine($"Output {outputE[0]}"); - iter++; - } - - return outputE[0]; - } - - public static bool HasDuplicateValues(int[] arr) - { - for (int i = 0; i < arr.Length; i++) - { - for (int j = 0; j < arr.Length; j++) - { - if (i == j) - continue; - if (arr[i] == arr[j]) - return true; - } - } - return false; - } - - public override void LoadInput() - { - _code = InputParsing.ParseIntCsv(GetInputFile("input.csv")); - } - - public override void CalculatePart1() - { - int output = int.MinValue; - int min = 0; - int max = 5; - var cpu = new IntCodeV2(); - - for (int i = min; i < max; i++) - { - for (int j = min; j < max; j++) - { - for (int k = min; k < max; k++) - { - for (int l = min; l < max; l++) - { - for (int m = min; m < max; m++) - { - var result = RunPhase(cpu, _code, new int[] { i, j, k, l, m }); - if (output < result) - { - output = result; - } - } - } - } - } - } - Part1 = output; - } - - public override void CalculatePart2() - { - int output = int.MinValue; - int min = 5; - int max = 10; - - for (int i = min; i < max; i++) - { - for (int j = min; j < max; j++) - { - for (int k = min; k < max; k++) - { - for (int l = min; l < max; l++) - { - for (int m = min; m < max; m++) - { - var result = RunFeedback(_code, new int[] { i, j, k, l, m }); - if (output < result) - { - output = result; - } - } - } - } - } - } - Part2 = output; - } - } +using AdventOfCode.Day_5; +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2019.Day7 +{ + [ProblemInfo(2019, 7, "Amplification Circuit")] + public class AmplificationCircuit : Problem + { + private int[] _code = Array.Empty(); + + public static int RunPhase(IntCodeV2 cpu, int[] code, int[] phaseSettings) + { + if (HasDuplicateValues(phaseSettings)) + return int.MinValue; + int[] outputBuffer = { 0 }; + int[] inputBuffer; + //Amp A + inputBuffer = new int[] { phaseSettings[0], outputBuffer[0] }; + cpu.ExecuteCode(code, inputBuffer, outputBuffer); + //Amp B + inputBuffer = new int[] { phaseSettings[1], outputBuffer[0] }; + cpu.ExecuteCode(code, inputBuffer, outputBuffer); + //Amp C + inputBuffer = new int[] { phaseSettings[2], outputBuffer[0] }; + cpu.ExecuteCode(code, inputBuffer, outputBuffer); + //Amp D + inputBuffer = new int[] { phaseSettings[3], outputBuffer[0] }; + cpu.ExecuteCode(code, inputBuffer, outputBuffer); + //Amp E + inputBuffer = new int[] { phaseSettings[4], outputBuffer[0] }; + cpu.ExecuteCode(code, inputBuffer, outputBuffer); + return outputBuffer[0]; + } + + public static int RunFeedback(int[] code, int[] phaseSettings) + { + if (HasDuplicateValues(phaseSettings)) + return int.MinValue; + var ampA = new IntCodeV2(true, true).LoadCode(code); + var ampB = new IntCodeV2(true, true).LoadCode(code); + var ampC = new IntCodeV2(true, true).LoadCode(code); + var ampD = new IntCodeV2(true, true).LoadCode(code); + var ampE = new IntCodeV2(true, true).LoadCode(code); + var outputA = new int[] { 273 }; + var outputB = new int[] { 0 }; + var outputC = new int[] { 0 }; + var outputD = new int[] { 0 }; + var outputE = new int[] { 0 }; + var inputA = new int[] { phaseSettings[0], outputE[0] }; + var inputB = new int[] { phaseSettings[1], outputA[0] }; + var inputC = new int[] { phaseSettings[2], outputB[0] }; + var inputD = new int[] { phaseSettings[3], outputC[0] }; + var inputE = new int[] { phaseSettings[4], outputD[0] }; + ampA.SetIO(inputA, outputA); + ampB.SetIO(inputB, outputB); + ampC.SetIO(inputC, outputC); + ampD.SetIO(inputD, outputD); + ampE.SetIO(inputE, outputE); + int iter = 0; + while (!ampE.IsHalted) + { + //Console.WriteLine($"Iteration {iter}"); + inputA[1] = outputE[0]; + + ampA.Run(); + inputB[1] = outputA[0]; + ampB.Run(); + inputC[1] = outputB[0]; + ampC.Run(); + inputD[1] = outputC[0]; + ampD.Run(); + inputE[1] = outputD[0]; + ampE.Run(); + + //Console.WriteLine($"Output {outputE[0]}"); + iter++; + } + + return outputE[0]; + } + + public static bool HasDuplicateValues(int[] arr) + { + for (int i = 0; i < arr.Length; i++) + { + for (int j = 0; j < arr.Length; j++) + { + if (i == j) + continue; + if (arr[i] == arr[j]) + return true; + } + } + return false; + } + + public override void LoadInput() + { + _code = InputParsing.ParseIntCsv(GetInputFile("input.csv")); + } + + public override void CalculatePart1() + { + int output = int.MinValue; + int min = 0; + int max = 5; + var cpu = new IntCodeV2(); + + for (int i = min; i < max; i++) + { + for (int j = min; j < max; j++) + { + for (int k = min; k < max; k++) + { + for (int l = min; l < max; l++) + { + for (int m = min; m < max; m++) + { + var result = RunPhase(cpu, _code, new int[] { i, j, k, l, m }); + if (output < result) + { + output = result; + } + } + } + } + } + } + Part1 = output; + } + + public override void CalculatePart2() + { + int output = int.MinValue; + int min = 5; + int max = 10; + + for (int i = min; i < max; i++) + { + for (int j = min; j < max; j++) + { + for (int k = min; k < max; k++) + { + for (int l = min; l < max; l++) + { + for (int m = min; m < max; m++) + { + var result = RunFeedback(_code, new int[] { i, j, k, l, m }); + if (output < result) + { + output = result; + } + } + } + } + } + } + Part2 = output; + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/Day8/SpaceImageFormat.cs b/AdventOfCode/Problems/AOC2019/Day8/SpaceImageFormat.cs index 5556273..b269f26 100644 --- a/AdventOfCode/Problems/AOC2019/Day8/SpaceImageFormat.cs +++ b/AdventOfCode/Problems/AOC2019/Day8/SpaceImageFormat.cs @@ -1,83 +1,83 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2019.Day8 -{ - [ProblemInfo(2019, 8, "Space Image Format")] - public class SpaceImageFormat : Problem - { - private int[] _imageData = Array.Empty(); - - public static void Execute() - { - var imageData = File.ReadAllText("Day8/input.txt").Replace("\n", "").Select(c => int.Parse(c.ToString())).ToArray(); - - Console.WriteLine(Checksum(imageData, 25, 6)); - } - - public static void RenderImage(int[] data, int h, int w) - { - var imgSize = h * w; - var layerCount = data.Length / imgSize; - - for (int l = 0; l < layerCount; l++) - { - } - } - - public static int Checksum(int[] data, int h, int w) - { - var imgSize = h * w; - var layerCount = data.Length / imgSize; - - int[] zeroCount = new int[layerCount]; - int[] oneCount = new int[layerCount]; - int[] twoCount = new int[layerCount]; - - int smallestLayer = -1; - int smallestLayerCount = int.MaxValue; - - for (int l = 0; l < layerCount; l++) - { - for (int i = imgSize * l; i < imgSize * (l + 1); i++) - { - switch (data[i]) - { - case 0: - zeroCount[l]++; - break; - - case 1: - oneCount[l]++; - break; - - case 2: - twoCount[l]++; - break; - } - } - if (zeroCount[l] <= smallestLayerCount) - { - smallestLayer = l; - smallestLayerCount = zeroCount[l]; - } - } - - return oneCount[smallestLayer] * twoCount[smallestLayer]; - } - - public override void LoadInput() - { - _imageData = ReadInputText().Replace("\n", "").Select(c => int.Parse(c.ToString())).ToArray(); - } - - public override void CalculatePart1() - { - Part1 = Checksum(_imageData, 25, 6); - } - - public override void CalculatePart2() - { - Part2 = null; - } - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2019.Day8 +{ + [ProblemInfo(2019, 8, "Space Image Format")] + public class SpaceImageFormat : Problem + { + private int[] _imageData = Array.Empty(); + + public static void Execute() + { + var imageData = File.ReadAllText("Day8/input.txt").Replace("\n", "").Select(c => int.Parse(c.ToString())).ToArray(); + + Console.WriteLine(Checksum(imageData, 25, 6)); + } + + public static void RenderImage(int[] data, int h, int w) + { + var imgSize = h * w; + var layerCount = data.Length / imgSize; + + for (int l = 0; l < layerCount; l++) + { + } + } + + public static int Checksum(int[] data, int h, int w) + { + var imgSize = h * w; + var layerCount = data.Length / imgSize; + + int[] zeroCount = new int[layerCount]; + int[] oneCount = new int[layerCount]; + int[] twoCount = new int[layerCount]; + + int smallestLayer = -1; + int smallestLayerCount = int.MaxValue; + + for (int l = 0; l < layerCount; l++) + { + for (int i = imgSize * l; i < imgSize * (l + 1); i++) + { + switch (data[i]) + { + case 0: + zeroCount[l]++; + break; + + case 1: + oneCount[l]++; + break; + + case 2: + twoCount[l]++; + break; + } + } + if (zeroCount[l] <= smallestLayerCount) + { + smallestLayer = l; + smallestLayerCount = zeroCount[l]; + } + } + + return oneCount[smallestLayer] * twoCount[smallestLayer]; + } + + public override void LoadInput() + { + _imageData = ReadInputText().Replace("\n", "").Select(c => int.Parse(c.ToString())).ToArray(); + } + + public override void CalculatePart1() + { + Part1 = Checksum(_imageData, 25, 6); + } + + public override void CalculatePart2() + { + Part2 = null; + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2019/InputParsing.cs b/AdventOfCode/Problems/AOC2019/InputParsing.cs index 251ce57..c63fd44 100644 --- a/AdventOfCode/Problems/AOC2019/InputParsing.cs +++ b/AdventOfCode/Problems/AOC2019/InputParsing.cs @@ -1,31 +1,31 @@ -namespace AdventOfCode -{ - public static class InputParsing - { - public static int[] ParseIntArray(string file) - { - return File.ReadAllLines(file).Select(s => int.Parse(s)).ToArray(); - } - - public static int[] ParseIntCsv(string file) - { - return File.ReadAllText(file).Split(',').Select(s => int.Parse(s)).ToArray(); - } - - public static int ToInt(this int[] intArr) - { - int value = 0; - for (int i = 0; i < intArr.Length; i++) - { - value += (int)Math.Pow(10, intArr.Length - i - 1) * intArr[i]; - } - return value; - } - - public static int[] ToIntArray(this int number) - { - int[] intArr = number.ToString().Select(d => int.Parse(d.ToString())).ToArray(); - return intArr; - } - } +namespace AdventOfCode +{ + public static class InputParsing + { + public static int[] ParseIntArray(string file) + { + return File.ReadAllLines(file).Select(s => int.Parse(s)).ToArray(); + } + + public static int[] ParseIntCsv(string file) + { + return File.ReadAllText(file).Split(',').Select(s => int.Parse(s)).ToArray(); + } + + public static int ToInt(this int[] intArr) + { + int value = 0; + for (int i = 0; i < intArr.Length; i++) + { + value += (int)Math.Pow(10, intArr.Length - i - 1) * intArr[i]; + } + return value; + } + + public static int[] ToIntArray(this int number) + { + int[] intArr = number.ToString().Select(d => int.Parse(d.ToString())).ToArray(); + return intArr; + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2021/Day11/DumboOctopus.cs b/AdventOfCode/Problems/AOC2021/Day11/DumboOctopus.cs index aeb3bc5..2960232 100644 --- a/AdventOfCode/Problems/AOC2021/Day11/DumboOctopus.cs +++ b/AdventOfCode/Problems/AOC2021/Day11/DumboOctopus.cs @@ -1,196 +1,196 @@ -using AdventOfCode.Runner.Attributes; - -using System.Collections; - -namespace AdventOfCode.Problems.AOC2021.Day11; - -[ProblemInfo(2021, 11, "Dumbo Octopus")] -public class DumboOctopus : Problem, IEnumerable -{ - public byte[] dataPart1 = Array.Empty(); - public byte[] dataPart2 = Array.Empty(); - - public override void LoadInput() - { - var data = ReadInputLines(); - dataPart1 = new byte[10 * 10]; - if (data.Length != 10) - throw new ArgumentException("Data must contain 10 elements", nameof(data)); - for (int y = 0; y < data.Length; y++) - { - var line = data[y]; - if (line.Length != 10) - throw new ArgumentException($"Lines must contain 10 elements. Line: {y + 1}", nameof(data)); - - for (int x = 0; x < line.Length; x++) - { - dataPart1[x + y * 10] = byte.Parse(line.Substring(x, 1)); - } - } - dataPart2 = new byte[10 * 10]; - Array.Copy(dataPart1, dataPart2, dataPart1.Length); - } - - public override void CalculatePart1() - { - Part1 = Run(ref dataPart1, 100, out _); - } - - public override void CalculatePart2() - { - Run(ref dataPart2, 210, out var fullFlash); - Part2 = fullFlash; - } - - public IEnumerator GetEnumerator() - { - return ((IEnumerable)dataPart1).GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return dataPart1.GetEnumerator(); - } - - public int Run(ref byte[] data, int count, out int fullFlash) - { - var flashes = 0; - fullFlash = 0; - for (int i = 0; i < count; i++) - { - var start = flashes; - Run(ref data, ref flashes); - if (flashes - start == 100) - { - fullFlash = i + 1; - break; - } - } - return flashes; - } - - public void Run(ref byte[] data, ref int flashes) - { - Increment(ref data); - Flash(ref data, ref flashes); - } - - private static void Increment(ref byte[] data) - { - for (int i = 0; i < data.Length; i++) - data[i]++; - } - - private void Flash(ref byte[] data, ref int flashes) - { - int diff; - do - { - var startFlash = flashes; - for (int i = 0; i < data.Length; i++) - { - if (data[i] > 9) - PerformFlash(ref data, i, ref flashes); - } - diff = flashes - startFlash; - } while (diff != 0); - } - - private void PerformFlash(ref byte[] data, int index, ref int flashes) - { - flashes++; - var y = index / 10; - var x = index % 10; - - data[index] = 0; - - if (x > 0) - { - //Left - index = x - 1 + y * 10; - if (index >= 0 && data[index] != 0) - data[index]++; - } - if (x < 9) - { - //Right - index = x + 1 + y * 10; - if (index < data.Length && data[index] != 0) - data[index]++; - } - if (y > 0) - { - //Up - index = x + 0 + (y - 1) * 10; - if (index >= 0 && data[index] != 0) - data[index]++; - if (x > 0) - { - //Up Left - index = x - 1 + (y - 1) * 10; - if (index >= 0 && data[index] != 0) - data[index]++; - } - if (x < 9) - { - //Up Right - index = x + 1 + (y - 1) * 10; - if (index < data.Length && data[index] != 0) - data[index]++; - } - } - - if (y < 9) - { - //Bottom - index = x + 0 + (y + 1) * 10; - if (index < data.Length && data[index] != 0) - data[index]++; - if (x > 0) - { - //Bottom Left - index = x - 1 + (y + 1) * 10; - if (index < data.Length && data[index] != 0) - data[index]++; - } - if (x < 9) - { - //Bottom Right - index = x + 1 + (y + 1) * 10; - if (index < data.Length && data[index] != 0) - data[index]++; - } - } - } - - //public override string ToString() - //{ - // var output = new StringBuilder(); - // for (int y = 0; y < 10; y++) - // { - // for (int x = 0; x < 10; x++) - // { - // output.Append(DataPart1[x + y * 10]); - // } - // output.AppendLine(); - // } - // return output.ToString(); - //} - - //public void Render() - //{ - // for (int y = 0; y < 10; y++) - // { - // for (int x = 0; x < 10; x++) - // { - // var index = x + y * 10; - // if (DataPart1[index] == 0) - // Console.ForegroundColor = ConsoleColor.Magenta; - // else - // Console.ForegroundColor = ConsoleColor.White; - // Console.Write(DataPart1[index]); - // } - // Console.WriteLine(); - // } - //} +using AdventOfCode.Runner.Attributes; + +using System.Collections; + +namespace AdventOfCode.Problems.AOC2021.Day11; + +[ProblemInfo(2021, 11, "Dumbo Octopus")] +public class DumboOctopus : Problem, IEnumerable +{ + public byte[] dataPart1 = Array.Empty(); + public byte[] dataPart2 = Array.Empty(); + + public override void LoadInput() + { + var data = ReadInputLines(); + dataPart1 = new byte[10 * 10]; + if (data.Length != 10) + throw new ArgumentException("Data must contain 10 elements", nameof(data)); + for (int y = 0; y < data.Length; y++) + { + var line = data[y]; + if (line.Length != 10) + throw new ArgumentException($"Lines must contain 10 elements. Line: {y + 1}", nameof(data)); + + for (int x = 0; x < line.Length; x++) + { + dataPart1[x + y * 10] = byte.Parse(line.Substring(x, 1)); + } + } + dataPart2 = new byte[10 * 10]; + Array.Copy(dataPart1, dataPart2, dataPart1.Length); + } + + public override void CalculatePart1() + { + Part1 = Run(ref dataPart1, 100, out _); + } + + public override void CalculatePart2() + { + Run(ref dataPart2, 210, out var fullFlash); + Part2 = fullFlash; + } + + public IEnumerator GetEnumerator() + { + return ((IEnumerable)dataPart1).GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return dataPart1.GetEnumerator(); + } + + public int Run(ref byte[] data, int count, out int fullFlash) + { + var flashes = 0; + fullFlash = 0; + for (int i = 0; i < count; i++) + { + var start = flashes; + Run(ref data, ref flashes); + if (flashes - start == 100) + { + fullFlash = i + 1; + break; + } + } + return flashes; + } + + public void Run(ref byte[] data, ref int flashes) + { + Increment(ref data); + Flash(ref data, ref flashes); + } + + private static void Increment(ref byte[] data) + { + for (int i = 0; i < data.Length; i++) + data[i]++; + } + + private void Flash(ref byte[] data, ref int flashes) + { + int diff; + do + { + var startFlash = flashes; + for (int i = 0; i < data.Length; i++) + { + if (data[i] > 9) + PerformFlash(ref data, i, ref flashes); + } + diff = flashes - startFlash; + } while (diff != 0); + } + + private void PerformFlash(ref byte[] data, int index, ref int flashes) + { + flashes++; + var y = index / 10; + var x = index % 10; + + data[index] = 0; + + if (x > 0) + { + //Left + index = x - 1 + y * 10; + if (index >= 0 && data[index] != 0) + data[index]++; + } + if (x < 9) + { + //Right + index = x + 1 + y * 10; + if (index < data.Length && data[index] != 0) + data[index]++; + } + if (y > 0) + { + //Up + index = x + 0 + (y - 1) * 10; + if (index >= 0 && data[index] != 0) + data[index]++; + if (x > 0) + { + //Up Left + index = x - 1 + (y - 1) * 10; + if (index >= 0 && data[index] != 0) + data[index]++; + } + if (x < 9) + { + //Up Right + index = x + 1 + (y - 1) * 10; + if (index < data.Length && data[index] != 0) + data[index]++; + } + } + + if (y < 9) + { + //Bottom + index = x + 0 + (y + 1) * 10; + if (index < data.Length && data[index] != 0) + data[index]++; + if (x > 0) + { + //Bottom Left + index = x - 1 + (y + 1) * 10; + if (index < data.Length && data[index] != 0) + data[index]++; + } + if (x < 9) + { + //Bottom Right + index = x + 1 + (y + 1) * 10; + if (index < data.Length && data[index] != 0) + data[index]++; + } + } + } + + //public override string ToString() + //{ + // var output = new StringBuilder(); + // for (int y = 0; y < 10; y++) + // { + // for (int x = 0; x < 10; x++) + // { + // output.Append(DataPart1[x + y * 10]); + // } + // output.AppendLine(); + // } + // return output.ToString(); + //} + + //public void Render() + //{ + // for (int y = 0; y < 10; y++) + // { + // for (int x = 0; x < 10; x++) + // { + // var index = x + y * 10; + // if (DataPart1[index] == 0) + // Console.ForegroundColor = ConsoleColor.Magenta; + // else + // Console.ForegroundColor = ConsoleColor.White; + // Console.Write(DataPart1[index]); + // } + // Console.WriteLine(); + // } + //} } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2021/Day3/BinaryDiagnostic.cs b/AdventOfCode/Problems/AOC2021/Day3/BinaryDiagnostic.cs index ec63e99..3004114 100644 --- a/AdventOfCode/Problems/AOC2021/Day3/BinaryDiagnostic.cs +++ b/AdventOfCode/Problems/AOC2021/Day3/BinaryDiagnostic.cs @@ -1,71 +1,71 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2021.Day3; - -[ProblemInfo(2021, 3, "Binary Diagnostic")] -public class BinaryDiagnostic : Problem -{ - public int[][] Data { get; set; } = Array.Empty(); - - private static int ToDecimal(int[] value) - { - return (int)value.Select((b, idx) => b * Math.Pow(2, value.Length - idx - 1)).Sum(); - } - - public override void LoadInput() - { - var data = ReadInputLines(); - Data = data.Select(line => line.Select(b => int.Parse(b.ToString())).ToArray()).ToArray(); - } - - public override void CalculatePart1() - { - var width = Data[0].Length; - var transposed = Enumerable.Range(0, width).Select(idx => Data.Select(row => row[idx])); - - var transposed2 = new int[width][]; - for (int i = 0; i < width; i++) - { - transposed2[i] = Data.Select(row => row[i]).ToArray(); - } - - var mid = Data.Length / 2; - var gamma = transposed.Select(col => col.Count(c => c == 1) > mid ? 1 : 0).ToArray(); - var epsilon = gamma.Select(b => b == 0 ? 1 : 0).ToArray(); - - var gammaDec = ToDecimal(gamma); - var epsilongDec = ToDecimal(epsilon); - - Part1 = gammaDec * epsilongDec; - } - - public override void CalculatePart2() - { - var oxygen = Data; - var index = 0; - while (oxygen.Length > 1) - { - var t = oxygen.Select(row => row[index]); - var m = oxygen.Length / 2f; - var g = t.Count(c => c == 1) >= m ? 1 : 0; - oxygen = oxygen.Where(row => row[index] == g).ToArray(); - index++; - } - - var carbon = Data; - index = 0; - while (carbon.Length > 1) - { - var t = carbon.Select(row => row[index]); - var m = carbon.Length / 2f; - var e = t.Count(c => c == 1) < m ? 1 : 0; - carbon = carbon.Where(row => row[index] == e).ToArray(); - index++; - } - - var oxygenLevel = ToDecimal(oxygen.First()); - var carbonLevel = ToDecimal(carbon.First()); - - Part2 = oxygenLevel * carbonLevel; - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2021.Day3; + +[ProblemInfo(2021, 3, "Binary Diagnostic")] +public class BinaryDiagnostic : Problem +{ + public int[][] Data { get; set; } = Array.Empty(); + + private static int ToDecimal(int[] value) + { + return (int)value.Select((b, idx) => b * Math.Pow(2, value.Length - idx - 1)).Sum(); + } + + public override void LoadInput() + { + var data = ReadInputLines(); + Data = data.Select(line => line.Select(b => int.Parse(b.ToString())).ToArray()).ToArray(); + } + + public override void CalculatePart1() + { + var width = Data[0].Length; + var transposed = Enumerable.Range(0, width).Select(idx => Data.Select(row => row[idx])); + + var transposed2 = new int[width][]; + for (int i = 0; i < width; i++) + { + transposed2[i] = Data.Select(row => row[i]).ToArray(); + } + + var mid = Data.Length / 2; + var gamma = transposed.Select(col => col.Count(c => c == 1) > mid ? 1 : 0).ToArray(); + var epsilon = gamma.Select(b => b == 0 ? 1 : 0).ToArray(); + + var gammaDec = ToDecimal(gamma); + var epsilongDec = ToDecimal(epsilon); + + Part1 = gammaDec * epsilongDec; + } + + public override void CalculatePart2() + { + var oxygen = Data; + var index = 0; + while (oxygen.Length > 1) + { + var t = oxygen.Select(row => row[index]); + var m = oxygen.Length / 2f; + var g = t.Count(c => c == 1) >= m ? 1 : 0; + oxygen = oxygen.Where(row => row[index] == g).ToArray(); + index++; + } + + var carbon = Data; + index = 0; + while (carbon.Length > 1) + { + var t = carbon.Select(row => row[index]); + var m = carbon.Length / 2f; + var e = t.Count(c => c == 1) < m ? 1 : 0; + carbon = carbon.Where(row => row[index] == e).ToArray(); + index++; + } + + var oxygenLevel = ToDecimal(oxygen.First()); + var carbonLevel = ToDecimal(carbon.First()); + + Part2 = oxygenLevel * carbonLevel; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2021/Day6/LanternFish.cs b/AdventOfCode/Problems/AOC2021/Day6/LanternFish.cs index e507ec2..5c374ab 100644 --- a/AdventOfCode/Problems/AOC2021/Day6/LanternFish.cs +++ b/AdventOfCode/Problems/AOC2021/Day6/LanternFish.cs @@ -1,50 +1,50 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2021.Day6; - -[ProblemInfo(2021, 6, "Lanternfish")] -internal class LanternFish : Problem -{ - public int[] Data { get; private set; } = Array.Empty(); - - public override void LoadInput() - { - var input = ReadInputLines(); - Data = input.First().Split(",").Select(v => int.Parse(v)).ToArray(); - } - - public override void CalculatePart1() - { - var lifetimes = PrepareLifetimes(); - Part1 = Simulate(lifetimes, 80); - } - - public override void CalculatePart2() - { - var lifetimes = PrepareLifetimes(); - Part2 = Simulate(lifetimes, 256); - } - - private long[] PrepareLifetimes() - { - var lifetimes = new long[9]; - foreach (var life in Data) - lifetimes[life] += 1; - - return lifetimes; - } - - private static long Simulate(long[] lifetimes, int days) - { - for (int i = 0; i < days; i++) - { - var day0Count = lifetimes[0]; - for (int j = 1; j < lifetimes.Length; j++) - lifetimes[j - 1] = lifetimes[j]; - lifetimes[6] += day0Count; - lifetimes[^1] = day0Count; - } - - return lifetimes.Sum(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2021.Day6; + +[ProblemInfo(2021, 6, "Lanternfish")] +internal class LanternFish : Problem +{ + public int[] Data { get; private set; } = Array.Empty(); + + public override void LoadInput() + { + var input = ReadInputLines(); + Data = input.First().Split(",").Select(v => int.Parse(v)).ToArray(); + } + + public override void CalculatePart1() + { + var lifetimes = PrepareLifetimes(); + Part1 = Simulate(lifetimes, 80); + } + + public override void CalculatePart2() + { + var lifetimes = PrepareLifetimes(); + Part2 = Simulate(lifetimes, 256); + } + + private long[] PrepareLifetimes() + { + var lifetimes = new long[9]; + foreach (var life in Data) + lifetimes[life] += 1; + + return lifetimes; + } + + private static long Simulate(long[] lifetimes, int days) + { + for (int i = 0; i < days; i++) + { + var day0Count = lifetimes[0]; + for (int j = 1; j < lifetimes.Length; j++) + lifetimes[j - 1] = lifetimes[j]; + lifetimes[6] += day0Count; + lifetimes[^1] = day0Count; + } + + return lifetimes.Sum(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day0/TestProblem.cs b/AdventOfCode/Problems/AOC2022/Day0/TestProblem.cs index ccb7e78..fa9798d 100644 --- a/AdventOfCode/Problems/AOC2022/Day0/TestProblem.cs +++ b/AdventOfCode/Problems/AOC2022/Day0/TestProblem.cs @@ -1,32 +1,32 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day0; - -[ProblemInfo(2022, 0, "Fancy Test")] -public class TestProblem : Problem -{ - public override void LoadInput() - { - Thread.Sleep(1000); - } - - public override void CalculatePart1() - { - Thread.Sleep(1000); - } - - public override void CalculatePart2() - { - Thread.Sleep(1000); - } - - public override void PrintPart1() - { - Console.WriteLine("Result"); - } - - public override void PrintPart2() - { - Console.WriteLine("Result 2"); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day0; + +[ProblemInfo(2022, 0, "Fancy Test")] +public class TestProblem : Problem +{ + public override void LoadInput() + { + Thread.Sleep(1000); + } + + public override void CalculatePart1() + { + Thread.Sleep(1000); + } + + public override void CalculatePart2() + { + Thread.Sleep(1000); + } + + public override void PrintPart1() + { + Console.WriteLine("Result"); + } + + public override void PrintPart2() + { + Console.WriteLine("Result 2"); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day1/CalorieCounting.cs b/AdventOfCode/Problems/AOC2022/Day1/CalorieCounting.cs index 11555c9..9398ca1 100644 --- a/AdventOfCode/Problems/AOC2022/Day1/CalorieCounting.cs +++ b/AdventOfCode/Problems/AOC2022/Day1/CalorieCounting.cs @@ -1,54 +1,54 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day1; - -[ProblemInfo(2022, 1, "Calorie Counting")] -internal class CalorieCounting : Problem -{ - public List> FlaresFood { get; set; } - - private (int calories, int elf)? _mostestElf; - private IEnumerable<(int sum, int idx)>? _mostestElves; - - public CalorieCounting() - { - FlaresFood = new List> - { - new List() - }; - } - - public override void LoadInput() - { - var lines = File.ReadAllLines(GetInputFile("input.txt")); - var c = 0; - foreach (var calorie in lines) - { - if (string.IsNullOrWhiteSpace(calorie)) - { - FlaresFood.Add(new List()); - c++; - continue; - } - FlaresFood[c].Add(int.Parse(calorie)); - } - } - - public override void CalculatePart1() - { - _mostestElf = FlaresFood - .Select((x, idx) => (sum: x.Sum(), idx)) - .MaxBy(x => x.sum); - - Part1 = _mostestElf.Value.ToString(); - } - - public override void CalculatePart2() - { - _mostestElves = FlaresFood - .Select((x, idx) => (sum: x.Sum(), idx)) - .OrderByDescending(e => e.sum) - .Take(3); - Part2 = _mostestElves.Sum(e => e.sum).ToString(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day1; + +[ProblemInfo(2022, 1, "Calorie Counting")] +internal class CalorieCounting : Problem +{ + public List> FlaresFood { get; set; } + + private (int calories, int elf)? _mostestElf; + private IEnumerable<(int sum, int idx)>? _mostestElves; + + public CalorieCounting() + { + FlaresFood = new List> + { + new List() + }; + } + + public override void LoadInput() + { + var lines = File.ReadAllLines(GetInputFile("input.txt")); + var c = 0; + foreach (var calorie in lines) + { + if (string.IsNullOrWhiteSpace(calorie)) + { + FlaresFood.Add(new List()); + c++; + continue; + } + FlaresFood[c].Add(int.Parse(calorie)); + } + } + + public override void CalculatePart1() + { + _mostestElf = FlaresFood + .Select((x, idx) => (sum: x.Sum(), idx)) + .MaxBy(x => x.sum); + + Part1 = _mostestElf.Value.ToString(); + } + + public override void CalculatePart2() + { + _mostestElves = FlaresFood + .Select((x, idx) => (sum: x.Sum(), idx)) + .OrderByDescending(e => e.sum) + .Take(3); + Part2 = _mostestElves.Sum(e => e.sum).ToString(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day10/CathodeCPU.cs b/AdventOfCode/Problems/AOC2022/Day10/CathodeCPU.cs index 677a55b..d721929 100644 --- a/AdventOfCode/Problems/AOC2022/Day10/CathodeCPU.cs +++ b/AdventOfCode/Problems/AOC2022/Day10/CathodeCPU.cs @@ -1,66 +1,66 @@ -namespace AdventOfCode.Problems.AOC2022.Day10; - -internal class CathodeCPU -{ - public enum Instruction - { - NoOp, - AddX - } - - public int X { get; private set; } = 1; - private int _cycleNumber = 1; - private int _programCounter; - private int _pending = -1; - - public int[] ExecuteCode((Instruction ins, int value)[] code, int[] outputCycles, Func? processor = null) - { - var result = new int[outputCycles.Length]; - - var ridx = 0; - - if (processor == null) - processor = (c, x) => c * x; - - ExecuteCode(code, (c, x) => - { - if (ridx < outputCycles.Length && c == outputCycles[ridx]) - { - result[ridx] = processor(c, x); - ridx++; - } - }); - - return result; - } - - public void ExecuteCode((Instruction ins, int value)[] code, Action processor) - { - while (_programCounter < code.Length) - { - var (ins, value) = code[_programCounter]; - - processor(_cycleNumber, X); - - switch ((ins, _pending)) - { - case { ins: Instruction.NoOp }: - _programCounter++; - break; - - case { ins: Instruction.AddX, _pending: -1 }: - _pending = 1; - break; - - case { ins: Instruction.AddX, _pending: 0 }: - X += value; - _programCounter++; - break; - } - - if (_pending >= 0) - _pending--; - _cycleNumber++; - } - } +namespace AdventOfCode.Problems.AOC2022.Day10; + +internal class CathodeCPU +{ + public enum Instruction + { + NoOp, + AddX + } + + public int X { get; private set; } = 1; + private int _cycleNumber = 1; + private int _programCounter; + private int _pending = -1; + + public int[] ExecuteCode((Instruction ins, int value)[] code, int[] outputCycles, Func? processor = null) + { + var result = new int[outputCycles.Length]; + + var ridx = 0; + + if (processor == null) + processor = (c, x) => c * x; + + ExecuteCode(code, (c, x) => + { + if (ridx < outputCycles.Length && c == outputCycles[ridx]) + { + result[ridx] = processor(c, x); + ridx++; + } + }); + + return result; + } + + public void ExecuteCode((Instruction ins, int value)[] code, Action processor) + { + while (_programCounter < code.Length) + { + var (ins, value) = code[_programCounter]; + + processor(_cycleNumber, X); + + switch ((ins, _pending)) + { + case { ins: Instruction.NoOp }: + _programCounter++; + break; + + case { ins: Instruction.AddX, _pending: -1 }: + _pending = 1; + break; + + case { ins: Instruction.AddX, _pending: 0 }: + X += value; + _programCounter++; + break; + } + + if (_pending >= 0) + _pending--; + _cycleNumber++; + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day10/CathodeRayTube.cs b/AdventOfCode/Problems/AOC2022/Day10/CathodeRayTube.cs index 1ce3416..2039115 100644 --- a/AdventOfCode/Problems/AOC2022/Day10/CathodeRayTube.cs +++ b/AdventOfCode/Problems/AOC2022/Day10/CathodeRayTube.cs @@ -1,55 +1,55 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day10; - -[ProblemInfo(2022, 10, "Cathode-Ray Tube")] -internal class CathodeRayTube : Problem -{ - private (CathodeCPU.Instruction ins, int value)[] _code = Array.Empty<(CathodeCPU.Instruction ins, int value)>(); - - public override void CalculatePart1() - { - var cpu = new CathodeCPU(); - var result = cpu.ExecuteCode(_code, new[] { 20, 60, 100, 140, 180, 220 }); - Part1 = result.Sum(); - } - - public override void CalculatePart2() - { - var output = Enumerable.Repeat(' ', 6 * 40).ToArray(); - - var cpu = new CathodeCPU(); - cpu.ExecuteCode(_code, (cycle, signal) => - { - cycle -= 1; - if (cycle > output.Length) - return; - - var pos = signal % 40; - var head = (cycle % 40); - var sprite = Math.Abs(pos - head); - if (sprite <= 1) - output[cycle] = '█'; - }); - - var lines = output.Chunk(40).Select(r => new string(r)); - Part2 = $"\n{string.Join("\n", lines)}"; - } - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - _code = new (CathodeCPU.Instruction ins, int value)[lines.Length]; - for (int i = 0; i < lines.Length; i++) - { - var ln = lines[i]; - if (ln == "noop") - _code[i] = (CathodeCPU.Instruction.NoOp, 0); - else - { - var instruction = ln.Split(' '); - _code[i] = (Enum.Parse(instruction[0], true), int.Parse(instruction[1])); - } - } - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day10; + +[ProblemInfo(2022, 10, "Cathode-Ray Tube")] +internal class CathodeRayTube : Problem +{ + private (CathodeCPU.Instruction ins, int value)[] _code = Array.Empty<(CathodeCPU.Instruction ins, int value)>(); + + public override void CalculatePart1() + { + var cpu = new CathodeCPU(); + var result = cpu.ExecuteCode(_code, new[] { 20, 60, 100, 140, 180, 220 }); + Part1 = result.Sum(); + } + + public override void CalculatePart2() + { + var output = Enumerable.Repeat(' ', 6 * 40).ToArray(); + + var cpu = new CathodeCPU(); + cpu.ExecuteCode(_code, (cycle, signal) => + { + cycle -= 1; + if (cycle > output.Length) + return; + + var pos = signal % 40; + var head = (cycle % 40); + var sprite = Math.Abs(pos - head); + if (sprite <= 1) + output[cycle] = '█'; + }); + + var lines = output.Chunk(40).Select(r => new string(r)); + Part2 = $"\n{string.Join("\n", lines)}"; + } + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + _code = new (CathodeCPU.Instruction ins, int value)[lines.Length]; + for (int i = 0; i < lines.Length; i++) + { + var ln = lines[i]; + if (ln == "noop") + _code[i] = (CathodeCPU.Instruction.NoOp, 0); + else + { + var instruction = ln.Split(' '); + _code[i] = (Enum.Parse(instruction[0], true), int.Parse(instruction[1])); + } + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day11/Monkey.cs b/AdventOfCode/Problems/AOC2022/Day11/Monkey.cs index e26b678..cb13ed5 100644 --- a/AdventOfCode/Problems/AOC2022/Day11/Monkey.cs +++ b/AdventOfCode/Problems/AOC2022/Day11/Monkey.cs @@ -1,73 +1,73 @@ -using System.Numerics; - -namespace AdventOfCode.Problems.AOC2022.Day11; - -internal class Monkey -{ - public int MonkeyNumber { get; set; } - public int InspectionCount { get; private set; } - public List Items { get; set; } - - private MonkeyOperator _operator; - private uint _operand; - private uint _divisor; - private int _trueTarget; - private int _falseTarget; - - public Monkey(string[] lines) - { - Items = new List(); - MonkeyNumber = int.Parse(lines[0].Split(' ')[^1][0..^1]); - Items = lines[1].Split(": ")[^1].Split(", ").Select(v => BigInteger.Parse(v)).ToList(); - var operation = lines[2].Split("= old ")[^1]; - _operator = operation[0] switch - { - '*' => MonkeyOperator.Multiply, - '+' => MonkeyOperator.Add, - _ => MonkeyOperator.Add - }; - if (!uint.TryParse(operation[1..], out _operand)) - _operator = MonkeyOperator.Power; - - _divisor = uint.Parse(lines[3].Split(' ')[^1]); - _trueTarget = int.Parse(lines[4].Split(' ')[^1]); - _falseTarget = int.Parse(lines[5].Split(' ')[^1]); - } - - public BigInteger Inspect(BigInteger value, uint worryOffset = 3) - { - InspectionCount++; - value = Operate(value); - if (worryOffset != 0) - value /= worryOffset; - return value; - } - - public int GetThrowTarget(BigInteger value) - { - return value % _divisor == 0 ? _trueTarget : _falseTarget; - } - - private BigInteger Operate(BigInteger value) - { - return _operator switch - { - MonkeyOperator.Multiply => value * _operand, - MonkeyOperator.Add => value + _operand, - MonkeyOperator.Power => value * value, - _ => value - }; - } - - private enum MonkeyOperator - { - Multiply, - Add, - Power - } - - public override string ToString() - { - return $"{MonkeyNumber}: ({InspectionCount}) [{string.Join(", ", Items)}]"; - } +using System.Numerics; + +namespace AdventOfCode.Problems.AOC2022.Day11; + +internal class Monkey +{ + public int MonkeyNumber { get; set; } + public int InspectionCount { get; private set; } + public List Items { get; set; } + + private MonkeyOperator _operator; + private uint _operand; + private uint _divisor; + private int _trueTarget; + private int _falseTarget; + + public Monkey(string[] lines) + { + Items = new List(); + MonkeyNumber = int.Parse(lines[0].Split(' ')[^1][0..^1]); + Items = lines[1].Split(": ")[^1].Split(", ").Select(v => BigInteger.Parse(v)).ToList(); + var operation = lines[2].Split("= old ")[^1]; + _operator = operation[0] switch + { + '*' => MonkeyOperator.Multiply, + '+' => MonkeyOperator.Add, + _ => MonkeyOperator.Add + }; + if (!uint.TryParse(operation[1..], out _operand)) + _operator = MonkeyOperator.Power; + + _divisor = uint.Parse(lines[3].Split(' ')[^1]); + _trueTarget = int.Parse(lines[4].Split(' ')[^1]); + _falseTarget = int.Parse(lines[5].Split(' ')[^1]); + } + + public BigInteger Inspect(BigInteger value, uint worryOffset = 3) + { + InspectionCount++; + value = Operate(value); + if (worryOffset != 0) + value /= worryOffset; + return value; + } + + public int GetThrowTarget(BigInteger value) + { + return value % _divisor == 0 ? _trueTarget : _falseTarget; + } + + private BigInteger Operate(BigInteger value) + { + return _operator switch + { + MonkeyOperator.Multiply => value * _operand, + MonkeyOperator.Add => value + _operand, + MonkeyOperator.Power => value * value, + _ => value + }; + } + + private enum MonkeyOperator + { + Multiply, + Add, + Power + } + + public override string ToString() + { + return $"{MonkeyNumber}: ({InspectionCount}) [{string.Join(", ", Items)}]"; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day11/MonkeyInTheMiddle.cs b/AdventOfCode/Problems/AOC2022/Day11/MonkeyInTheMiddle.cs index 20526c7..eb08f89 100644 --- a/AdventOfCode/Problems/AOC2022/Day11/MonkeyInTheMiddle.cs +++ b/AdventOfCode/Problems/AOC2022/Day11/MonkeyInTheMiddle.cs @@ -1,60 +1,60 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day11; - -[ProblemInfo(2022, 11, "Monkey in the Middle")] -internal class MonkeyInTheMiddle : Problem -{ - private Monkey[] _monkeysPart1 = Array.Empty(); - private Monkey[] _monkeysPart2 = Array.Empty(); - - public override void CalculatePart1() - { - Simulate(_monkeysPart1, 20); - Part1 = _monkeysPart1.OrderByDescending(m => m.InspectionCount) - .Take(2) - .Select(m => m.InspectionCount) - .Aggregate((a, b) => a * b); - } - - public override void CalculatePart2() - { - Simulate(_monkeysPart2, 10000, 0); - Part2 = _monkeysPart2.OrderByDescending(m => m.InspectionCount) - .Take(2) - .Select(m => m.InspectionCount) - .Aggregate((a, b) => a * b); - } - - public override void LoadInput() - { - var lines = ReadInputLines("test.txt").Chunk(7); - _monkeysPart1 = lines.Select(ln => new Monkey(ln)).ToArray(); - _monkeysPart2 = lines.Select(ln => new Monkey(ln)).ToArray(); - } - - private static void Simulate(Monkey[] monkeys, int rounds, uint worry = 3) - { - for (int i = 0; i < rounds; i++) - { - SimulateRound(monkeys, worry); - } - } - - private static void SimulateRound(Monkey[] monkeys, uint worry = 3) - { - foreach (var monkey in monkeys) - SimulateTurn(monkey, monkeys, worry); - } - - private static void SimulateTurn(Monkey monkey, Monkey[] monkeys, uint worry = 3) - { - for (int i = 0; i < monkey.Items.Count; i++) - { - var item = monkey.Inspect(monkey.Items[i], worry); - var target = monkey.GetThrowTarget(item); - monkeys[target].Items.Add(item); - } - monkey.Items.Clear(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day11; + +[ProblemInfo(2022, 11, "Monkey in the Middle")] +internal class MonkeyInTheMiddle : Problem +{ + private Monkey[] _monkeysPart1 = Array.Empty(); + private Monkey[] _monkeysPart2 = Array.Empty(); + + public override void CalculatePart1() + { + Simulate(_monkeysPart1, 20); + Part1 = _monkeysPart1.OrderByDescending(m => m.InspectionCount) + .Take(2) + .Select(m => m.InspectionCount) + .Aggregate((a, b) => a * b); + } + + public override void CalculatePart2() + { + Simulate(_monkeysPart2, 10000, 0); + Part2 = _monkeysPart2.OrderByDescending(m => m.InspectionCount) + .Take(2) + .Select(m => m.InspectionCount) + .Aggregate((a, b) => a * b); + } + + public override void LoadInput() + { + var lines = ReadInputLines("test.txt").Chunk(7); + _monkeysPart1 = lines.Select(ln => new Monkey(ln)).ToArray(); + _monkeysPart2 = lines.Select(ln => new Monkey(ln)).ToArray(); + } + + private static void Simulate(Monkey[] monkeys, int rounds, uint worry = 3) + { + for (int i = 0; i < rounds; i++) + { + SimulateRound(monkeys, worry); + } + } + + private static void SimulateRound(Monkey[] monkeys, uint worry = 3) + { + foreach (var monkey in monkeys) + SimulateTurn(monkey, monkeys, worry); + } + + private static void SimulateTurn(Monkey monkey, Monkey[] monkeys, uint worry = 3) + { + for (int i = 0; i < monkey.Items.Count; i++) + { + var item = monkey.Inspect(monkey.Items[i], worry); + var target = monkey.GetThrowTarget(item); + monkeys[target].Items.Add(item); + } + monkey.Items.Clear(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day12/HillClimbing.cs b/AdventOfCode/Problems/AOC2022/Day12/HillClimbing.cs index 4c0b0c2..90c6573 100644 --- a/AdventOfCode/Problems/AOC2022/Day12/HillClimbing.cs +++ b/AdventOfCode/Problems/AOC2022/Day12/HillClimbing.cs @@ -1,22 +1,22 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day12; - -[ProblemInfo(2022, 12, "Hill Climbing Algorithm")] -internal class HillClimbing : Problem -{ - public override void CalculatePart1() - { - throw new NotImplementedException(); - } - - public override void CalculatePart2() - { - throw new NotImplementedException(); - } - - public override void LoadInput() - { - throw new NotImplementedException(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day12; + +[ProblemInfo(2022, 12, "Hill Climbing Algorithm")] +internal class HillClimbing : Problem +{ + public override void CalculatePart1() + { + throw new NotImplementedException(); + } + + public override void CalculatePart2() + { + throw new NotImplementedException(); + } + + public override void LoadInput() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day13/DistressSignal.cs b/AdventOfCode/Problems/AOC2022/Day13/DistressSignal.cs index bba79ef..ba26680 100644 --- a/AdventOfCode/Problems/AOC2022/Day13/DistressSignal.cs +++ b/AdventOfCode/Problems/AOC2022/Day13/DistressSignal.cs @@ -1,22 +1,22 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day13; - -[ProblemInfo(2022, 13, "Distress Signal")] -internal class DistressSignal : Problem -{ - public override void CalculatePart1() - { - throw new NotImplementedException(); - } - - public override void CalculatePart2() - { - throw new NotImplementedException(); - } - - public override void LoadInput() - { - throw new NotImplementedException(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day13; + +[ProblemInfo(2022, 13, "Distress Signal")] +internal class DistressSignal : Problem +{ + public override void CalculatePart1() + { + throw new NotImplementedException(); + } + + public override void CalculatePart2() + { + throw new NotImplementedException(); + } + + public override void LoadInput() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day14/RegolithReservoir.cs b/AdventOfCode/Problems/AOC2022/Day14/RegolithReservoir.cs index 82dd291..8b837ca 100644 --- a/AdventOfCode/Problems/AOC2022/Day14/RegolithReservoir.cs +++ b/AdventOfCode/Problems/AOC2022/Day14/RegolithReservoir.cs @@ -1,22 +1,22 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day14; - -[ProblemInfo(2022, 14, "Regolith Reservoir")] -internal class RegolithReservoir : Problem -{ - public override void CalculatePart1() - { - throw new NotImplementedException(); - } - - public override void CalculatePart2() - { - throw new NotImplementedException(); - } - - public override void LoadInput() - { - throw new NotImplementedException(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day14; + +[ProblemInfo(2022, 14, "Regolith Reservoir")] +internal class RegolithReservoir : Problem +{ + public override void CalculatePart1() + { + throw new NotImplementedException(); + } + + public override void CalculatePart2() + { + throw new NotImplementedException(); + } + + public override void LoadInput() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day2/RockPaperScissors.cs b/AdventOfCode/Problems/AOC2022/Day2/RockPaperScissors.cs index 4029747..c5f535a 100644 --- a/AdventOfCode/Problems/AOC2022/Day2/RockPaperScissors.cs +++ b/AdventOfCode/Problems/AOC2022/Day2/RockPaperScissors.cs @@ -1,100 +1,100 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day2; - -[ProblemInfo(2022, 2, "Rock Paper Scissors")] -internal class RockPaperScissors : Problem -{ - private string[] _lines; - - public RockPaperScissors() - { - _lines = Array.Empty(); - } - - public override void LoadInput() - { - _lines = File.ReadAllLines(GetInputFile("input.txt")); - } - - public override void CalculatePart1() - { - var totalScore = 0; - foreach (var line in _lines) - { - var move = line[0]; - var response = line[^1]; - - totalScore += GetMoveValue(response); - totalScore += GetResult(move, response); - } - Part1 = totalScore.ToString(); - } - - private static int GetMoveValue(char move) - { - return move switch - { - 'A' => 1, - 'B' => 2, - 'C' => 3, - 'X' => 1, - 'Y' => 2, - 'Z' => 3, - _ => 0, - }; - } - - private static int GetResult(char move, char response) - { - return (move, response) switch - { - ('A', 'X') => 3, - ('B', 'X') => 0, - ('C', 'X') => 6, - ('A', 'Y') => 6, - ('B', 'Y') => 3, - ('C', 'Y') => 0, - ('A', 'Z') => 0, - ('B', 'Z') => 6, - ('C', 'Z') => 3, - _ => 0, - }; - } - - private static int GetResultValue(char result) - { - return result switch - { - 'X' => 0, - 'Y' => 3, - 'Z' => 6, - _ => 0, - }; - } - - private static int GetResponseValue(char move, char result) - { - var p = result switch - { - 'X' => (GetMoveValue(move) + 2) % 3, //Lose - 'Y' => GetMoveValue(move), //Tie - 'Z' => (GetMoveValue(move) + 1) % 3, //Win - _ => 0 - }; - return p == 0 ? 3 : p; - } - - public override void CalculatePart2() - { - var score = 0; - foreach (var line in _lines) - { - var move = line[0]; - var result = line[^1]; - score += GetResponseValue(move, result); - score += GetResultValue(result); - } - Part2 = score.ToString(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day2; + +[ProblemInfo(2022, 2, "Rock Paper Scissors")] +internal class RockPaperScissors : Problem +{ + private string[] _lines; + + public RockPaperScissors() + { + _lines = Array.Empty(); + } + + public override void LoadInput() + { + _lines = File.ReadAllLines(GetInputFile("input.txt")); + } + + public override void CalculatePart1() + { + var totalScore = 0; + foreach (var line in _lines) + { + var move = line[0]; + var response = line[^1]; + + totalScore += GetMoveValue(response); + totalScore += GetResult(move, response); + } + Part1 = totalScore.ToString(); + } + + private static int GetMoveValue(char move) + { + return move switch + { + 'A' => 1, + 'B' => 2, + 'C' => 3, + 'X' => 1, + 'Y' => 2, + 'Z' => 3, + _ => 0, + }; + } + + private static int GetResult(char move, char response) + { + return (move, response) switch + { + ('A', 'X') => 3, + ('B', 'X') => 0, + ('C', 'X') => 6, + ('A', 'Y') => 6, + ('B', 'Y') => 3, + ('C', 'Y') => 0, + ('A', 'Z') => 0, + ('B', 'Z') => 6, + ('C', 'Z') => 3, + _ => 0, + }; + } + + private static int GetResultValue(char result) + { + return result switch + { + 'X' => 0, + 'Y' => 3, + 'Z' => 6, + _ => 0, + }; + } + + private static int GetResponseValue(char move, char result) + { + var p = result switch + { + 'X' => (GetMoveValue(move) + 2) % 3, //Lose + 'Y' => GetMoveValue(move), //Tie + 'Z' => (GetMoveValue(move) + 1) % 3, //Win + _ => 0 + }; + return p == 0 ? 3 : p; + } + + public override void CalculatePart2() + { + var score = 0; + foreach (var line in _lines) + { + var move = line[0]; + var result = line[^1]; + score += GetResponseValue(move, result); + score += GetResultValue(result); + } + Part2 = score.ToString(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day3/RucksackReorganization.cs b/AdventOfCode/Problems/AOC2022/Day3/RucksackReorganization.cs index 821ac0a..33ad3c9 100644 --- a/AdventOfCode/Problems/AOC2022/Day3/RucksackReorganization.cs +++ b/AdventOfCode/Problems/AOC2022/Day3/RucksackReorganization.cs @@ -1,54 +1,54 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day3; - -[ProblemInfo(2022, 3, "Rucksack Reorganization")] -internal class RucksackReorganization : Problem -{ - private string[] _sacks; - - public RucksackReorganization() - { - _sacks = Array.Empty(); - } - - public override void LoadInput() - { - _sacks = ReadInputLines("input.txt"); - } - - public override void CalculatePart1() - { - var total = 0; - foreach (var sack in _sacks) - { - var mid = sack.Length / 2; - var left = sack[..mid]; - var right = sack[mid..]; - var common = right.First(itm => left.Contains(itm)); - total += GetValue(common); - } - Part1 = total.ToString(); - } - - public static int GetValue(char c) - { - return c switch - { - <= 'Z' => c - 'A' + 27, - _ => c - 'a' + 1 - }; - } - - public override void CalculatePart2() - { - var groups = _sacks.Chunk(3); - var total = 0; - foreach (var group in groups) - { - var badgeType = group[0].First(badge => group[1..].All(sack => sack.Contains(badge))); - total += GetValue(badgeType); - } - Part2 = total.ToString(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day3; + +[ProblemInfo(2022, 3, "Rucksack Reorganization")] +internal class RucksackReorganization : Problem +{ + private string[] _sacks; + + public RucksackReorganization() + { + _sacks = Array.Empty(); + } + + public override void LoadInput() + { + _sacks = ReadInputLines("input.txt"); + } + + public override void CalculatePart1() + { + var total = 0; + foreach (var sack in _sacks) + { + var mid = sack.Length / 2; + var left = sack[..mid]; + var right = sack[mid..]; + var common = right.First(itm => left.Contains(itm)); + total += GetValue(common); + } + Part1 = total.ToString(); + } + + public static int GetValue(char c) + { + return c switch + { + <= 'Z' => c - 'A' + 27, + _ => c - 'a' + 1 + }; + } + + public override void CalculatePart2() + { + var groups = _sacks.Chunk(3); + var total = 0; + foreach (var group in groups) + { + var badgeType = group[0].First(badge => group[1..].All(sack => sack.Contains(badge))); + total += GetValue(badgeType); + } + Part2 = total.ToString(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day4/CampCleanup.cs b/AdventOfCode/Problems/AOC2022/Day4/CampCleanup.cs index ce307c3..fdbd5cf 100644 --- a/AdventOfCode/Problems/AOC2022/Day4/CampCleanup.cs +++ b/AdventOfCode/Problems/AOC2022/Day4/CampCleanup.cs @@ -1,63 +1,63 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day4; - -[ProblemInfo(2022, 4, "Camp Cleanup")] -internal class CampCleanup : Problem -{ - private List<(Range a, Range b)> _pairs = new(500); - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - foreach (var line in lines) - { - var (a, b) = line.Split(',') - .Select(range => - range.Split('-') - .Select(v => int.Parse(v)) - .Chunk(2) - .Select(r => new Range(r.First(), r.Last())) - .First() - ).Chunk(2) - .Select(pair => (pair.First(), pair.Last())) - .First(); - _pairs.Add((a, b)); - } - } - - public override void CalculatePart1() - { - var total = 0; - foreach (var (a, b) in _pairs) - { - if (a.Contains(b) || b.Contains(a)) - total++; - } - Part1 = total; - } - - public override void CalculatePart2() - { - foreach (var (a, b) in _pairs) - { - if (a.OverlapsWith(b)) - Part2++; - } - } - - record Range(int A, int B) - { - public bool Contains(Range other) - { - return (A <= other.A && B >= other.B); - } - - public bool OverlapsWith(Range other) - { - return (B >= other.A && A <= other.A) || (A <= other.B && B >= other.B) || (A >= other.A && B <= other.B); - } - - public static implicit operator Range((int a, int b) value) => new(value.a, value.b); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day4; + +[ProblemInfo(2022, 4, "Camp Cleanup")] +internal class CampCleanup : Problem +{ + private List<(Range a, Range b)> _pairs = new(500); + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + foreach (var line in lines) + { + var (a, b) = line.Split(',') + .Select(range => + range.Split('-') + .Select(v => int.Parse(v)) + .Chunk(2) + .Select(r => new Range(r.First(), r.Last())) + .First() + ).Chunk(2) + .Select(pair => (pair.First(), pair.Last())) + .First(); + _pairs.Add((a, b)); + } + } + + public override void CalculatePart1() + { + var total = 0; + foreach (var (a, b) in _pairs) + { + if (a.Contains(b) || b.Contains(a)) + total++; + } + Part1 = total; + } + + public override void CalculatePart2() + { + foreach (var (a, b) in _pairs) + { + if (a.OverlapsWith(b)) + Part2++; + } + } + + record Range(int A, int B) + { + public bool Contains(Range other) + { + return (A <= other.A && B >= other.B); + } + + public bool OverlapsWith(Range other) + { + return (B >= other.A && A <= other.A) || (A <= other.B && B >= other.B) || (A >= other.A && B <= other.B); + } + + public static implicit operator Range((int a, int b) value) => new(value.a, value.b); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day5/SupplyStacks.cs b/AdventOfCode/Problems/AOC2022/Day5/SupplyStacks.cs index f09d45f..66885c2 100644 --- a/AdventOfCode/Problems/AOC2022/Day5/SupplyStacks.cs +++ b/AdventOfCode/Problems/AOC2022/Day5/SupplyStacks.cs @@ -1,131 +1,131 @@ -using AdventOfCode.Runner.Attributes; - -using Superpower; -using Superpower.Parsers; - -using System.Text.RegularExpressions; - -namespace AdventOfCode.Problems.AOC2022.Day5; - -[ProblemInfo(2022, 5, "Supply Stacks")] -internal partial class SupplyStacks : Problem -{ - private List[] _stacksPart1 = Array.Empty>(); - private List[] _stacksPart2 = Array.Empty>(); - - private readonly TextParser<(int, int, int)> _moveParser = from move in Character.Letter.Or(Character.WhiteSpace).Many() - from stack in Character.Digit.Many() - from frm in Character.Letter.Or(Character.WhiteSpace).Many() - from source in Character.Digit.Many() - from to in Character.Letter.Or(Character.WhiteSpace).Many() - from dst in Character.Digit.Many() - select (int.Parse(stack), int.Parse(source), int.Parse(dst)); - - private List<(int stack, int from, int to)> _moves = new(); - - public override void CalculatePart1() - { - foreach (var move in _moves) - { - PerformBasicMove(_stacksPart1, move); - } - Part1 = new string(_stacksPart1.Select(b => b.Last()).ToArray()); - } - - private static void PerformBasicMove(List[] data, (int stack, int from, int to) move) - { - var from = data[move.from - 1]; - var to = data[move.to - 1]; - for (int i = 0; i < move.stack; i++) - { - var item = from[^1]; - from.RemoveAt(from.Count - 1); - to.Add(item); - } - } - - private static void PerformMove(List[] data, (int stack, int from, int to) move) - { - var from = data[move.from - 1]; - var to = data[move.to - 1]; - var items = from.Skip(from.Count - move.stack); - to.AddRange(items); - from.RemoveRange(from.Count - move.stack, move.stack); - } - - public override void CalculatePart2() - { - foreach (var move in _moves) - { - PerformMove(_stacksPart2, move); - } - Part2 = new string(_stacksPart2.Select(b => b.Last()).ToArray()); - } - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - var readMoves = false; - - var buffers = new List>(); - var moves = new List<(int stack, int from, int to)>(); - foreach (var line in lines) - { - if (string.IsNullOrWhiteSpace(line)) - { - readMoves = true; - continue; - } - - if (readMoves) - { - moves.Add(ParseMoveLineRegex(line)); - } - else - { - var crates = ParseCrateLine(line); - for (int i = 0; i < crates.Count; i++) - { - var crate = crates[i]; - if (buffers.Count == i) - buffers.Add(crate == ' ' ? new() : new List() { crate }); - else if (crate != ' ') - buffers[i].Add(crate); - } - } - } - _stacksPart1 = buffers.Select(b => b.Take(b.Count - 1).Reverse().ToList()).ToArray(); - _stacksPart2 = buffers.Select(b => b.Take(b.Count - 1).Reverse().ToList()).ToArray(); - _moves = moves; - } - - //Way slower - private (int stack, int from, int to) ParseMoveLine(string line) - { - return _moveParser.Parse(line); - } - - private static (int stack, int from, int to) ParseMoveLineRegex(string line) - { - var r = MoveParser().Matches(line); - var items = r.First() - .Groups.Values.Skip(1) - .Select(v => int.Parse(v.ValueSpan)) - .ToArray(); - return (items[0], items[1], items[2]); - } - - private static List ParseCrateLine(string line) - { - var result = new List(line.Length / 4); - for (int i = 1; i < line.Length; i += 4) - { - var c = line[i]; - result.Add(c); - } - return result; - } - - [GeneratedRegex("move (\\d+) from (\\d+) to (\\d+)")] - private static partial Regex MoveParser(); +using AdventOfCode.Runner.Attributes; + +using Superpower; +using Superpower.Parsers; + +using System.Text.RegularExpressions; + +namespace AdventOfCode.Problems.AOC2022.Day5; + +[ProblemInfo(2022, 5, "Supply Stacks")] +internal partial class SupplyStacks : Problem +{ + private List[] _stacksPart1 = Array.Empty>(); + private List[] _stacksPart2 = Array.Empty>(); + + private readonly TextParser<(int, int, int)> _moveParser = from move in Character.Letter.Or(Character.WhiteSpace).Many() + from stack in Character.Digit.Many() + from frm in Character.Letter.Or(Character.WhiteSpace).Many() + from source in Character.Digit.Many() + from to in Character.Letter.Or(Character.WhiteSpace).Many() + from dst in Character.Digit.Many() + select (int.Parse(stack), int.Parse(source), int.Parse(dst)); + + private List<(int stack, int from, int to)> _moves = new(); + + public override void CalculatePart1() + { + foreach (var move in _moves) + { + PerformBasicMove(_stacksPart1, move); + } + Part1 = new string(_stacksPart1.Select(b => b.Last()).ToArray()); + } + + private static void PerformBasicMove(List[] data, (int stack, int from, int to) move) + { + var from = data[move.from - 1]; + var to = data[move.to - 1]; + for (int i = 0; i < move.stack; i++) + { + var item = from[^1]; + from.RemoveAt(from.Count - 1); + to.Add(item); + } + } + + private static void PerformMove(List[] data, (int stack, int from, int to) move) + { + var from = data[move.from - 1]; + var to = data[move.to - 1]; + var items = from.Skip(from.Count - move.stack); + to.AddRange(items); + from.RemoveRange(from.Count - move.stack, move.stack); + } + + public override void CalculatePart2() + { + foreach (var move in _moves) + { + PerformMove(_stacksPart2, move); + } + Part2 = new string(_stacksPart2.Select(b => b.Last()).ToArray()); + } + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + var readMoves = false; + + var buffers = new List>(); + var moves = new List<(int stack, int from, int to)>(); + foreach (var line in lines) + { + if (string.IsNullOrWhiteSpace(line)) + { + readMoves = true; + continue; + } + + if (readMoves) + { + moves.Add(ParseMoveLineRegex(line)); + } + else + { + var crates = ParseCrateLine(line); + for (int i = 0; i < crates.Count; i++) + { + var crate = crates[i]; + if (buffers.Count == i) + buffers.Add(crate == ' ' ? new() : new List() { crate }); + else if (crate != ' ') + buffers[i].Add(crate); + } + } + } + _stacksPart1 = buffers.Select(b => b.Take(b.Count - 1).Reverse().ToList()).ToArray(); + _stacksPart2 = buffers.Select(b => b.Take(b.Count - 1).Reverse().ToList()).ToArray(); + _moves = moves; + } + + //Way slower + private (int stack, int from, int to) ParseMoveLine(string line) + { + return _moveParser.Parse(line); + } + + private static (int stack, int from, int to) ParseMoveLineRegex(string line) + { + var r = MoveParser().Matches(line); + var items = r.First() + .Groups.Values.Skip(1) + .Select(v => int.Parse(v.ValueSpan)) + .ToArray(); + return (items[0], items[1], items[2]); + } + + private static List ParseCrateLine(string line) + { + var result = new List(line.Length / 4); + for (int i = 1; i < line.Length; i += 4) + { + var c = line[i]; + result.Add(c); + } + return result; + } + + [GeneratedRegex("move (\\d+) from (\\d+) to (\\d+)")] + private static partial Regex MoveParser(); } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day6/TuningTrouble.cs b/AdventOfCode/Problems/AOC2022/Day6/TuningTrouble.cs index ab1be03..343a7dc 100644 --- a/AdventOfCode/Problems/AOC2022/Day6/TuningTrouble.cs +++ b/AdventOfCode/Problems/AOC2022/Day6/TuningTrouble.cs @@ -1,35 +1,35 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day6; - -[ProblemInfo(2022, 6, "Tuning Trouble")] -internal class TuningTrouble : Problem -{ - private string _input = string.Empty; - - public override void CalculatePart1() - { - Part1 = FindMarker(4); - } - - private int FindMarker(int size = 4) - { - for (int i = size; i < _input.Length; i++) - { - var group = _input[(i - size)..i]; - if (group.All(c => group.Count(gc => gc == c) == 1)) - return i; - } - return -1; - } - - public override void CalculatePart2() - { - Part2 = FindMarker(14); - } - - public override void LoadInput() - { - _input = ReadInputText(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day6; + +[ProblemInfo(2022, 6, "Tuning Trouble")] +internal class TuningTrouble : Problem +{ + private string _input = string.Empty; + + public override void CalculatePart1() + { + Part1 = FindMarker(4); + } + + private int FindMarker(int size = 4) + { + for (int i = size; i < _input.Length; i++) + { + var group = _input[(i - size)..i]; + if (group.All(c => group.Count(gc => gc == c) == 1)) + return i; + } + return -1; + } + + public override void CalculatePart2() + { + Part2 = FindMarker(14); + } + + public override void LoadInput() + { + _input = ReadInputText(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day7/DirectoryNode.cs b/AdventOfCode/Problems/AOC2022/Day7/DirectoryNode.cs index cf2586c..dce8d50 100644 --- a/AdventOfCode/Problems/AOC2022/Day7/DirectoryNode.cs +++ b/AdventOfCode/Problems/AOC2022/Day7/DirectoryNode.cs @@ -1,121 +1,121 @@ -namespace AdventOfCode.Problems.AOC2022.Day7; - -internal class DirectoryNode -{ - public DirectoryNode Parent { get; set; } - public string Name { get; set; } - public string FullPath => GetFullPath(); - public List Children { get; set; } - public List<(string name, int size)> Files { get; set; } - public int Size => Files.Sum(f => f.size) + Children.Sum(c => c.Size); - public int LocalSize => Files.Sum(f => f.size); - - public DirectoryNode(string name) - { - Name = name; - Files = new(); - Children = new(); - Parent = this; - } - - public DirectoryNode(string name, DirectoryNode parent) - { - Name = name; - Files = new(); - Children = new(); - Parent = parent; - } - - public DirectoryNode(string name, List<(string name, int size)> files) - { - Name = name; - Files = files; - Children = new(); - Parent = this; - } - - public DirectoryNode AddDirectory(string path) - { - if (path == "/") - return this; - if (string.IsNullOrWhiteSpace(path)) - return this; - var segments = path.Split("/").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray(); - if (segments.Length == 0) - throw new Exception("Invalid Path?"); - return AddDirectory(segments); - } - - private DirectoryNode AddDirectory(string[] segments) - { - var curSegment = segments[0]; - var child = Children.FirstOrDefault(c => c.Name == curSegment); - if (child == null) - { - var node = new DirectoryNode(curSegment, this); - Children.Add(node); - if (segments.Length == 1) - return node; - else - return node.AddDirectory(segments[1..]); - } - else - { - if (segments.Length == 1) - return child; - return child.AddDirectory(segments[1..]); - } - } - - public void AddFile(string name, int size) - { - Files.Add((name, size)); - } - - public DirectoryNode? GetDirectory(string path) - { - if (path == "/") - return this; - var segments = path.Split("/").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray(); - if (segments.Length == 0) - throw new Exception("Invalid Path?"); - return GetDirectory(segments); - } - - private DirectoryNode? GetDirectory(string[] segments) - { - if (Children.Count == 0) - return null; - - var child = Children.FirstOrDefault(c => c.Name == segments[0]); - - if (child == null) - return null; - else - if (segments.Length == 1) - return child; - else - return child.GetDirectory(segments[1..]); - } - - public List Where(Func filter) - { - var result = new List(); - if (filter(this)) - result.Add(this); - result.AddRange(Children.SelectMany(c => c.Where(filter))); - return result; - } - - public string GetFullPath() - { - if (Parent == this) - return ""; - return $"{Parent.GetFullPath()}/{Name}"; - } - - public override string ToString() - { - return $"{Name} - {Children.Count}"; - } +namespace AdventOfCode.Problems.AOC2022.Day7; + +internal class DirectoryNode +{ + public DirectoryNode Parent { get; set; } + public string Name { get; set; } + public string FullPath => GetFullPath(); + public List Children { get; set; } + public List<(string name, int size)> Files { get; set; } + public int Size => Files.Sum(f => f.size) + Children.Sum(c => c.Size); + public int LocalSize => Files.Sum(f => f.size); + + public DirectoryNode(string name) + { + Name = name; + Files = new(); + Children = new(); + Parent = this; + } + + public DirectoryNode(string name, DirectoryNode parent) + { + Name = name; + Files = new(); + Children = new(); + Parent = parent; + } + + public DirectoryNode(string name, List<(string name, int size)> files) + { + Name = name; + Files = files; + Children = new(); + Parent = this; + } + + public DirectoryNode AddDirectory(string path) + { + if (path == "/") + return this; + if (string.IsNullOrWhiteSpace(path)) + return this; + var segments = path.Split("/").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray(); + if (segments.Length == 0) + throw new Exception("Invalid Path?"); + return AddDirectory(segments); + } + + private DirectoryNode AddDirectory(string[] segments) + { + var curSegment = segments[0]; + var child = Children.FirstOrDefault(c => c.Name == curSegment); + if (child == null) + { + var node = new DirectoryNode(curSegment, this); + Children.Add(node); + if (segments.Length == 1) + return node; + else + return node.AddDirectory(segments[1..]); + } + else + { + if (segments.Length == 1) + return child; + return child.AddDirectory(segments[1..]); + } + } + + public void AddFile(string name, int size) + { + Files.Add((name, size)); + } + + public DirectoryNode? GetDirectory(string path) + { + if (path == "/") + return this; + var segments = path.Split("/").Where(s => !string.IsNullOrWhiteSpace(s)).ToArray(); + if (segments.Length == 0) + throw new Exception("Invalid Path?"); + return GetDirectory(segments); + } + + private DirectoryNode? GetDirectory(string[] segments) + { + if (Children.Count == 0) + return null; + + var child = Children.FirstOrDefault(c => c.Name == segments[0]); + + if (child == null) + return null; + else + if (segments.Length == 1) + return child; + else + return child.GetDirectory(segments[1..]); + } + + public List Where(Func filter) + { + var result = new List(); + if (filter(this)) + result.Add(this); + result.AddRange(Children.SelectMany(c => c.Where(filter))); + return result; + } + + public string GetFullPath() + { + if (Parent == this) + return ""; + return $"{Parent.GetFullPath()}/{Name}"; + } + + public override string ToString() + { + return $"{Name} - {Children.Count}"; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day7/NoSpace.cs b/AdventOfCode/Problems/AOC2022/Day7/NoSpace.cs index 08a217d..3c8f3fc 100644 --- a/AdventOfCode/Problems/AOC2022/Day7/NoSpace.cs +++ b/AdventOfCode/Problems/AOC2022/Day7/NoSpace.cs @@ -1,75 +1,75 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day7; - -[ProblemInfo(2022, 7, "No Space Left On Device")] -internal class NoSpace : Problem -{ - private DirectoryNode _dirTree = new DirectoryNode("/"); - - public override void CalculatePart1() - { - var dirs = _dirTree.Where(d => d.Size <= 100000); - Part1 = dirs.Sum(d => d.Size); - } - - public override void CalculatePart2() - { - var neededPace = 30000000; - var totalSize = 70000000; - var unusedSpace = totalSize - _dirTree.Size; - var targetSize = neededPace - unusedSpace; - var bigEnough = _dirTree.Where(d => d.Size >= targetSize); - Part2 = bigEnough.MinBy(d => d.Size)?.Size ?? 0; - } - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - - var curDir = new Stack(); - - var dir = "/"; - foreach (var line in lines) - { - if (line[0] == '$') - { - ParseCommand(line[2..], ref curDir); - dir = $"/{string.Join("/", curDir.Reverse())}"; - _dirTree.AddDirectory(dir); - } - else - ReadDirectory(line, _dirTree.GetDirectory(dir)!); - } - } - - private static void ReadDirectory(string line, DirectoryNode curDir) - { - if (line.StartsWith("dir")) - return; - - var split = line.Split(' '); - var name = split[1]; - var size = int.Parse(split[0]); - curDir.AddFile(name, size); - } - - private static void ParseCommand(string command, ref Stack curDir) - { - var split = command.Split(' '); - var keyword = split.First(); - var param = split.Last(); - - switch (keyword) - { - case "cd": - if (param == "..") - curDir.Pop(); - else if (param == "/") - curDir.Clear(); - else - curDir.Push(param); - break; - } - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day7; + +[ProblemInfo(2022, 7, "No Space Left On Device")] +internal class NoSpace : Problem +{ + private DirectoryNode _dirTree = new DirectoryNode("/"); + + public override void CalculatePart1() + { + var dirs = _dirTree.Where(d => d.Size <= 100000); + Part1 = dirs.Sum(d => d.Size); + } + + public override void CalculatePart2() + { + var neededPace = 30000000; + var totalSize = 70000000; + var unusedSpace = totalSize - _dirTree.Size; + var targetSize = neededPace - unusedSpace; + var bigEnough = _dirTree.Where(d => d.Size >= targetSize); + Part2 = bigEnough.MinBy(d => d.Size)?.Size ?? 0; + } + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + + var curDir = new Stack(); + + var dir = "/"; + foreach (var line in lines) + { + if (line[0] == '$') + { + ParseCommand(line[2..], ref curDir); + dir = $"/{string.Join("/", curDir.Reverse())}"; + _dirTree.AddDirectory(dir); + } + else + ReadDirectory(line, _dirTree.GetDirectory(dir)!); + } + } + + private static void ReadDirectory(string line, DirectoryNode curDir) + { + if (line.StartsWith("dir")) + return; + + var split = line.Split(' '); + var name = split[1]; + var size = int.Parse(split[0]); + curDir.AddFile(name, size); + } + + private static void ParseCommand(string command, ref Stack curDir) + { + var split = command.Split(' '); + var keyword = split.First(); + var param = split.Last(); + + switch (keyword) + { + case "cd": + if (param == "..") + curDir.Pop(); + else if (param == "/") + curDir.Clear(); + else + curDir.Push(param); + break; + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day8/TreetopTreeHouse.cs b/AdventOfCode/Problems/AOC2022/Day8/TreetopTreeHouse.cs index 6ece543..de4f287 100644 --- a/AdventOfCode/Problems/AOC2022/Day8/TreetopTreeHouse.cs +++ b/AdventOfCode/Problems/AOC2022/Day8/TreetopTreeHouse.cs @@ -1,99 +1,99 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day8; - -[ProblemInfo(2022, 8, "Treetop Tree House")] -internal class TreetopTreeHouse : Problem -{ - private int[][] _input = Array.Empty(); - private int _height; - private int _width; - - public override void CalculatePart1() - { - for (int y = 1; y < _height - 1; y++) - { - for (int x = 1; x < _width - 1; x++) - { - Part1 += IsVisible(x, y) ? 1 : 0; - } - } - Part1 += _height * 2 + _width * 2 - 4; - } - - private bool IsVisible(int x, int y) - { - return IsVisibleColumn(x, y) || IsVisibleRow(x, y); - } - - private bool IsVisibleColumn(int col, int row) - { - var tree = _input[row][col]; - - var columnOfTrees = _input.Select(r => r[col]); - - var above = columnOfTrees.Take(row); - var below = columnOfTrees.Skip(row + 1); - - return above.All(t => t < tree) || below.All(t => t < tree); - } - - private bool IsVisibleRow(int col, int row) - { - var tree = _input[row][col]; - - var rowOfTrees = _input[row]; - - var left = rowOfTrees.Take(col); - var right = rowOfTrees.Skip(col + 1); - - return left.All(t => t < tree) || right.All(t => t < tree); - } - - public override void CalculatePart2() - { - Part2 = int.MinValue; - for (int y = 1; y < _height - 1; y++) - { - for (int x = 1; x < _width - 1; x++) - { - var v = GetScenicScore(x, y); - if (Part2 < v) - Part2 = v; - } - } - } - - public int GetScenicScore(int row, int col) - { - var tree = _input[row][col]; - - var columnOfTrees = _input.Select(r => r[col]); - var rowOfTrees = _input[row]; - - var above = columnOfTrees.Take(row).Reverse(); - var below = columnOfTrees.Skip(row + 1); - var left = rowOfTrees.Take(col).Reverse(); - var right = rowOfTrees.Skip(col + 1); - - var score = above.Select((t, idx) => (t, idx)) - .FirstOrDefault(v => v.t >= tree, (t: 0, idx: above.Count() - 1)).idx + 1; - score *= below.Select((t, idx) => (t, idx)) - .FirstOrDefault(v => v.t >= tree, (t: 0, idx: below.Count() - 1)).idx + 1; - - score *= left.Select((t, idx) => (t, idx)) - .FirstOrDefault(v => v.t >= tree, (t: 0, idx: left.Count() - 1)).idx + 1; - score *= right.Select((t, idx) => (t, idx)) - .FirstOrDefault(v => v.t >= tree, (t: 0, idx: right.Count() - 1)).idx + 1; - - return score; - } - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - _input = lines.Select(ln => ln.Select(tree => int.Parse(tree.ToString())).ToArray()).ToArray(); - _height = _input.Length; - _width = _input[0].Length; - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day8; + +[ProblemInfo(2022, 8, "Treetop Tree House")] +internal class TreetopTreeHouse : Problem +{ + private int[][] _input = Array.Empty(); + private int _height; + private int _width; + + public override void CalculatePart1() + { + for (int y = 1; y < _height - 1; y++) + { + for (int x = 1; x < _width - 1; x++) + { + Part1 += IsVisible(x, y) ? 1 : 0; + } + } + Part1 += _height * 2 + _width * 2 - 4; + } + + private bool IsVisible(int x, int y) + { + return IsVisibleColumn(x, y) || IsVisibleRow(x, y); + } + + private bool IsVisibleColumn(int col, int row) + { + var tree = _input[row][col]; + + var columnOfTrees = _input.Select(r => r[col]); + + var above = columnOfTrees.Take(row); + var below = columnOfTrees.Skip(row + 1); + + return above.All(t => t < tree) || below.All(t => t < tree); + } + + private bool IsVisibleRow(int col, int row) + { + var tree = _input[row][col]; + + var rowOfTrees = _input[row]; + + var left = rowOfTrees.Take(col); + var right = rowOfTrees.Skip(col + 1); + + return left.All(t => t < tree) || right.All(t => t < tree); + } + + public override void CalculatePart2() + { + Part2 = int.MinValue; + for (int y = 1; y < _height - 1; y++) + { + for (int x = 1; x < _width - 1; x++) + { + var v = GetScenicScore(x, y); + if (Part2 < v) + Part2 = v; + } + } + } + + public int GetScenicScore(int row, int col) + { + var tree = _input[row][col]; + + var columnOfTrees = _input.Select(r => r[col]); + var rowOfTrees = _input[row]; + + var above = columnOfTrees.Take(row).Reverse(); + var below = columnOfTrees.Skip(row + 1); + var left = rowOfTrees.Take(col).Reverse(); + var right = rowOfTrees.Skip(col + 1); + + var score = above.Select((t, idx) => (t, idx)) + .FirstOrDefault(v => v.t >= tree, (t: 0, idx: above.Count() - 1)).idx + 1; + score *= below.Select((t, idx) => (t, idx)) + .FirstOrDefault(v => v.t >= tree, (t: 0, idx: below.Count() - 1)).idx + 1; + + score *= left.Select((t, idx) => (t, idx)) + .FirstOrDefault(v => v.t >= tree, (t: 0, idx: left.Count() - 1)).idx + 1; + score *= right.Select((t, idx) => (t, idx)) + .FirstOrDefault(v => v.t >= tree, (t: 0, idx: right.Count() - 1)).idx + 1; + + return score; + } + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + _input = lines.Select(ln => ln.Select(tree => int.Parse(tree.ToString())).ToArray()).ToArray(); + _height = _input.Length; + _width = _input[0].Length; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day9/RopeBridge.cs b/AdventOfCode/Problems/AOC2022/Day9/RopeBridge.cs index 8984c43..1d54327 100644 --- a/AdventOfCode/Problems/AOC2022/Day9/RopeBridge.cs +++ b/AdventOfCode/Problems/AOC2022/Day9/RopeBridge.cs @@ -1,31 +1,31 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2022.Day9; - -[ProblemInfo(2022, 9, "Rope Bridge")] -internal class RopeBridge : Problem -{ - private (RopeSimulator.Direction, int)[] _moves = Array.Empty<(RopeSimulator.Direction, int)>(); - - public override void CalculatePart1() - { - var sim = new RopeSimulator(_moves); - sim.Simulate(); - Part1 = sim.Visited; - } - - public override void CalculatePart2() - { - var sim = new RopeSimulator(_moves, 9); - sim.Simulate(); - Part2 = sim.Visited; - } - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - _moves = lines.Select(ln => ln.Split(' ')) - .Select(move => (Enum.Parse(move.First()), int.Parse(move.Last()))) - .ToArray(); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2022.Day9; + +[ProblemInfo(2022, 9, "Rope Bridge")] +internal class RopeBridge : Problem +{ + private (RopeSimulator.Direction, int)[] _moves = Array.Empty<(RopeSimulator.Direction, int)>(); + + public override void CalculatePart1() + { + var sim = new RopeSimulator(_moves); + sim.Simulate(); + Part1 = sim.Visited; + } + + public override void CalculatePart2() + { + var sim = new RopeSimulator(_moves, 9); + sim.Simulate(); + Part2 = sim.Visited; + } + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + _moves = lines.Select(ln => ln.Split(' ')) + .Select(move => (Enum.Parse(move.First()), int.Parse(move.Last()))) + .ToArray(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2022/Day9/RopeSimulator.cs b/AdventOfCode/Problems/AOC2022/Day9/RopeSimulator.cs index 5f6efdc..cc930a7 100644 --- a/AdventOfCode/Problems/AOC2022/Day9/RopeSimulator.cs +++ b/AdventOfCode/Problems/AOC2022/Day9/RopeSimulator.cs @@ -1,146 +1,146 @@ -namespace AdventOfCode.Problems.AOC2022.Day9; - -public class RopeSimulator -{ - public int Visited => _visited.Count; - - private readonly (Direction dir, int ammount)[] _movement; - private readonly bool _render; - - public enum Direction - { - L, - R, - U, - D - } - - private (int x, int y) _head; - private (int x, int y)[] _segments; - private Dictionary<(int x, int y), int> _visited; - - public RopeSimulator((Direction dir, int ammount)[] movement, int segments = 1, bool render = false) - { - _movement = movement; - _render = render; - _visited = new Dictionary<(int x, int y), int>() - { - { (0,0), 1 } - }; - _head = (0, 0); - _segments = Enumerable.Repeat((0, 0), segments).ToArray(); - } - - public void Simulate() - { - foreach (var (dir, ammount) in _movement) - { - ProcessStep(dir, ammount); - } - } - - private void ProcessStep(Direction dir, int ammount) - { - for (int i = 0; i < ammount; i++) - { - switch (dir) - { - case Direction.L: - _head.x--; - break; - - case Direction.R: - _head.x++; - break; - - case Direction.U: - _head.y++; - break; - - case Direction.D: - _head.y--; - break; - } - FollowHead(); - var tail = _segments.Last(); - if (_visited.ContainsKey(tail)) - _visited[tail]++; - else - _visited.Add(tail, 1); - } - } - - private void FollowHead() - { - var curHead = _head; - for (int i = 0; i < _segments.Length; i++) - { - var tail = _segments[i]; - curHead = _segments[i] = FollowSegment(curHead, tail); - } - if (_render) - { - DrawScene(); - Console.ReadKey(); - } - } - - private static (int x, int y) FollowSegment((int x, int y) head, (int x, int y) tail) - { - var xDist = head.x - tail.x; - var yDist = head.y - tail.y; - - if (xDist * xDist + yDist * yDist < 4) - return tail; - - if (xDist > 1) - head.x -= 1; - if (xDist < -1) - head.x += 1; - - if (yDist > 1) - head.y -= 1; - if (yDist < -1) - head.y += 1; - - return head; - } - - private static bool ShouldMoveTail((int x, int y) head, (int x, int y) tail) - { - var xDist = Math.Abs(head.x - tail.x); - var yDist = Math.Abs(head.y - tail.y); - return (xDist > 1 || yDist > 1); - } - - private void DrawScene(int segment = -1) - { - var upperX = Math.Max(_head.x, _segments.MaxBy(s => s.x).x); - var upperY = Math.Max(_head.y, _segments.MaxBy(s => s.y).y); - var lowerX = Math.Min(_head.x, _segments.MinBy(s => s.y).y); - var lowerY = Math.Min(_head.y, _segments.MinBy(s => s.y).y); - - var width = upperX - lowerX; - var height = upperY - lowerY; - - Console.Clear(); - Console.ForegroundColor = ConsoleColor.Gray; - Draw('s', (0, 0), lowerX, upperY); - Draw('H', _head, lowerX, upperY); - - for (int i = _segments.Length - 1; i >= 0; i--) - { - if (segment == i) - Console.ForegroundColor = ConsoleColor.Red; - else - Console.ForegroundColor = ConsoleColor.Gray; - Draw((i + 1).ToString()[0], _segments[i], lowerX, upperY); - } - } - - private void Draw(char c, (int x, int y) pos, int offsetX, int offsetY) - { - Console.SetCursorPosition(pos.x + offsetX, -pos.y + offsetY); - Console.WriteLine(c); - } +namespace AdventOfCode.Problems.AOC2022.Day9; + +public class RopeSimulator +{ + public int Visited => _visited.Count; + + private readonly (Direction dir, int ammount)[] _movement; + private readonly bool _render; + + public enum Direction + { + L, + R, + U, + D + } + + private (int x, int y) _head; + private (int x, int y)[] _segments; + private Dictionary<(int x, int y), int> _visited; + + public RopeSimulator((Direction dir, int ammount)[] movement, int segments = 1, bool render = false) + { + _movement = movement; + _render = render; + _visited = new Dictionary<(int x, int y), int>() + { + { (0,0), 1 } + }; + _head = (0, 0); + _segments = Enumerable.Repeat((0, 0), segments).ToArray(); + } + + public void Simulate() + { + foreach (var (dir, ammount) in _movement) + { + ProcessStep(dir, ammount); + } + } + + private void ProcessStep(Direction dir, int ammount) + { + for (int i = 0; i < ammount; i++) + { + switch (dir) + { + case Direction.L: + _head.x--; + break; + + case Direction.R: + _head.x++; + break; + + case Direction.U: + _head.y++; + break; + + case Direction.D: + _head.y--; + break; + } + FollowHead(); + var tail = _segments.Last(); + if (_visited.ContainsKey(tail)) + _visited[tail]++; + else + _visited.Add(tail, 1); + } + } + + private void FollowHead() + { + var curHead = _head; + for (int i = 0; i < _segments.Length; i++) + { + var tail = _segments[i]; + curHead = _segments[i] = FollowSegment(curHead, tail); + } + if (_render) + { + DrawScene(); + Console.ReadKey(); + } + } + + private static (int x, int y) FollowSegment((int x, int y) head, (int x, int y) tail) + { + var xDist = head.x - tail.x; + var yDist = head.y - tail.y; + + if (xDist * xDist + yDist * yDist < 4) + return tail; + + if (xDist > 1) + head.x -= 1; + if (xDist < -1) + head.x += 1; + + if (yDist > 1) + head.y -= 1; + if (yDist < -1) + head.y += 1; + + return head; + } + + private static bool ShouldMoveTail((int x, int y) head, (int x, int y) tail) + { + var xDist = Math.Abs(head.x - tail.x); + var yDist = Math.Abs(head.y - tail.y); + return (xDist > 1 || yDist > 1); + } + + private void DrawScene(int segment = -1) + { + var upperX = Math.Max(_head.x, _segments.MaxBy(s => s.x).x); + var upperY = Math.Max(_head.y, _segments.MaxBy(s => s.y).y); + var lowerX = Math.Min(_head.x, _segments.MinBy(s => s.y).y); + var lowerY = Math.Min(_head.y, _segments.MinBy(s => s.y).y); + + var width = upperX - lowerX; + var height = upperY - lowerY; + + Console.Clear(); + Console.ForegroundColor = ConsoleColor.Gray; + Draw('s', (0, 0), lowerX, upperY); + Draw('H', _head, lowerX, upperY); + + for (int i = _segments.Length - 1; i >= 0; i--) + { + if (segment == i) + Console.ForegroundColor = ConsoleColor.Red; + else + Console.ForegroundColor = ConsoleColor.Gray; + Draw((i + 1).ToString()[0], _segments[i], lowerX, upperY); + } + } + + private void Draw(char c, (int x, int y) pos, int offsetX, int offsetY) + { + Console.SetCursorPosition(pos.x + offsetX, -pos.y + offsetY); + Console.WriteLine(c); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day1/Trebuchet.cs b/AdventOfCode/Problems/AOC2023/Day1/Trebuchet.cs index 5a0dc59..ca2fc27 100644 --- a/AdventOfCode/Problems/AOC2023/Day1/Trebuchet.cs +++ b/AdventOfCode/Problems/AOC2023/Day1/Trebuchet.cs @@ -1,97 +1,97 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2023.Day1; - -[ProblemInfo(2023, 1, "Trebuchet!?")] -public partial class Trebuchet : Problem -{ - private string[] _inputData = []; - - public override void LoadInput() - { - _inputData = ReadInputLines(); - } - - public override void CalculatePart1() - { - Part1 = _inputData.Select(GetCalibrationValues) - .Select(cv => cv.left * 10 + cv.right) - .Sum(); - } - - private (int left, int right) GetCalibrationValues(string line) - { - var (left, right) = (0, 0); - for (int i = 0; i < line.Length; i++) - { - if (line[i] - '0' >= 10) - continue; - - left = line[i] - '0'; - break; - } - for (int i = line.Length - 1; i >= 0; i--) - { - if (line[i] - '0' >= 10) - continue; - right = line[i] - '0'; - break; - } - return (left, right); - } - - private readonly (string word, int value)[] _numberWords = new[] - { - ("one", 1), - ("two", 2), - ("three", 3), - ("four", 4), - ("five", 5), - ("six", 6), - ("seven", 7), - ("eight", 8), - ("nine", 9) - }; - - public override void CalculatePart2() - { - Part2 = _inputData.Select(GetNamedCalibrationValues) - .Select(cv => cv.left * 10 + cv.right) - .Sum(); - } - - private (int left, int right) GetNamedCalibrationValues(string line) - { - var (left, right) = (0, 0); - for (int i = 0; i < line.Length; i++) - { - var word = _numberWords.FirstOrDefault(v => line[i..].StartsWith(v.word, StringComparison.Ordinal), (word: "", value: -1)).value; - if (word != -1) - { - left = word; - break; - } - else if (line[i] - '0' >= 10) - continue; - - left = line[i] - '0'; - break; - } - - for (int i = line.Length - 1; i >= 0; i--) - { - var word = _numberWords.FirstOrDefault(v => line[..(i + 1)].EndsWith(v.word, StringComparison.Ordinal), (word: "", value: -1)).value; - if (word != -1) - { - right = word; - break; - } - else if (line[i] - '0' >= 10) - continue; - - right = line[i] - '0'; - break; - } - return (left, right); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2023.Day1; + +[ProblemInfo(2023, 1, "Trebuchet!?")] +public partial class Trebuchet : Problem +{ + private string[] _inputData = []; + + public override void LoadInput() + { + _inputData = ReadInputLines(); + } + + public override void CalculatePart1() + { + Part1 = _inputData.Select(GetCalibrationValues) + .Select(cv => cv.left * 10 + cv.right) + .Sum(); + } + + private (int left, int right) GetCalibrationValues(string line) + { + var (left, right) = (0, 0); + for (int i = 0; i < line.Length; i++) + { + if (line[i] - '0' >= 10) + continue; + + left = line[i] - '0'; + break; + } + for (int i = line.Length - 1; i >= 0; i--) + { + if (line[i] - '0' >= 10) + continue; + right = line[i] - '0'; + break; + } + return (left, right); + } + + private readonly (string word, int value)[] _numberWords = new[] + { + ("one", 1), + ("two", 2), + ("three", 3), + ("four", 4), + ("five", 5), + ("six", 6), + ("seven", 7), + ("eight", 8), + ("nine", 9) + }; + + public override void CalculatePart2() + { + Part2 = _inputData.Select(GetNamedCalibrationValues) + .Select(cv => cv.left * 10 + cv.right) + .Sum(); + } + + private (int left, int right) GetNamedCalibrationValues(string line) + { + var (left, right) = (0, 0); + for (int i = 0; i < line.Length; i++) + { + var word = _numberWords.FirstOrDefault(v => line[i..].StartsWith(v.word, StringComparison.Ordinal), (word: "", value: -1)).value; + if (word != -1) + { + left = word; + break; + } + else if (line[i] - '0' >= 10) + continue; + + left = line[i] - '0'; + break; + } + + for (int i = line.Length - 1; i >= 0; i--) + { + var word = _numberWords.FirstOrDefault(v => line[..(i + 1)].EndsWith(v.word, StringComparison.Ordinal), (word: "", value: -1)).value; + if (word != -1) + { + right = word; + break; + } + else if (line[i] - '0' >= 10) + continue; + + right = line[i] - '0'; + break; + } + return (left, right); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day10/PipeMaze.cs b/AdventOfCode/Problems/AOC2023/Day10/PipeMaze.cs index ae70244..5d63d80 100644 --- a/AdventOfCode/Problems/AOC2023/Day10/PipeMaze.cs +++ b/AdventOfCode/Problems/AOC2023/Day10/PipeMaze.cs @@ -1,106 +1,106 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day10; - -[ProblemInfo(2023, 10, "Pipe Maze")] -internal class PipeMaze : Problem -{ - private string[] _maze = []; - - public override void LoadInput() - { - _maze = ReadInputLines(); - } - - public override void CalculatePart1() - { - var start = GetStartPointPos(); - var nPoints = GetStartConnections(start); - var seen = new Dictionary<(int, int), int>(); - - foreach (var point in nPoints) - { - var curPoint = start; - var prevPoint = point; - var dist = 0; - while (true) - { - dist++; - var next = GetNextPoint(curPoint, prevPoint); - prevPoint = curPoint; - curPoint = next; - if (next == start) - break; - if (seen.TryGetValue(next, out var d)) - { - if (d > dist) - seen[next] = dist; - else - break; - } - else - seen.Add(next, dist); - } - } - - Part1 = seen.Values.Max(); - } - - private (int x, int y) GetStartPointPos() - { - for (int y = 0; y < _maze.Length; y++) - { - var x = _maze[y].IndexOf('S'); - if (x >= 0) - return (x, y); - } - throw new Exception("Start point not found"); - } - - private List<(int x, int y)> GetStartConnections((int x, int y) pos) - { - var points = new List<(int x, int y)>(); - if (_maze[pos.y + 1][pos.x] is '|' or 'J' or 'L') - points.Add((pos.x + 1, pos.y)); - if (_maze[pos.y - 1][pos.x] is '|' or 'F' or '7') - points.Add((pos.x - 1, pos.y)); - - if (_maze[pos.y][pos.x + 1] is '-' or 'J' or '7') - points.Add((pos.x, pos.y + 1)); - if (_maze[pos.y][pos.x - 1] is '-' or 'F' or 'L') - points.Add((pos.x, pos.y - 1)); - - return points; - } - - private (int x, int y) GetNextPoint((int x, int y) pos, (int x, int y) prev) - { - var curPipe = _maze[pos.y][pos.x]; - (int x, int y) = (pos.x - prev.x, pos.y - prev.y); - - if (curPipe == 'S') - return GetStartConnections(pos).First(p => p != prev); - - return curPipe switch - { - '|' => (pos.x, pos.y + y), - '-' => (pos.x + x, pos.y), - 'L' => (pos.x + y, pos.y + x), - 'F' => (pos.x - y, pos.y - x), - 'J' => (pos.x - y, pos.y - x), - '7' => (pos.x + y, pos.y + x), - _ => throw new Exception() - }; - } - - public override void CalculatePart2() - { - throw new NotImplementedException(); - } +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day10; + +[ProblemInfo(2023, 10, "Pipe Maze")] +internal class PipeMaze : Problem +{ + private string[] _maze = []; + + public override void LoadInput() + { + _maze = ReadInputLines(); + } + + public override void CalculatePart1() + { + var start = GetStartPointPos(); + var nPoints = GetStartConnections(start); + var seen = new Dictionary<(int, int), int>(); + + foreach (var point in nPoints) + { + var curPoint = start; + var prevPoint = point; + var dist = 0; + while (true) + { + dist++; + var next = GetNextPoint(curPoint, prevPoint); + prevPoint = curPoint; + curPoint = next; + if (next == start) + break; + if (seen.TryGetValue(next, out var d)) + { + if (d > dist) + seen[next] = dist; + else + break; + } + else + seen.Add(next, dist); + } + } + + Part1 = seen.Values.Max(); + } + + private (int x, int y) GetStartPointPos() + { + for (int y = 0; y < _maze.Length; y++) + { + var x = _maze[y].IndexOf('S'); + if (x >= 0) + return (x, y); + } + throw new Exception("Start point not found"); + } + + private List<(int x, int y)> GetStartConnections((int x, int y) pos) + { + var points = new List<(int x, int y)>(); + if (_maze[pos.y + 1][pos.x] is '|' or 'J' or 'L') + points.Add((pos.x + 1, pos.y)); + if (_maze[pos.y - 1][pos.x] is '|' or 'F' or '7') + points.Add((pos.x - 1, pos.y)); + + if (_maze[pos.y][pos.x + 1] is '-' or 'J' or '7') + points.Add((pos.x, pos.y + 1)); + if (_maze[pos.y][pos.x - 1] is '-' or 'F' or 'L') + points.Add((pos.x, pos.y - 1)); + + return points; + } + + private (int x, int y) GetNextPoint((int x, int y) pos, (int x, int y) prev) + { + var curPipe = _maze[pos.y][pos.x]; + (int x, int y) = (pos.x - prev.x, pos.y - prev.y); + + if (curPipe == 'S') + return GetStartConnections(pos).First(p => p != prev); + + return curPipe switch + { + '|' => (pos.x, pos.y + y), + '-' => (pos.x + x, pos.y), + 'L' => (pos.x + y, pos.y + x), + 'F' => (pos.x - y, pos.y - x), + 'J' => (pos.x - y, pos.y - x), + '7' => (pos.x + y, pos.y + x), + _ => throw new Exception() + }; + } + + public override void CalculatePart2() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day11/CosmicExpansion.cs b/AdventOfCode/Problems/AOC2023/Day11/CosmicExpansion.cs index ea715f8..3e59ca0 100644 --- a/AdventOfCode/Problems/AOC2023/Day11/CosmicExpansion.cs +++ b/AdventOfCode/Problems/AOC2023/Day11/CosmicExpansion.cs @@ -1,89 +1,89 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day11; - -[ProblemInfo(2023, 11, "Cosmic Expansion")] -internal class CosmicExpansion : Problem -{ - private string[] _data = []; - private int[] _yGaps = []; - private int[] _xGaps = []; - - public override void CalculatePart1() - { - var points = GetPoints().Select(p => Inflate(p, 2)).ToList(); - for (int i = 0; i < points.Count - 1; i++) - { - for (int j = i + 1; j < points.Count; j++) - { - var a = points[i]; - var b = points[j]; - Part1 += GetDistance(a, b); - } - } - } - - public List<(int x, int y)> GetPoints() - { - var result = new List<(int x, int y)>(); - for (int y = 0; y < _data.Length; y++) - { - for (int x = 0; x < _data[0].Length; x++) - { - if (_data[y][x] == '#') - result.Add((x, y)); - } - } - return result; - } - - public int GetDistance((int x, int y) a, (int x, int y) b) - { - var xDist = Math.Abs(a.x - b.x); - var yDist = Math.Abs(a.y - b.y); - - return xDist + yDist; - } - - public (int x, int y) Inflate((int x, int y) point, int factor) - { - factor -= 1; - var cX = _xGaps.Count(x => point.x >= x); - var cY = _yGaps.Count(y => point.y >= y); - return (point.x + cX * factor, point.y + cY * factor); - } - - public override void CalculatePart2() - { - var points = GetPoints().Select(p => Inflate(p, 1000000)).ToList(); - for (int i = 0; i < points.Count - 1; i++) - { - for (int j = i + 1; j < points.Count; j++) - { - var a = points[i]; - var b = points[j]; - Part2 += GetDistance(a, b); - } - } - } - - public override void LoadInput() - { - _data = ReadInputLines(); - _yGaps = _data.Select((v, i) => (c: v.Count(x => x == '.'), i)) - .Where(v => v.c == _data[0].Length) - .Select(v => v.i) - .ToArray(); - - _xGaps = _data.Transpose().Select((v, i) => (c: v.Count(x => x == '.'), i)) - .Where(v => v.c == _data[0].Length) - .Select(v => v.i) - .ToArray(); - } -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day11; + +[ProblemInfo(2023, 11, "Cosmic Expansion")] +internal class CosmicExpansion : Problem +{ + private string[] _data = []; + private int[] _yGaps = []; + private int[] _xGaps = []; + + public override void CalculatePart1() + { + var points = GetPoints().Select(p => Inflate(p, 2)).ToList(); + for (int i = 0; i < points.Count - 1; i++) + { + for (int j = i + 1; j < points.Count; j++) + { + var a = points[i]; + var b = points[j]; + Part1 += GetDistance(a, b); + } + } + } + + public List<(int x, int y)> GetPoints() + { + var result = new List<(int x, int y)>(); + for (int y = 0; y < _data.Length; y++) + { + for (int x = 0; x < _data[0].Length; x++) + { + if (_data[y][x] == '#') + result.Add((x, y)); + } + } + return result; + } + + public int GetDistance((int x, int y) a, (int x, int y) b) + { + var xDist = Math.Abs(a.x - b.x); + var yDist = Math.Abs(a.y - b.y); + + return xDist + yDist; + } + + public (int x, int y) Inflate((int x, int y) point, int factor) + { + factor -= 1; + var cX = _xGaps.Count(x => point.x >= x); + var cY = _yGaps.Count(y => point.y >= y); + return (point.x + cX * factor, point.y + cY * factor); + } + + public override void CalculatePart2() + { + var points = GetPoints().Select(p => Inflate(p, 1000000)).ToList(); + for (int i = 0; i < points.Count - 1; i++) + { + for (int j = i + 1; j < points.Count; j++) + { + var a = points[i]; + var b = points[j]; + Part2 += GetDistance(a, b); + } + } + } + + public override void LoadInput() + { + _data = ReadInputLines(); + _yGaps = _data.Select((v, i) => (c: v.Count(x => x == '.'), i)) + .Where(v => v.c == _data[0].Length) + .Select(v => v.i) + .ToArray(); + + _xGaps = _data.Transpose().Select((v, i) => (c: v.Count(x => x == '.'), i)) + .Where(v => v.c == _data[0].Length) + .Select(v => v.i) + .ToArray(); + } +} diff --git a/AdventOfCode/Problems/AOC2023/Day12/HotSprings.cs b/AdventOfCode/Problems/AOC2023/Day12/HotSprings.cs index 3e3faf7..ce9155a 100644 --- a/AdventOfCode/Problems/AOC2023/Day12/HotSprings.cs +++ b/AdventOfCode/Problems/AOC2023/Day12/HotSprings.cs @@ -1,111 +1,111 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day12; - -[ProblemInfo(2023, 12, "Hot Springs")] -internal class HotSprings : Problem -{ - private Record[] _data = []; - - public override void CalculatePart1() - { - Part1 = _data.Select(r => CountPossiblilites(r)).Sum(); - } - - public override void CalculatePart2() - { - var unfolded = _data.Select(r => - { - var unfoldData = string.Join("", Enumerable.Repeat(r.Data, 5)); - var unfoldPattern = Enumerable.Repeat(r.Pattern, 5).SelectMany(x => x).ToArray(); - return new Record(unfoldData, unfoldPattern); - }).ToArray(); - Part2 = unfolded.Select(r => CountPossiblilites(r)).Sum(); - } - - public static int CountPossiblilites(Record record, int pos = 0) - { - if (pos == -1 || pos >= record.Data.Length) - return record.IsValid ? 1 : 0; - if (!record.IsValid) - return 0; - if (record.Data[pos] != '?') - return CountPossiblilites(record, record.Data.IndexOf('?')); - - var front = record.Data[..pos]; - var back = record.Data[(pos + 1)..]; - var r1 = record with { Data = $"{front}.{back}" }; - var r2 = record with { Data = $"{front}#{back}" }; - return CountPossiblilites(r1, pos + 1) + CountPossiblilites(r2, pos + 1); - } - - public override void LoadInput() - { - var data = ReadInputLines(); - - _data = data.Select(x => x.Split(' ')) - .Select(x => new Record(x[0], x[1].Split(',').Select(int.Parse).ToArray())) - .ToArray(); - } - - public record Record(string Data, int[] Pattern) - { - public bool IsValid => CheckValidity(this); - public static bool CheckValidity(Record record) - { - var section = 0; - var start = 0; - var inSection = false; - for (int i = 0; i < record.Data.Length; i++) - { - var c = record.Data[i]; - if (section >= record.Pattern.Length) - return !record.Data[i..].Contains('#'); - - var len = record.Pattern[section]; - - switch (c) - { - case '?': - if (inSection && i - start > len) - return false; - return true; - - case '.': - if (inSection) - { - if (i - start != len) - return false; - inSection = false; - start = 0; - section++; - } - continue; - case '#': - if (!inSection) - { - inSection = true; - start = i; - } - break; - } - } - if (inSection) - { - if (record.Pattern[section] != (record.Data[start..].Length)) - return false; - else - section++; - } - if (section != record.Pattern.Length) - return false; - return true; - } - }; +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day12; + +[ProblemInfo(2023, 12, "Hot Springs")] +internal class HotSprings : Problem +{ + private Record[] _data = []; + + public override void CalculatePart1() + { + Part1 = _data.Select(r => CountPossiblilites(r)).Sum(); + } + + public override void CalculatePart2() + { + var unfolded = _data.Select(r => + { + var unfoldData = string.Join("", Enumerable.Repeat(r.Data, 5)); + var unfoldPattern = Enumerable.Repeat(r.Pattern, 5).SelectMany(x => x).ToArray(); + return new Record(unfoldData, unfoldPattern); + }).ToArray(); + Part2 = unfolded.Select(r => CountPossiblilites(r)).Sum(); + } + + public static int CountPossiblilites(Record record, int pos = 0) + { + if (pos == -1 || pos >= record.Data.Length) + return record.IsValid ? 1 : 0; + if (!record.IsValid) + return 0; + if (record.Data[pos] != '?') + return CountPossiblilites(record, record.Data.IndexOf('?')); + + var front = record.Data[..pos]; + var back = record.Data[(pos + 1)..]; + var r1 = record with { Data = $"{front}.{back}" }; + var r2 = record with { Data = $"{front}#{back}" }; + return CountPossiblilites(r1, pos + 1) + CountPossiblilites(r2, pos + 1); + } + + public override void LoadInput() + { + var data = ReadInputLines(); + + _data = data.Select(x => x.Split(' ')) + .Select(x => new Record(x[0], x[1].Split(',').Select(int.Parse).ToArray())) + .ToArray(); + } + + public record Record(string Data, int[] Pattern) + { + public bool IsValid => CheckValidity(this); + public static bool CheckValidity(Record record) + { + var section = 0; + var start = 0; + var inSection = false; + for (int i = 0; i < record.Data.Length; i++) + { + var c = record.Data[i]; + if (section >= record.Pattern.Length) + return !record.Data[i..].Contains('#'); + + var len = record.Pattern[section]; + + switch (c) + { + case '?': + if (inSection && i - start > len) + return false; + return true; + + case '.': + if (inSection) + { + if (i - start != len) + return false; + inSection = false; + start = 0; + section++; + } + continue; + case '#': + if (!inSection) + { + inSection = true; + start = i; + } + break; + } + } + if (inSection) + { + if (record.Pattern[section] != (record.Data[start..].Length)) + return false; + else + section++; + } + if (section != record.Pattern.Length) + return false; + return true; + } + }; } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day2/CubeConundrum.cs b/AdventOfCode/Problems/AOC2023/Day2/CubeConundrum.cs index 88fef56..18b1065 100644 --- a/AdventOfCode/Problems/AOC2023/Day2/CubeConundrum.cs +++ b/AdventOfCode/Problems/AOC2023/Day2/CubeConundrum.cs @@ -1,31 +1,31 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2023.Day2; - -[ProblemInfo(2023, 2, "Cube Conundrum")] -internal class CubeConundrum : Problem -{ - private CubeGame[] _gameInfo = []; - - public override void LoadInput() - { - var lines = ReadInputLines(); - _gameInfo = lines.Select(l => new CubeGame(l)).ToArray(); - } - - public override void CalculatePart1() - { - Part1 = FindPossibleGames(new CubeRound(12, 13, 14)).Sum(); - } - - public override void CalculatePart2() - { - Part2 = _gameInfo.Select(g => g.GetMinimalConstraints().Power()).Sum(); - } - - public IEnumerable FindPossibleGames(CubeRound constraints) - { - return _gameInfo.Where(g => !g.Rounds.Any(r => !r.IsPossible(constraints))) - .Select(r => r.Id); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2023.Day2; + +[ProblemInfo(2023, 2, "Cube Conundrum")] +internal class CubeConundrum : Problem +{ + private CubeGame[] _gameInfo = []; + + public override void LoadInput() + { + var lines = ReadInputLines(); + _gameInfo = lines.Select(l => new CubeGame(l)).ToArray(); + } + + public override void CalculatePart1() + { + Part1 = FindPossibleGames(new CubeRound(12, 13, 14)).Sum(); + } + + public override void CalculatePart2() + { + Part2 = _gameInfo.Select(g => g.GetMinimalConstraints().Power()).Sum(); + } + + public IEnumerable FindPossibleGames(CubeRound constraints) + { + return _gameInfo.Where(g => !g.Rounds.Any(r => !r.IsPossible(constraints))) + .Select(r => r.Id); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day2/CubeGame.cs b/AdventOfCode/Problems/AOC2023/Day2/CubeGame.cs index 0d9291b..1de0f0a 100644 --- a/AdventOfCode/Problems/AOC2023/Day2/CubeGame.cs +++ b/AdventOfCode/Problems/AOC2023/Day2/CubeGame.cs @@ -1,81 +1,81 @@ -namespace AdventOfCode.Problems.AOC2023.Day2; - -internal class CubeGame -{ - public CubeRound[] Rounds { get; } - - public int Id { get; } - - public CubeGame(string line) - { - var info = line.Split(':'); - Id = int.Parse(info[0].Split(' ')[^1]); - - var roundsData = info[1].Split(';'); - Rounds = new CubeRound[roundsData.Length]; - for (int i = 0; i < roundsData.Length; i++) - Rounds[i] = CubeRound.ParseRound(roundsData[i]); - } - - public CubeRound GetMinimalConstraints() - { - var (r, g, b) = (0, 0, 0); - foreach (var round in Rounds) - { - if (round.Red > r) - r = round.Red; - if (round.Green > g) - g = round.Green; - if (round.Blue > b) - b = round.Blue; - } - return new CubeRound(r, g, b); - } -} - -internal record struct CubeRound(int Red, int Green, int Blue) -{ - public static CubeRound ParseRound(string round) - { - var cubes = round.Split(','); - var (r, g, b) = (0, 0, 0); - - foreach (var cube in cubes) - { - var info = cube.TrimStart().Split(' '); - var count = int.Parse(info[0]); - switch (info[1]) - { - case ['r', ..]: - r = count; - break; - - case ['g', ..]: - g = count; - break; - - case ['b', ..]: - b = count; - break; - } - } - return new CubeRound(r, g, b); - } - - public readonly bool IsPossible(CubeRound constraints) - { - if (Red > constraints.Red) - return false; - if (Green > constraints.Green) - return false; - if (Blue > constraints.Blue) - return false; - - return true; - } - - public readonly int Power() - { - return Red * Green * Blue; - } +namespace AdventOfCode.Problems.AOC2023.Day2; + +internal class CubeGame +{ + public CubeRound[] Rounds { get; } + + public int Id { get; } + + public CubeGame(string line) + { + var info = line.Split(':'); + Id = int.Parse(info[0].Split(' ')[^1]); + + var roundsData = info[1].Split(';'); + Rounds = new CubeRound[roundsData.Length]; + for (int i = 0; i < roundsData.Length; i++) + Rounds[i] = CubeRound.ParseRound(roundsData[i]); + } + + public CubeRound GetMinimalConstraints() + { + var (r, g, b) = (0, 0, 0); + foreach (var round in Rounds) + { + if (round.Red > r) + r = round.Red; + if (round.Green > g) + g = round.Green; + if (round.Blue > b) + b = round.Blue; + } + return new CubeRound(r, g, b); + } +} + +internal record struct CubeRound(int Red, int Green, int Blue) +{ + public static CubeRound ParseRound(string round) + { + var cubes = round.Split(','); + var (r, g, b) = (0, 0, 0); + + foreach (var cube in cubes) + { + var info = cube.TrimStart().Split(' '); + var count = int.Parse(info[0]); + switch (info[1]) + { + case ['r', ..]: + r = count; + break; + + case ['g', ..]: + g = count; + break; + + case ['b', ..]: + b = count; + break; + } + } + return new CubeRound(r, g, b); + } + + public readonly bool IsPossible(CubeRound constraints) + { + if (Red > constraints.Red) + return false; + if (Green > constraints.Green) + return false; + if (Blue > constraints.Blue) + return false; + + return true; + } + + public readonly int Power() + { + return Red * Green * Blue; + } }; \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day3/GearRatios.cs b/AdventOfCode/Problems/AOC2023/Day3/GearRatios.cs index 2be2ce5..3175566 100644 --- a/AdventOfCode/Problems/AOC2023/Day3/GearRatios.cs +++ b/AdventOfCode/Problems/AOC2023/Day3/GearRatios.cs @@ -1,136 +1,136 @@ -using AdventOfCode.Runner.Attributes; - -namespace AdventOfCode.Problems.AOC2023.Day3; - -[ProblemInfo(2023, 3, "Gear Ratios")] -internal class GearRatios : Problem -{ - private string[] _data = []; - private int _width; - private int _height; - - public override void LoadInput() - { - _data = ReadInputLines(); - _width = _data[0].Length - 1; - _height = _data.Length - 1; - } - - public override void CalculatePart1() - { - var partNumbers = new List(); - - for (int y = 0; y < _height; y++) - { - for (int x = 0; x <= _width; x++) - { - var cell = _data[y][x]; - switch (cell) - { - case '.': - continue; - case < '0' or > '9': - FindNumbers(x, y, ref partNumbers); - break; - } - } - } - Part1 = partNumbers.Sum(); - } - - public override void CalculatePart2() - { - var ratios = new List(); - var curNums = new List(); - for (int y = 0; y < _height; y++) - { - for (int x = 0; x <= _width; x++) - { - var cell = _data[y][x]; - switch (cell) - { - case '*': - curNums.Clear(); - FindNumbers(x, y, ref curNums); - if (curNums.Count == 2) - ratios.Add(curNums[0] * curNums[1]); - break; - } - } - } - Part2 = ratios.Sum(); - } - - public void FindNumbers(int x, int y, ref List results) - { - var seen = new HashSet<(int x, int y)>(); - - var n = GetNeighborPoints(x, y); - foreach (var (xN, yN) in n) - { - var c = _data[yN][xN] - '0'; - if (c >= 0) //A bug exists here, I wont fix it - { - var num = GetNumber(xN, yN, out var idx); - - if (seen.Contains(idx)) - continue; - seen.Add(idx); - results.Add(num); - } - } - } - - public List<(int x, int y)> GetNeighborPoints(int x, int y) - { - var points = new List<(int x, int y)>(); - if (x > 0) - points.Add((x - 1, y)); - if (x < _width) - points.Add((x + 1, y)); - if (y > 0) - points.Add((x, y - 1)); - if (y < _height) - points.Add((x, y + 1)); - if (x > 0 && y > 0) - points.Add((x - 1, y - 1)); - if (x > 0 && y < _height) - points.Add((x - 1, y + 1)); - if (x < _width && y < _height) - points.Add((x + 1, y + 1)); - if (x < _width && y > 0) - points.Add((x + 1, y - 1)); - - return points; - } - - public int GetNumber(int x, int y, out (int iX, int iY) index) - { - var row = _data[y]; - - var numStart = 0; - var numEnd = _width + 1; - for (int i = x; i >= 0; i--) - { - switch (row[i]) - { - case < '0' or > '9': - numStart = i + 1; - goto leftDone; - } - } - leftDone: - for (int i = x; i <= _width; i++) - { - switch (row[i]) - { - case < '0' or > '9': - numEnd = i; - goto done; - } - } - done: - index = (numStart, y); - return int.Parse(row[numStart..numEnd]); - } +using AdventOfCode.Runner.Attributes; + +namespace AdventOfCode.Problems.AOC2023.Day3; + +[ProblemInfo(2023, 3, "Gear Ratios")] +internal class GearRatios : Problem +{ + private string[] _data = []; + private int _width; + private int _height; + + public override void LoadInput() + { + _data = ReadInputLines(); + _width = _data[0].Length - 1; + _height = _data.Length - 1; + } + + public override void CalculatePart1() + { + var partNumbers = new List(); + + for (int y = 0; y < _height; y++) + { + for (int x = 0; x <= _width; x++) + { + var cell = _data[y][x]; + switch (cell) + { + case '.': + continue; + case < '0' or > '9': + FindNumbers(x, y, ref partNumbers); + break; + } + } + } + Part1 = partNumbers.Sum(); + } + + public override void CalculatePart2() + { + var ratios = new List(); + var curNums = new List(); + for (int y = 0; y < _height; y++) + { + for (int x = 0; x <= _width; x++) + { + var cell = _data[y][x]; + switch (cell) + { + case '*': + curNums.Clear(); + FindNumbers(x, y, ref curNums); + if (curNums.Count == 2) + ratios.Add(curNums[0] * curNums[1]); + break; + } + } + } + Part2 = ratios.Sum(); + } + + public void FindNumbers(int x, int y, ref List results) + { + var seen = new HashSet<(int x, int y)>(); + + var n = GetNeighborPoints(x, y); + foreach (var (xN, yN) in n) + { + var c = _data[yN][xN] - '0'; + if (c >= 0) //A bug exists here, I wont fix it + { + var num = GetNumber(xN, yN, out var idx); + + if (seen.Contains(idx)) + continue; + seen.Add(idx); + results.Add(num); + } + } + } + + public List<(int x, int y)> GetNeighborPoints(int x, int y) + { + var points = new List<(int x, int y)>(); + if (x > 0) + points.Add((x - 1, y)); + if (x < _width) + points.Add((x + 1, y)); + if (y > 0) + points.Add((x, y - 1)); + if (y < _height) + points.Add((x, y + 1)); + if (x > 0 && y > 0) + points.Add((x - 1, y - 1)); + if (x > 0 && y < _height) + points.Add((x - 1, y + 1)); + if (x < _width && y < _height) + points.Add((x + 1, y + 1)); + if (x < _width && y > 0) + points.Add((x + 1, y - 1)); + + return points; + } + + public int GetNumber(int x, int y, out (int iX, int iY) index) + { + var row = _data[y]; + + var numStart = 0; + var numEnd = _width + 1; + for (int i = x; i >= 0; i--) + { + switch (row[i]) + { + case < '0' or > '9': + numStart = i + 1; + goto leftDone; + } + } + leftDone: + for (int i = x; i <= _width; i++) + { + switch (row[i]) + { + case < '0' or > '9': + numEnd = i; + goto done; + } + } + done: + index = (numStart, y); + return int.Parse(row[numStart..numEnd]); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day4/Scratchcards.cs b/AdventOfCode/Problems/AOC2023/Day4/Scratchcards.cs index 68f2dd6..d95693c 100644 --- a/AdventOfCode/Problems/AOC2023/Day4/Scratchcards.cs +++ b/AdventOfCode/Problems/AOC2023/Day4/Scratchcards.cs @@ -1,66 +1,66 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day4; -[ProblemInfo(2023, 4, "Scratchcards")] -internal class Scratchcards : Problem -{ - private (int card, int[] win, int[] have)[] _cards = []; - private readonly Dictionary _cardCount = []; - - public override void CalculatePart1() - { - Part1 = _cards - .Select(c => c.have.Intersect(c.win).Count()) - .Select(c => c == 0 ? 0 : Math.Pow(2, c - 1)) - .Sum(); - } - - public override void CalculatePart2() - { - Part2 = _cards.Length; - for (int i = 0; i < _cards.Length; i++) - { - var card = _cards[i]; - var wins = card.have.Intersect(card.win).Count(); - var cCount = GetCardCount(card.card); - for (int j = 1; j <= wins; j++) - AddCards(card.card + j, cCount); - Part2 += wins * cCount; - } - } - - private int GetCardCount(int card) - { - if(_cardCount.TryGetValue(card, out var count)) - return count; - return 1; - } - - private void AddCards(int card, int count) - { - if(_cardCount.ContainsKey(card)) - _cardCount[card] += count; - else - _cardCount.Add(card, count + 1); - } - - public override void LoadInput() - { - var lines = ReadInputLines(); - _cards = new (int card, int[] win, int[] have)[lines.Length]; - for (int i = 0; i < lines.Length; i++) - { - var card = lines[i].Split(':'); - var cardNum = int.Parse(card[0].Split(' ').Last()); - var numbers = card[1].Split('|') - .Select(v => v.Split(' ').Where(v => v.Length > 0).Select(int.Parse)); - _cards[i] = (cardNum, numbers.First().ToArray(), numbers.Last().ToArray()); - } - } -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day4; +[ProblemInfo(2023, 4, "Scratchcards")] +internal class Scratchcards : Problem +{ + private (int card, int[] win, int[] have)[] _cards = []; + private readonly Dictionary _cardCount = []; + + public override void CalculatePart1() + { + Part1 = _cards + .Select(c => c.have.Intersect(c.win).Count()) + .Select(c => c == 0 ? 0 : Math.Pow(2, c - 1)) + .Sum(); + } + + public override void CalculatePart2() + { + Part2 = _cards.Length; + for (int i = 0; i < _cards.Length; i++) + { + var card = _cards[i]; + var wins = card.have.Intersect(card.win).Count(); + var cCount = GetCardCount(card.card); + for (int j = 1; j <= wins; j++) + AddCards(card.card + j, cCount); + Part2 += wins * cCount; + } + } + + private int GetCardCount(int card) + { + if(_cardCount.TryGetValue(card, out var count)) + return count; + return 1; + } + + private void AddCards(int card, int count) + { + if(_cardCount.ContainsKey(card)) + _cardCount[card] += count; + else + _cardCount.Add(card, count + 1); + } + + public override void LoadInput() + { + var lines = ReadInputLines(); + _cards = new (int card, int[] win, int[] have)[lines.Length]; + for (int i = 0; i < lines.Length; i++) + { + var card = lines[i].Split(':'); + var cardNum = int.Parse(card[0].Split(' ').Last()); + var numbers = card[1].Split('|') + .Select(v => v.Split(' ').Where(v => v.Length > 0).Select(int.Parse)); + _cards[i] = (cardNum, numbers.First().ToArray(), numbers.Last().ToArray()); + } + } +} diff --git a/AdventOfCode/Problems/AOC2023/Day5/CategoryEvaluator.cs b/AdventOfCode/Problems/AOC2023/Day5/CategoryEvaluator.cs index d7a1135..8e7f0a7 100644 --- a/AdventOfCode/Problems/AOC2023/Day5/CategoryEvaluator.cs +++ b/AdventOfCode/Problems/AOC2023/Day5/CategoryEvaluator.cs @@ -1,73 +1,73 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day5; -internal class CategoryEvaluator -{ - public Dictionary destinations = []; - - public CategoryEvaluator(CategoryMapper[] mappers) - { - destinations = mappers.ToDictionary(m => m.Destination); - } - - public long Evaluate(Category source, long sourceValue, Category destination) - { - var mappers = new List(); - var curMapper = destinations[destination]; - do - { - mappers.Add(curMapper); - curMapper = destinations[curMapper.Source]; - } while (curMapper.Source != source); - mappers.Add(destinations[mappers.Last().Source]); - mappers.Reverse(); - var result = sourceValue; - foreach (var mapper in mappers) - { - result = mapper.Evaluate(result); - } - return result; - } - - public (long start, long end)[] Evaluate(Category source, (long start, long end)[] seeds, Category destination) - { - var mappers = new List(); - var curMapper = destinations[destination]; - do - { - mappers.Add(curMapper); - curMapper = destinations[curMapper.Source]; - } while (curMapper.Source != source); - mappers.Add(destinations[mappers.Last().Source]); - mappers.Reverse(); - var result = seeds; - foreach (var mapper in mappers) - { - result = mapper.Evaluate(result); - } - return result.Distinct().ToArray(); - } - - public CategoryMapper GetCategoryMapper(Category destination) - { - return destinations[destination]; - } - - - public enum Category - { - Seed, - Soil, - Fertilizer, - Water, - Light, - Temperature, - Humidity, - Location - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day5; +internal class CategoryEvaluator +{ + public Dictionary destinations = []; + + public CategoryEvaluator(CategoryMapper[] mappers) + { + destinations = mappers.ToDictionary(m => m.Destination); + } + + public long Evaluate(Category source, long sourceValue, Category destination) + { + var mappers = new List(); + var curMapper = destinations[destination]; + do + { + mappers.Add(curMapper); + curMapper = destinations[curMapper.Source]; + } while (curMapper.Source != source); + mappers.Add(destinations[mappers.Last().Source]); + mappers.Reverse(); + var result = sourceValue; + foreach (var mapper in mappers) + { + result = mapper.Evaluate(result); + } + return result; + } + + public (long start, long end)[] Evaluate(Category source, (long start, long end)[] seeds, Category destination) + { + var mappers = new List(); + var curMapper = destinations[destination]; + do + { + mappers.Add(curMapper); + curMapper = destinations[curMapper.Source]; + } while (curMapper.Source != source); + mappers.Add(destinations[mappers.Last().Source]); + mappers.Reverse(); + var result = seeds; + foreach (var mapper in mappers) + { + result = mapper.Evaluate(result); + } + return result.Distinct().ToArray(); + } + + public CategoryMapper GetCategoryMapper(Category destination) + { + return destinations[destination]; + } + + + public enum Category + { + Seed, + Soil, + Fertilizer, + Water, + Light, + Temperature, + Humidity, + Location + } +} diff --git a/AdventOfCode/Problems/AOC2023/Day5/CategoryMapper.cs b/AdventOfCode/Problems/AOC2023/Day5/CategoryMapper.cs index 927cc2e..19adba3 100644 --- a/AdventOfCode/Problems/AOC2023/Day5/CategoryMapper.cs +++ b/AdventOfCode/Problems/AOC2023/Day5/CategoryMapper.cs @@ -1,88 +1,88 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day5; -internal class CategoryMapper -{ - public CategoryEvaluator.Category Source { get; } - public CategoryEvaluator.Category Destination { get; } - public long[] DestinationStart { get; } - public long[] DestinationEnd { get; } - public long[] SourceStart { get; } - public long[] SourceEnd { get; } - public long[] RangeLength { get; } - public long[] Gap { get; } - - public CategoryMapper(CategoryEvaluator.Category source, CategoryEvaluator.Category destination, long[] destinationStart, long[] sourceStart, long[] length) - { - Source = source; - Destination = destination; - DestinationStart = destinationStart; - DestinationEnd = destinationStart.Select((v, i) => v + length[i]).ToArray(); - SourceStart = sourceStart; - SourceEnd = sourceStart.Select((v, i) => v + length[i]).ToArray(); - RangeLength = length; - Gap = sourceStart.Select((v, i) => destinationStart[i] - v).ToArray(); - } - - public static CategoryMapper Parse(string categoryData) - { - var lines = categoryData.Split("\r\n"); - var names = lines[0].Split(' ')[0].Split('-'); - var source = Enum.Parse(names[0], true); - var dst = Enum.Parse(names[^1], true); - - var mappingData = lines[1..].Select(ln => ln.Split(' ').Select(long.Parse).ToArray()); - var dStart = mappingData.Select(d => d[0]).ToArray(); - var sStart = mappingData.Select(d => d[1]).ToArray(); - var len = mappingData.Select(d => d[2]).ToArray(); - return new CategoryMapper(source, dst, dStart, sStart, len); - - } - - public long Evaluate(long value) - { - for (int i = 0; i < DestinationStart.Length; i++) - { - if (SourceStart[i] > value) - continue; - if (SourceEnd[i] < value) - continue; - return value + Gap[i]; - } - return value; - } - - public (long start, long end)[] Evaluate((long start, long end)[] ranges) - { - var result = new List<(long start, long end)>(); - for (int i = 0; i < DestinationStart.Length; i++) - { - result.AddRange(ranges.SelectMany(r => SubdivideRange(r, (SourceStart[i], SourceEnd[i])))); - } - return result.Distinct().Select(v => (Evaluate(v.start), Evaluate(v.end))).ToArray(); - } - - public static (long start, long end)[] SubdivideRange((long start, long end) source, (long start, long end) dst) - { - if (source.start >= dst.start && source.end <= dst.end) - return [source]; - if(source.end < dst.end) - return [source]; - if(source.start > dst.start) - return [source]; - - if(source.start < dst.start) - return [(source.start, dst.start - 1), (dst.start, source.end), (source.end + 1, dst.end)]; - else - return [(dst.start, source.start - 1), (source.start, dst.end), (dst.end + 1, source.end)]; - } - - public override string ToString() - { - return $"{Source} -> {Destination}"; - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day5; +internal class CategoryMapper +{ + public CategoryEvaluator.Category Source { get; } + public CategoryEvaluator.Category Destination { get; } + public long[] DestinationStart { get; } + public long[] DestinationEnd { get; } + public long[] SourceStart { get; } + public long[] SourceEnd { get; } + public long[] RangeLength { get; } + public long[] Gap { get; } + + public CategoryMapper(CategoryEvaluator.Category source, CategoryEvaluator.Category destination, long[] destinationStart, long[] sourceStart, long[] length) + { + Source = source; + Destination = destination; + DestinationStart = destinationStart; + DestinationEnd = destinationStart.Select((v, i) => v + length[i]).ToArray(); + SourceStart = sourceStart; + SourceEnd = sourceStart.Select((v, i) => v + length[i]).ToArray(); + RangeLength = length; + Gap = sourceStart.Select((v, i) => destinationStart[i] - v).ToArray(); + } + + public static CategoryMapper Parse(string categoryData) + { + var lines = categoryData.Split("\r\n"); + var names = lines[0].Split(' ')[0].Split('-'); + var source = Enum.Parse(names[0], true); + var dst = Enum.Parse(names[^1], true); + + var mappingData = lines[1..].Select(ln => ln.Split(' ').Select(long.Parse).ToArray()); + var dStart = mappingData.Select(d => d[0]).ToArray(); + var sStart = mappingData.Select(d => d[1]).ToArray(); + var len = mappingData.Select(d => d[2]).ToArray(); + return new CategoryMapper(source, dst, dStart, sStart, len); + + } + + public long Evaluate(long value) + { + for (int i = 0; i < DestinationStart.Length; i++) + { + if (SourceStart[i] > value) + continue; + if (SourceEnd[i] < value) + continue; + return value + Gap[i]; + } + return value; + } + + public (long start, long end)[] Evaluate((long start, long end)[] ranges) + { + var result = new List<(long start, long end)>(); + for (int i = 0; i < DestinationStart.Length; i++) + { + result.AddRange(ranges.SelectMany(r => SubdivideRange(r, (SourceStart[i], SourceEnd[i])))); + } + return result.Distinct().Select(v => (Evaluate(v.start), Evaluate(v.end))).ToArray(); + } + + public static (long start, long end)[] SubdivideRange((long start, long end) source, (long start, long end) dst) + { + if (source.start >= dst.start && source.end <= dst.end) + return [source]; + if(source.end < dst.end) + return [source]; + if(source.start > dst.start) + return [source]; + + if(source.start < dst.start) + return [(source.start, dst.start - 1), (dst.start, source.end), (source.end + 1, dst.end)]; + else + return [(dst.start, source.start - 1), (source.start, dst.end), (dst.end + 1, source.end)]; + } + + public override string ToString() + { + return $"{Source} -> {Destination}"; + } +} diff --git a/AdventOfCode/Problems/AOC2023/Day5/SeedFertilizer.cs b/AdventOfCode/Problems/AOC2023/Day5/SeedFertilizer.cs index 075ec37..a61f691 100644 --- a/AdventOfCode/Problems/AOC2023/Day5/SeedFertilizer.cs +++ b/AdventOfCode/Problems/AOC2023/Day5/SeedFertilizer.cs @@ -1,38 +1,38 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day5; -[ProblemInfo(2023, 5, "If You Give A Seed A Fertilizer")] -internal class SeedFertilizer : Problem -{ - private long[] _seeds = []; - private CategoryEvaluator _evaluator = new ([]); - - public override void LoadInput() - { - var data = ReadInputText("sample.txt"); - var sections = data.Split("\r\n\r\n"); - _seeds = sections[0].Split(": ")[1].Split(" ").Select(long.Parse).ToArray(); - - var mappers = sections[1..].Select(CategoryMapper.Parse).ToArray(); - _evaluator = new CategoryEvaluator(mappers); - } - - public override void CalculatePart1() - { - var evaludated = _seeds.Select(s => _evaluator.Evaluate(CategoryEvaluator.Category.Seed, s, CategoryEvaluator.Category.Location)); - Part1 = evaludated.Min(); - } - - public override void CalculatePart2() - { - var splitRanges = _evaluator.Evaluate(CategoryEvaluator.Category.Seed, _seeds.Chunk(2).Select(s => (s[0], s[0] + s[1])).ToArray(), CategoryEvaluator.Category.Location); - - } - -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day5; +[ProblemInfo(2023, 5, "If You Give A Seed A Fertilizer")] +internal class SeedFertilizer : Problem +{ + private long[] _seeds = []; + private CategoryEvaluator _evaluator = new ([]); + + public override void LoadInput() + { + var data = ReadInputText("sample.txt"); + var sections = data.Split("\r\n\r\n"); + _seeds = sections[0].Split(": ")[1].Split(" ").Select(long.Parse).ToArray(); + + var mappers = sections[1..].Select(CategoryMapper.Parse).ToArray(); + _evaluator = new CategoryEvaluator(mappers); + } + + public override void CalculatePart1() + { + var evaludated = _seeds.Select(s => _evaluator.Evaluate(CategoryEvaluator.Category.Seed, s, CategoryEvaluator.Category.Location)); + Part1 = evaludated.Min(); + } + + public override void CalculatePart2() + { + var splitRanges = _evaluator.Evaluate(CategoryEvaluator.Category.Seed, _seeds.Chunk(2).Select(s => (s[0], s[0] + s[1])).ToArray(), CategoryEvaluator.Category.Location); + + } + +} diff --git a/AdventOfCode/Problems/AOC2023/Day6/WaitForIt.cs b/AdventOfCode/Problems/AOC2023/Day6/WaitForIt.cs index 69a495f..9d9426c 100644 --- a/AdventOfCode/Problems/AOC2023/Day6/WaitForIt.cs +++ b/AdventOfCode/Problems/AOC2023/Day6/WaitForIt.cs @@ -1,65 +1,65 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day6; -[ProblemInfo(2023, 6, "Wait For It")] -internal class WaitForIt : Problem -{ - private int[] _times = []; - private int[] _distances = []; - private int _realTime; - private long _realDistance; - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - _times = lines[0].Split(':')[1] - .Split(' ') - .Where(e => e.Length > 0) - .Select(int.Parse) - .ToArray(); - - _distances = lines[1].Split(':')[1] - .Split(' ') - .Where(e => e.Length > 0) - .Select(int.Parse) - .ToArray(); - - _realTime = int.Parse(lines[0].Split(":")[1].Replace(" ", "")); - _realDistance = long.Parse(lines[1].Split(":")[1].Replace(" ", "")); - } - - public override void CalculatePart1() - { - var winList = new List(); - for (int i = 0; i < _times.Length; i++) - { - var time = _times[i]; - var distance = _distances[i]; - var minTime = (int)Math.Floor((float)distance / time); - var possibleHeldTimes = Enumerable.Range(minTime, time - minTime); - var races = possibleHeldTimes.Select(t => (time - t) * t); - winList.Add(races.Count(d => d > distance)); - } - Part1 = winList.Aggregate((a, b) => a * b); - } - - public override void CalculatePart2() - { - var minTime = (long)Math.Floor((float)_realDistance/ _realTime); - var maxTime = _realTime - minTime; - for (long i = minTime; i <= maxTime; i++) - { - var dist = (_realTime - i) * i; - if(dist > _realDistance) - Part2++; - } - } - -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day6; +[ProblemInfo(2023, 6, "Wait For It")] +internal class WaitForIt : Problem +{ + private int[] _times = []; + private int[] _distances = []; + private int _realTime; + private long _realDistance; + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + _times = lines[0].Split(':')[1] + .Split(' ') + .Where(e => e.Length > 0) + .Select(int.Parse) + .ToArray(); + + _distances = lines[1].Split(':')[1] + .Split(' ') + .Where(e => e.Length > 0) + .Select(int.Parse) + .ToArray(); + + _realTime = int.Parse(lines[0].Split(":")[1].Replace(" ", "")); + _realDistance = long.Parse(lines[1].Split(":")[1].Replace(" ", "")); + } + + public override void CalculatePart1() + { + var winList = new List(); + for (int i = 0; i < _times.Length; i++) + { + var time = _times[i]; + var distance = _distances[i]; + var minTime = (int)Math.Floor((float)distance / time); + var possibleHeldTimes = Enumerable.Range(minTime, time - minTime); + var races = possibleHeldTimes.Select(t => (time - t) * t); + winList.Add(races.Count(d => d > distance)); + } + Part1 = winList.Aggregate((a, b) => a * b); + } + + public override void CalculatePart2() + { + var minTime = (long)Math.Floor((float)_realDistance/ _realTime); + var maxTime = _realTime - minTime; + for (long i = minTime; i <= maxTime; i++) + { + var dist = (_realTime - i) * i; + if(dist > _realDistance) + Part2++; + } + } + +} diff --git a/AdventOfCode/Problems/AOC2023/Day7/CamelCards.cs b/AdventOfCode/Problems/AOC2023/Day7/CamelCards.cs index bf8aeaf..8e51baf 100644 --- a/AdventOfCode/Problems/AOC2023/Day7/CamelCards.cs +++ b/AdventOfCode/Problems/AOC2023/Day7/CamelCards.cs @@ -1,36 +1,36 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day7; -[ProblemInfo(2023, 7, "Camel Cards")] -internal class CamelCards : Problem -{ - private CamelHand[] _hands = []; - private CamelHand[] _jokerHands = []; - - public override void LoadInput() - { - var data = ReadInputLines("input.txt"); - _hands = data.Select(d => new CamelHand(d)).ToArray(); - _jokerHands = data.Select(d => new CamelHand(d, true)).ToArray(); - } - - public override void CalculatePart1() - { - var x = _hands.Order(); - Part1 = x.Select((h, i) => (i + 1) * h.Bid).Sum(); - } - - public override void CalculatePart2() - { - var x = _jokerHands.Order().Print(); - //x.Where(x => x.Hand.Contains('J')).Print(); - Part2 = x.Select((h, i) => (i + 1) * h.Bid).Sum(); - } - -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day7; +[ProblemInfo(2023, 7, "Camel Cards")] +internal class CamelCards : Problem +{ + private CamelHand[] _hands = []; + private CamelHand[] _jokerHands = []; + + public override void LoadInput() + { + var data = ReadInputLines("input.txt"); + _hands = data.Select(d => new CamelHand(d)).ToArray(); + _jokerHands = data.Select(d => new CamelHand(d, true)).ToArray(); + } + + public override void CalculatePart1() + { + var x = _hands.Order(); + Part1 = x.Select((h, i) => (i + 1) * h.Bid).Sum(); + } + + public override void CalculatePart2() + { + var x = _jokerHands.Order().Print(); + //x.Where(x => x.Hand.Contains('J')).Print(); + Part2 = x.Select((h, i) => (i + 1) * h.Bid).Sum(); + } + +} diff --git a/AdventOfCode/Problems/AOC2023/Day7/CamelHand.cs b/AdventOfCode/Problems/AOC2023/Day7/CamelHand.cs index 9352765..62e136c 100644 --- a/AdventOfCode/Problems/AOC2023/Day7/CamelHand.cs +++ b/AdventOfCode/Problems/AOC2023/Day7/CamelHand.cs @@ -1,106 +1,106 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day7; -internal class CamelHand : IComparable -{ - public static readonly List CARDS = [ '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A' ]; - public static readonly List CARDS_JOKER = [ 'J', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'Q', 'K', 'A' ]; - - public string Hand { get; set; } - public int Bid { get; set; } - public int Value { get; set; } - public HandType Type { get; set; } - public CamelHand(string data, bool useJoker = false) - { - var split = data.Split(' '); - Hand = split[0]; - Bid = int.Parse(split[1]); - Type = useJoker ? GetJokerHandType(Hand) : GetHandType(Hand); - Value = CalculateValue(Hand, useJoker); - } - - public static int CalculateValue(string hand, bool useJoker) - { - var total = 0; - for (int i = 0; i < hand.Length; i++) - { - var p = (hand.Length - i - 1); - var v = useJoker ? CARDS_JOKER.IndexOf(hand[i]) : CARDS.IndexOf(hand[i]); - total += (v + 1) * (int)Math.Pow(13, p); - } - return total; - } - - public bool IsStrongerThan(CamelHand card) - { - if (Type > card.Type) - return true; - if(Type < card.Type) - return false; - - return Value >= card.Value; - } - - private static HandType GetJokerHandType(string hand) - { - var type = GetHandType(hand); - if (type == HandType.FiveOfKind) - return type; - - if (!hand.Contains('J')) - return type; - var bestCard = hand.GroupBy(c => c) - .OrderByDescending(c => c.Count()) - .First(c => c.Key != 'J').Key; - - var newHand = hand.Replace('J', bestCard); - return GetHandType(newHand); - } - private static HandType GetHandType(string hand) - { - var cardGroups = hand.GroupBy(c => c).Select(g => g.Count()).ToArray(); - - if (cardGroups.Length == 1) - return HandType.FiveOfKind; - if(cardGroups.Contains(4)) - return HandType.FourOfKind; - if (cardGroups.Contains(3) && cardGroups.Contains(2)) - return HandType.FullHouse; - if(cardGroups.Contains(3)) - return HandType.ThreeOfKind; - - var pairs = cardGroups.Count(c => c == 2); - if (pairs == 2) - return HandType.TwoPair; - if (pairs == 1) - return HandType.OnePair; - - return HandType.HighCard; - } - - public int CompareTo(CamelHand? other) - { - if(other == null) return 1; - return IsStrongerThan(other) ? 1 : -1; - } - - public override string ToString() - { - return $"[{Value}] {Hand}: {Type} | {Bid}"; - } - - public enum HandType - { - HighCard, - OnePair, - TwoPair, - ThreeOfKind, - FullHouse, - FourOfKind, - FiveOfKind - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day7; +internal class CamelHand : IComparable +{ + public static readonly List CARDS = [ '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A' ]; + public static readonly List CARDS_JOKER = [ 'J', '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'Q', 'K', 'A' ]; + + public string Hand { get; set; } + public int Bid { get; set; } + public int Value { get; set; } + public HandType Type { get; set; } + public CamelHand(string data, bool useJoker = false) + { + var split = data.Split(' '); + Hand = split[0]; + Bid = int.Parse(split[1]); + Type = useJoker ? GetJokerHandType(Hand) : GetHandType(Hand); + Value = CalculateValue(Hand, useJoker); + } + + public static int CalculateValue(string hand, bool useJoker) + { + var total = 0; + for (int i = 0; i < hand.Length; i++) + { + var p = (hand.Length - i - 1); + var v = useJoker ? CARDS_JOKER.IndexOf(hand[i]) : CARDS.IndexOf(hand[i]); + total += (v + 1) * (int)Math.Pow(13, p); + } + return total; + } + + public bool IsStrongerThan(CamelHand card) + { + if (Type > card.Type) + return true; + if(Type < card.Type) + return false; + + return Value >= card.Value; + } + + private static HandType GetJokerHandType(string hand) + { + var type = GetHandType(hand); + if (type == HandType.FiveOfKind) + return type; + + if (!hand.Contains('J')) + return type; + var bestCard = hand.GroupBy(c => c) + .OrderByDescending(c => c.Count()) + .First(c => c.Key != 'J').Key; + + var newHand = hand.Replace('J', bestCard); + return GetHandType(newHand); + } + private static HandType GetHandType(string hand) + { + var cardGroups = hand.GroupBy(c => c).Select(g => g.Count()).ToArray(); + + if (cardGroups.Length == 1) + return HandType.FiveOfKind; + if(cardGroups.Contains(4)) + return HandType.FourOfKind; + if (cardGroups.Contains(3) && cardGroups.Contains(2)) + return HandType.FullHouse; + if(cardGroups.Contains(3)) + return HandType.ThreeOfKind; + + var pairs = cardGroups.Count(c => c == 2); + if (pairs == 2) + return HandType.TwoPair; + if (pairs == 1) + return HandType.OnePair; + + return HandType.HighCard; + } + + public int CompareTo(CamelHand? other) + { + if(other == null) return 1; + return IsStrongerThan(other) ? 1 : -1; + } + + public override string ToString() + { + return $"[{Value}] {Hand}: {Type} | {Bid}"; + } + + public enum HandType + { + HighCard, + OnePair, + TwoPair, + ThreeOfKind, + FullHouse, + FourOfKind, + FiveOfKind + } +} diff --git a/AdventOfCode/Problems/AOC2023/Day8/HauntedWasteland.cs b/AdventOfCode/Problems/AOC2023/Day8/HauntedWasteland.cs index 000a8e0..083d463 100644 --- a/AdventOfCode/Problems/AOC2023/Day8/HauntedWasteland.cs +++ b/AdventOfCode/Problems/AOC2023/Day8/HauntedWasteland.cs @@ -1,74 +1,74 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day8; - -[ProblemInfo(2023, 8, "Haunted Wasteland")] -internal class HauntedWasteland : Problem -{ - private string _path = string.Empty; - private Dictionary _nodes = []; - - public override void LoadInput() - { - var data = ReadInputLines(); - _path = data[0]; - - for (int i = 2; i < data.Length; i++) - { - var curLine = data[i].Split('='); - var node = curLine[0].TrimEnd(); - var branches = curLine[1][2..^1].Split(", "); - _nodes.Add(node, (branches[0], branches[1])); - } - } - - public override void CalculatePart1() - { - var curPos = "AAA"; - var i = 0; - var steps = 0; - do - { - curPos = _path[i] switch - { - 'L' => _nodes[curPos].left, - 'R' => _nodes[curPos].right, - _ => throw new Exception("Something went horribly wrong") - }; - i = (i + 1) % _path.Length; - steps++; - } while (curPos != "ZZZ"); - Part1 = steps; - } - - public override void CalculatePart2() - { - var curPos = _nodes.Keys.Where(n => n[^1] == 'A').ToArray(); - var len = new long[curPos.Length]; - var i = 0; - do - { - for (int j = 0; j < curPos.Length; j++) - { - if (curPos[j][^1] == 'Z') - continue; - len[j]++; - curPos[j] = _path[i] switch - { - 'L' => _nodes[curPos[j]].left, - 'R' => _nodes[curPos[j]].right, - _ => throw new Exception("Something went horribly wrong") - }; - } - i = (i + 1) % _path.Length; - } while (curPos.Any(n => n[^1] != 'Z')); - - Part2 = len.LCM(); - } +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day8; + +[ProblemInfo(2023, 8, "Haunted Wasteland")] +internal class HauntedWasteland : Problem +{ + private string _path = string.Empty; + private Dictionary _nodes = []; + + public override void LoadInput() + { + var data = ReadInputLines(); + _path = data[0]; + + for (int i = 2; i < data.Length; i++) + { + var curLine = data[i].Split('='); + var node = curLine[0].TrimEnd(); + var branches = curLine[1][2..^1].Split(", "); + _nodes.Add(node, (branches[0], branches[1])); + } + } + + public override void CalculatePart1() + { + var curPos = "AAA"; + var i = 0; + var steps = 0; + do + { + curPos = _path[i] switch + { + 'L' => _nodes[curPos].left, + 'R' => _nodes[curPos].right, + _ => throw new Exception("Something went horribly wrong") + }; + i = (i + 1) % _path.Length; + steps++; + } while (curPos != "ZZZ"); + Part1 = steps; + } + + public override void CalculatePart2() + { + var curPos = _nodes.Keys.Where(n => n[^1] == 'A').ToArray(); + var len = new long[curPos.Length]; + var i = 0; + do + { + for (int j = 0; j < curPos.Length; j++) + { + if (curPos[j][^1] == 'Z') + continue; + len[j]++; + curPos[j] = _path[i] switch + { + 'L' => _nodes[curPos[j]].left, + 'R' => _nodes[curPos[j]].right, + _ => throw new Exception("Something went horribly wrong") + }; + } + i = (i + 1) % _path.Length; + } while (curPos.Any(n => n[^1] != 'Z')); + + Part2 = len.LCM(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2023/Day9/MirageMaintenance.cs b/AdventOfCode/Problems/AOC2023/Day9/MirageMaintenance.cs index a5a8f02..27c1b21 100644 --- a/AdventOfCode/Problems/AOC2023/Day9/MirageMaintenance.cs +++ b/AdventOfCode/Problems/AOC2023/Day9/MirageMaintenance.cs @@ -1,85 +1,85 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2023.Day9; -[ProblemInfo(2023, 9, "Mirage Maintenance")] -internal class MirageMaintenance : Problem -{ - private long[][] _history = []; - - public override void LoadInput() - { - _history = ReadInputLines("input.txt").Select(ln => ln.Split(' ').Select(long.Parse).ToArray()).ToArray(); - } - - public long CalculateNumber(long[] values, bool last = true) - { - var diffs = new long[values.Length - 1]; - for (int i = 0; i < values.Length - 1; i++) - diffs[i] = values[i + 1] - values[i]; - - if (diffs.Any(d => d != 0)) - return last ? (values.Last() + CalculateNumber(diffs, last)) : (values.First() - CalculateNumber(diffs, last)); - else - return last ? values.Last() : values.First(); - } - - [Obsolete("Optimize too soon garbage")] - public long GetNextNumber(long[] history) - { - var data = new List> - { - new(history.Reverse()) - }; - CalculateLayer(data, 1, 1); - var sum = data.Select(d => d.First()).Sum(); - Console.WriteLine(); - Console.WriteLine(string.Join(',', history)); - Console.WriteLine(); - - foreach (var item in data) - Console.WriteLine(string.Join(" | ", item.Select(n => n.ToString()))); - return sum; - } - - [Obsolete("Optimize too soon garbage")] - public void CalculateLayer(List> data, int layer, int pos) - { - while (data.Count <= layer) - data.Add([]); - var lastLayer = layer - 1; - if (layer != 0 && data[lastLayer].Count <= pos) - CalculateLayer(data, lastLayer, pos + 1); - - var right = data[lastLayer][pos - 1]; - var left = data[lastLayer][pos]; - var diff = right - left; - data[layer].Add(diff); - if (diff != 0 && pos == 1) - CalculateLayer(data, layer + 1, 1); - } - - public enum State - { - Diff, - Expand, - Predict - } - - public override void CalculatePart1() - { - //GetNextNumber(_history[2]); - Part1 = _history.Select(c => CalculateNumber(c)).Sum(); - } - - public override void CalculatePart2() - { - Part2 = _history.Select(c => CalculateNumber(c, false)).Sum(); - } - -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2023.Day9; +[ProblemInfo(2023, 9, "Mirage Maintenance")] +internal class MirageMaintenance : Problem +{ + private long[][] _history = []; + + public override void LoadInput() + { + _history = ReadInputLines("input.txt").Select(ln => ln.Split(' ').Select(long.Parse).ToArray()).ToArray(); + } + + public long CalculateNumber(long[] values, bool last = true) + { + var diffs = new long[values.Length - 1]; + for (int i = 0; i < values.Length - 1; i++) + diffs[i] = values[i + 1] - values[i]; + + if (diffs.Any(d => d != 0)) + return last ? (values.Last() + CalculateNumber(diffs, last)) : (values.First() - CalculateNumber(diffs, last)); + else + return last ? values.Last() : values.First(); + } + + [Obsolete("Optimize too soon garbage")] + public long GetNextNumber(long[] history) + { + var data = new List> + { + new(history.Reverse()) + }; + CalculateLayer(data, 1, 1); + var sum = data.Select(d => d.First()).Sum(); + Console.WriteLine(); + Console.WriteLine(string.Join(',', history)); + Console.WriteLine(); + + foreach (var item in data) + Console.WriteLine(string.Join(" | ", item.Select(n => n.ToString()))); + return sum; + } + + [Obsolete("Optimize too soon garbage")] + public void CalculateLayer(List> data, int layer, int pos) + { + while (data.Count <= layer) + data.Add([]); + var lastLayer = layer - 1; + if (layer != 0 && data[lastLayer].Count <= pos) + CalculateLayer(data, lastLayer, pos + 1); + + var right = data[lastLayer][pos - 1]; + var left = data[lastLayer][pos]; + var diff = right - left; + data[layer].Add(diff); + if (diff != 0 && pos == 1) + CalculateLayer(data, layer + 1, 1); + } + + public enum State + { + Diff, + Expand, + Predict + } + + public override void CalculatePart1() + { + //GetNextNumber(_history[2]); + Part1 = _history.Select(c => CalculateNumber(c)).Sum(); + } + + public override void CalculatePart2() + { + Part2 = _history.Select(c => CalculateNumber(c, false)).Sum(); + } + +} diff --git a/AdventOfCode/Problems/AOC2024/Day1/HistorianHysteria.cs b/AdventOfCode/Problems/AOC2024/Day1/HistorianHysteria.cs index ac676d4..b4411ae 100644 --- a/AdventOfCode/Problems/AOC2024/Day1/HistorianHysteria.cs +++ b/AdventOfCode/Problems/AOC2024/Day1/HistorianHysteria.cs @@ -1,40 +1,40 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2024.Day1; -[ProblemInfo(2024, 1, "Historian Hysteria")] -internal class HistorianHysteria : Problem -{ - private int[] _left = []; - private int[] _right = []; - - public override void CalculatePart1() - { - Part1 = _left.Order() - .Zip(_right.Order()) - .Select(a => Math.Abs(a.First - a.Second)) - .Sum(); - } - - public override void CalculatePart2() - { - var rightFeq = _right.GroupBy(x => x) - .ToFrozenDictionary(g => g.Key, g => g.Count()); - Part2 = _left.Select(x => rightFeq.TryGetValue(x, out var f) ? f * x : 0) - .Sum(); - } - - public override void LoadInput() - { - var lines = ReadInputLines(); - var data = lines.Select(l => l.Split(' ').Select(int.Parse)).ToList(); - _left = data.Select(l => l.First()).ToArray(); - _right = data.Select(l => l.Last()).ToArray(); - } -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2024.Day1; +[ProblemInfo(2024, 1, "Historian Hysteria")] +internal class HistorianHysteria : Problem +{ + private int[] _left = []; + private int[] _right = []; + + public override void CalculatePart1() + { + Part1 = _left.Order() + .Zip(_right.Order()) + .Select(a => Math.Abs(a.First - a.Second)) + .Sum(); + } + + public override void CalculatePart2() + { + var rightFeq = _right.GroupBy(x => x) + .ToFrozenDictionary(g => g.Key, g => g.Count()); + Part2 = _left.Select(x => rightFeq.TryGetValue(x, out var f) ? f * x : 0) + .Sum(); + } + + public override void LoadInput() + { + var lines = ReadInputLines(); + var data = lines.Select(l => l.Split(' ').Select(int.Parse)).ToList(); + _left = data.Select(l => l.First()).ToArray(); + _right = data.Select(l => l.Last()).ToArray(); + } +} diff --git a/AdventOfCode/Problems/AOC2024/Day10/HoofIt.cs b/AdventOfCode/Problems/AOC2024/Day10/HoofIt.cs index aec0b70..59e23c7 100644 --- a/AdventOfCode/Problems/AOC2024/Day10/HoofIt.cs +++ b/AdventOfCode/Problems/AOC2024/Day10/HoofIt.cs @@ -1,102 +1,102 @@ -using AdventOfCode.Utils.Models; - -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2024.Day10; -[ProblemInfo(2024, 10, "Hoof It")] -internal class HoofIt : Problem -{ - private int[][] _data = []; - - public static Vec2[] DIRS = [ - new(0, -1), - new(1, 0), - new(0, 1), - new(-1, 0), - ]; - - public override void CalculatePart1() - { - for (int y = 0; y < _data.Length; y++) - { - var row = _data[y]; - for (int x = 0; x < row.Length; x++) - { - var h = row[x]; - if (h != 0) - continue; - var (s,_) = GetScore(new(x, y)); - Part1 += s; - } - } - } - - public override void CalculatePart2() - { - for (int y = 0; y < _data.Length; y++) - { - var row = _data[y]; - for (int x = 0; x < row.Length; x++) - { - var h = row[x]; - if (h != 0) - continue; - var (_, s) = GetScore(new(x, y)); - Part2 += s; - } - } - } - - public (int score, int scoreDistinct) GetScore(Vec2 pos) - { - return GetScore(pos, []); - } - - public (int score, int scoreDistinct) GetScore(Vec2 pos, HashSet> visited) - { - var curHeight = _data[pos.Y][pos.X]; - if (curHeight == 9) - { - if(visited.Contains(pos)) - return (0, 1); - visited.Add(pos); - return (1, 1); - } - - var score = 0; - var scoreDistinct = 0; - foreach (var dir in DIRS) - { - var n = pos + dir; - if (!IsInBounds(n)) - continue; - var h = _data[n.Y][n.X]; - if (h - curHeight != 1) - continue; - var (s, d)= GetScore(n, visited); - score += s; - scoreDistinct += d; - } - - return (score, scoreDistinct); - } - - public bool IsInBounds(Vec2 pos) - { - if (pos.X < 0 || pos.Y < 0) - return false; - if(pos.X >= _data.Length || pos.Y >= _data[0].Length) - return false; - return true; - } - - public override void LoadInput() - { - _data = ReadInputLines("input.txt").Select(l => l.Select(v => v - '0').ToArray()).ToArray(); - } -} +using AdventOfCode.Utils.Models; + +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2024.Day10; +[ProblemInfo(2024, 10, "Hoof It")] +internal class HoofIt : Problem +{ + private int[][] _data = []; + + public static Vec2[] DIRS = [ + new(0, -1), + new(1, 0), + new(0, 1), + new(-1, 0), + ]; + + public override void CalculatePart1() + { + for (int y = 0; y < _data.Length; y++) + { + var row = _data[y]; + for (int x = 0; x < row.Length; x++) + { + var h = row[x]; + if (h != 0) + continue; + var (s,_) = GetScore(new(x, y)); + Part1 += s; + } + } + } + + public override void CalculatePart2() + { + for (int y = 0; y < _data.Length; y++) + { + var row = _data[y]; + for (int x = 0; x < row.Length; x++) + { + var h = row[x]; + if (h != 0) + continue; + var (_, s) = GetScore(new(x, y)); + Part2 += s; + } + } + } + + public (int score, int scoreDistinct) GetScore(Vec2 pos) + { + return GetScore(pos, []); + } + + public (int score, int scoreDistinct) GetScore(Vec2 pos, HashSet> visited) + { + var curHeight = _data[pos.Y][pos.X]; + if (curHeight == 9) + { + if(visited.Contains(pos)) + return (0, 1); + visited.Add(pos); + return (1, 1); + } + + var score = 0; + var scoreDistinct = 0; + foreach (var dir in DIRS) + { + var n = pos + dir; + if (!IsInBounds(n)) + continue; + var h = _data[n.Y][n.X]; + if (h - curHeight != 1) + continue; + var (s, d)= GetScore(n, visited); + score += s; + scoreDistinct += d; + } + + return (score, scoreDistinct); + } + + public bool IsInBounds(Vec2 pos) + { + if (pos.X < 0 || pos.Y < 0) + return false; + if(pos.X >= _data.Length || pos.Y >= _data[0].Length) + return false; + return true; + } + + public override void LoadInput() + { + _data = ReadInputLines("input.txt").Select(l => l.Select(v => v - '0').ToArray()).ToArray(); + } +} diff --git a/AdventOfCode/Problems/AOC2024/Day11/PlutonianPebbles.cs b/AdventOfCode/Problems/AOC2024/Day11/PlutonianPebbles.cs index af9c6ec..6531d8b 100644 --- a/AdventOfCode/Problems/AOC2024/Day11/PlutonianPebbles.cs +++ b/AdventOfCode/Problems/AOC2024/Day11/PlutonianPebbles.cs @@ -1,115 +1,115 @@ -using Superpower.Model; - -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using static System.Runtime.InteropServices.JavaScript.JSType; - -namespace AdventOfCode.Problems.AOC2024.Day11; - -[ProblemInfo(2024, 11, "Plutonian Pebbles")] -public class PlutonianPebbles : Problem -{ - private List _data = []; - private readonly Dictionary<(long, long), long> _depthLookup = []; - - public override void CalculatePart1() - { - Part1 = _data.Sum(v => ProcessStoneRecursive(v, 25)); - } - - public override void CalculatePart2() - { - Part2 = _data.Sum(v => ProcessStoneRecursive(v, 75)); - } - - public long ProcessStoneRecursive(long stone, long target, long curDepth = 0) - { - if (curDepth == target) - return 1; - var d = target - curDepth; - if(_depthLookup.TryGetValue((stone, d), out var c)) - return c; - long result; - if (stone == 0) - result = ProcessStoneRecursive(1, target, curDepth + 1); - else if (FastSplit(stone, out var left, out var right)) - result = ProcessStoneRecursive(left, target, curDepth + 1) + ProcessStoneRecursive(right, target, curDepth + 1); - else - result = ProcessStoneRecursive(stone * 2024, target, curDepth + 1); - - _depthLookup.Add((stone, d), result); - return result; - } - - public long Run(long count) - { - var a = _data.ToList(); - var b = new List(a.Count); - for (long i = 0; i < count; i++) - { - foreach (var stone in a) - ProcessStone(stone, b); - - (a, b) = (b, a); - b.Clear(); - } - return a.Count; - } - - public void ProcessStone(long stone, List data) - { - if (stone == 0) - { - data.Add(1); - return; - } - if (FastSplit(stone, out var left, out var right)) - { - data.Add(left); - data.Add(right); - return; - } - data.Add(stone * 2024); - } - - private static IEnumerable Split(long stone, int len) - { - var v = stone.ToString(); - return [long.Parse(v[..(len / 2)]), long.Parse(v[(len / 2)..])]; - } - - private static bool FastSplit(long stone, out long left, out long right) - { - - var len = stone.DigitCount(); - if (len % 2 != 0) - { - left = 0; - right = 0; - return false; - } - var l = QuickMath.FastPow10(len / 2); - var a = stone / l; - - (left, right) = (a, stone - (a * l)); - return true; - - } - - private static bool IsEvenDigits(long value, out int len) - { - var v = len = value.ToString().Length; - return v % 2 == 0; - } - - public override void LoadInput() - { - _data = ReadInputText("input.txt").Split(' ').Select(long.Parse).ToList(); - } +using Superpower.Model; + +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace AdventOfCode.Problems.AOC2024.Day11; + +[ProblemInfo(2024, 11, "Plutonian Pebbles")] +public class PlutonianPebbles : Problem +{ + private List _data = []; + private readonly Dictionary<(long, long), long> _depthLookup = []; + + public override void CalculatePart1() + { + Part1 = _data.Sum(v => ProcessStoneRecursive(v, 25)); + } + + public override void CalculatePart2() + { + Part2 = _data.Sum(v => ProcessStoneRecursive(v, 75)); + } + + public long ProcessStoneRecursive(long stone, long target, long curDepth = 0) + { + if (curDepth == target) + return 1; + var d = target - curDepth; + if(_depthLookup.TryGetValue((stone, d), out var c)) + return c; + long result; + if (stone == 0) + result = ProcessStoneRecursive(1, target, curDepth + 1); + else if (FastSplit(stone, out var left, out var right)) + result = ProcessStoneRecursive(left, target, curDepth + 1) + ProcessStoneRecursive(right, target, curDepth + 1); + else + result = ProcessStoneRecursive(stone * 2024, target, curDepth + 1); + + _depthLookup.Add((stone, d), result); + return result; + } + + public long Run(long count) + { + var a = _data.ToList(); + var b = new List(a.Count); + for (long i = 0; i < count; i++) + { + foreach (var stone in a) + ProcessStone(stone, b); + + (a, b) = (b, a); + b.Clear(); + } + return a.Count; + } + + public void ProcessStone(long stone, List data) + { + if (stone == 0) + { + data.Add(1); + return; + } + if (FastSplit(stone, out var left, out var right)) + { + data.Add(left); + data.Add(right); + return; + } + data.Add(stone * 2024); + } + + private static IEnumerable Split(long stone, int len) + { + var v = stone.ToString(); + return [long.Parse(v[..(len / 2)]), long.Parse(v[(len / 2)..])]; + } + + private static bool FastSplit(long stone, out long left, out long right) + { + + var len = stone.DigitCount(); + if (len % 2 != 0) + { + left = 0; + right = 0; + return false; + } + var l = QuickMath.FastPow10(len / 2); + var a = stone / l; + + (left, right) = (a, stone - (a * l)); + return true; + + } + + private static bool IsEvenDigits(long value, out int len) + { + var v = len = value.ToString().Length; + return v % 2 == 0; + } + + public override void LoadInput() + { + _data = ReadInputText("input.txt").Split(' ').Select(long.Parse).ToList(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs b/AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs index a80e65a..fe321d2 100644 --- a/AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs +++ b/AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs @@ -1,301 +1,301 @@ -using AdventOfCode.Utils.Models; - -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using static System.Runtime.InteropServices.JavaScript.JSType; - -namespace AdventOfCode.Problems.AOC2024.Day12; - -[ProblemInfo(2024, 12, "Garden Groups")] -internal class GardenGroups : Problem -{ - private char[][] _data = []; - - public static readonly Vec2[] DIRS = [ - new(0,1), - new(1,0), - new(0,-1), - new(-1,0), - ]; - - public override void CalculatePart1() - { - var r = FindPlots(_data); - Part1 = r.Sum(plot => plot.area.Count * plot.perimeter); - } - - public override void CalculatePart2() - { - var plots = FindPlots(_data); - var r = plots.Select(plot => (plot.plant, area: plot.area.Count, sides: CountSides(GroupSides(plot.outline, plot.area), plot.area))); - foreach (var (plant, area, perimeter, outline) in plots) - { - Console.WriteLine(); - var groups = GroupSides(outline, area); - Console.WriteLine($"{plant}: {CountSides(groups, area)}, {groups.Count}"); - DrawPlot(area, groups, plant); - } - Part2 = r.Sum(v => v.area * v.sides); - } - - public static List>> GroupSides(List> outline, List> area) - { - var result = new List>>(); - var visited = new HashSet>(); - var open = new HashSet>(outline); - - while (open.Count > 0) - { - var p = open.First(); - open.Remove(p); - if(visited.Contains(p)) - continue; - visited.Add(p); - var group = new List>() { p }; - GetGroup(p, group); - result.Add(group); - } - - void GetGroup(Vec2 point, List> group) - { - var up = DIRS[0]; - var right = DIRS[1]; - if(outline.Contains(point + up) || outline.Contains(point - up)) - { - ProcessDirection(point, up, group); - ProcessDirection(point, -up, group); - } - else if(outline.Contains(point + right) || outline.Contains(point - right)) - { - ProcessDirection(point, right, group); - ProcessDirection(point, -right, group); - } - } - - void ProcessDirection(Vec2 point, Vec2 dir, List> group) - { - var n = point + dir; - if (!outline.Contains(n) || visited.Contains(n)) - return; - //if (!area.Contains(n + dir.YX) && !area.Contains(n - dir.YX)) - // return; - visited.Add(n); - group.Add(n); - ProcessDirection(n, dir, group); - } - - return result; - - } - - public static void DrawPlot(List> area, List>> outline, char plant) - { - var (min, max) = GetBounds(outline.SelectMany(v => v).ToList()); - - int Sides(Vec2 point, List> group) - { - var s = 0; - foreach (var dir in DIRS) - { - var n = point + dir; - if (area.Contains(n)) - s++; - if(group.Count > 1 && outline.Any(g => group != g && g.Contains(n))) - s--; - } - return s; - } - - ConsoleColor[] colors = [ - ConsoleColor.Red, - ConsoleColor.DarkGreen, - ConsoleColor.Blue, - ConsoleColor.DarkRed, - ConsoleColor.Magenta, - ConsoleColor.DarkCyan, - ConsoleColor.DarkBlue, - ConsoleColor.DarkMagenta, - ConsoleColor.DarkYellow - ]; - - for (int y = min.Y; y <= max.Y; y++) - { - for (int x = min.X; x <= max.X; x++) - { - Console.ResetColor(); - var p = new Vec2(x,y); - if (area.Contains(p)) - { - Console.BackgroundColor = ConsoleColor.Black; - Console.Write(plant); - } - else - { - var curSideGroup = outline.FirstOrDefault(v => v.Contains(p)); - if (curSideGroup != null) - { - var idx = outline.IndexOf(curSideGroup); - Console.BackgroundColor = colors[idx % colors.Length]; - var s = Sides(p, curSideGroup); - if(curSideGroup.Count > 1 && IsInclosed(curSideGroup, outline, area)) - Console.Write('&'); - else - Console.Write(s); - }else - Console.Write(' '); - } - Console.ResetColor(); - } - Console.ResetColor(); - Console.WriteLine(); - } - Console.ResetColor(); - } - - public static void DrawPoints(List> data, char display) - { - var (min, max) = GetBounds(data); - - var output = new StringBuilder(); - for (int y = min.Y; y <= max.Y; y++) - { - for (int x = min.X; x <= max.X; x++) - { - var p = new Vec2(x,y); - if (data.Contains(p)) - output.Append(display); - else - output.Append(' '); - - } - output.AppendLine(); - } - Console.WriteLine(output); - } - - public static (Vec2 min, Vec2 max) GetBounds(List> points) - { - var min = Vec2.Splat(int.MaxValue); - var max = Vec2.Splat(int.MinValue); - foreach (var pos in points) - { - if (pos.X < min.X) - min.X = pos.X; - if (pos.Y < min.Y) - min.Y = pos.Y; - - if (pos.X > max.X) - max.X = pos.X; - if (pos.Y > max.Y) - max.Y = pos.Y; - } - return (min, max); - } - - public static bool IsInclosed(List> side, List>> sides, List> area) - { - var otherSides = sides.Where(g => g != side).SelectMany(s => s).ToFrozenSet(); - foreach (var point in side) - { - foreach (var dir in DIRS) - { - var n = point + dir; - if (side.Contains(n)) - continue; - if (!area.Contains(n)) - return false; - if (otherSides.Contains(n)) - return false; - } - } - return true; - } - - public static int CountSides(List>> groups, List> area) - { - int Sides(Vec2 point, List> group) - { - var s = 0; - foreach (var dir in DIRS) - { - var n = point + dir; - if(area.Contains(n)) - s++; - if (group.Count > 1 && groups.Any(g => group != g && g.Contains(n))) - s--; - } - return s; - } - return groups.Sum(s => s.Select(p => Sides(p, s)).Max() + (s.Count > 1 && IsInclosed(s, groups, area) ? 1 : 0)); - } - - private static List<(char plant, List> area, int perimeter, List> outline)> FindPlots(char[][] data) - { - var visited = new HashSet>(data.Length * data[0].Length); - - var results = new List<(char plant, List>, int perimeter, List> outline)>(); - - for (int y = 0; y < data.Length; y++) - { - var row = data[y]; - for (int x = 0; x < row.Length; x++) - { - var p = new Vec2(x, y); - if (visited.Contains(p)) - continue; - var members = new List>(); - var plant = data[y][x]; - var perimeter = 0; - var outline = new List>(); - GetMembers(data, plant, p, visited, members, ref perimeter, outline); - results.Add((plant, members, perimeter, outline)); - } - } - return results; - } - - private static void GetMembers(char[][] data, char plant, Vec2 point, HashSet> visited, List> members, ref int perimeter, List> outline) - { - if (visited.Contains(point)) - return; - visited.Add(point); - members.Add(point); - - foreach (var dir in DIRS) - { - var n = dir + point; - if (!IsInBounds(n, data)) - { - perimeter += 1; - outline.Add(n); - continue; - } - if (data[n.Y][n.X] != plant) - { - perimeter += 1; - outline.Add(n); - continue; - } - GetMembers(data, plant, n, visited, members, ref perimeter, outline); - } - } - - public static bool IsInBounds(Vec2 pos, char[][] data) - { - if (pos.X < 0 || pos.Y < 0) - return false; - if (pos.X >= data.Length || pos.Y >= data[0].Length) - return false; - return true; - } - - public override void LoadInput() - { - _data = ReadInputLines("sample3.txt").Select(ln => ln.ToCharArray()).ToArray(); - } +using AdventOfCode.Utils.Models; + +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using static System.Runtime.InteropServices.JavaScript.JSType; + +namespace AdventOfCode.Problems.AOC2024.Day12; + +[ProblemInfo(2024, 12, "Garden Groups")] +internal class GardenGroups : Problem +{ + private char[][] _data = []; + + public static readonly Vec2[] DIRS = [ + new(0,1), + new(1,0), + new(0,-1), + new(-1,0), + ]; + + public override void CalculatePart1() + { + var r = FindPlots(_data); + Part1 = r.Sum(plot => plot.area.Count * plot.perimeter); + } + + public override void CalculatePart2() + { + var plots = FindPlots(_data); + var r = plots.Select(plot => (plot.plant, area: plot.area.Count, sides: CountSides(GroupSides(plot.outline, plot.area), plot.area))); + foreach (var (plant, area, perimeter, outline) in plots) + { + Console.WriteLine(); + var groups = GroupSides(outline, area); + Console.WriteLine($"{plant}: {CountSides(groups, area)}, {groups.Count}"); + DrawPlot(area, groups, plant); + } + Part2 = r.Sum(v => v.area * v.sides); + } + + public static List>> GroupSides(List> outline, List> area) + { + var result = new List>>(); + var visited = new HashSet>(); + var open = new HashSet>(outline); + + while (open.Count > 0) + { + var p = open.First(); + open.Remove(p); + if(visited.Contains(p)) + continue; + visited.Add(p); + var group = new List>() { p }; + GetGroup(p, group); + result.Add(group); + } + + void GetGroup(Vec2 point, List> group) + { + var up = DIRS[0]; + var right = DIRS[1]; + if(outline.Contains(point + up) || outline.Contains(point - up)) + { + ProcessDirection(point, up, group); + ProcessDirection(point, -up, group); + } + else if(outline.Contains(point + right) || outline.Contains(point - right)) + { + ProcessDirection(point, right, group); + ProcessDirection(point, -right, group); + } + } + + void ProcessDirection(Vec2 point, Vec2 dir, List> group) + { + var n = point + dir; + if (!outline.Contains(n) || visited.Contains(n)) + return; + //if (!area.Contains(n + dir.YX) && !area.Contains(n - dir.YX)) + // return; + visited.Add(n); + group.Add(n); + ProcessDirection(n, dir, group); + } + + return result; + + } + + public static void DrawPlot(List> area, List>> outline, char plant) + { + var (min, max) = GetBounds(outline.SelectMany(v => v).ToList()); + + int Sides(Vec2 point, List> group) + { + var s = 0; + foreach (var dir in DIRS) + { + var n = point + dir; + if (area.Contains(n)) + s++; + if(group.Count > 1 && outline.Any(g => group != g && g.Contains(n))) + s--; + } + return s; + } + + ConsoleColor[] colors = [ + ConsoleColor.Red, + ConsoleColor.DarkGreen, + ConsoleColor.Blue, + ConsoleColor.DarkRed, + ConsoleColor.Magenta, + ConsoleColor.DarkCyan, + ConsoleColor.DarkBlue, + ConsoleColor.DarkMagenta, + ConsoleColor.DarkYellow + ]; + + for (int y = min.Y; y <= max.Y; y++) + { + for (int x = min.X; x <= max.X; x++) + { + Console.ResetColor(); + var p = new Vec2(x,y); + if (area.Contains(p)) + { + Console.BackgroundColor = ConsoleColor.Black; + Console.Write(plant); + } + else + { + var curSideGroup = outline.FirstOrDefault(v => v.Contains(p)); + if (curSideGroup != null) + { + var idx = outline.IndexOf(curSideGroup); + Console.BackgroundColor = colors[idx % colors.Length]; + var s = Sides(p, curSideGroup); + if(curSideGroup.Count > 1 && IsInclosed(curSideGroup, outline, area)) + Console.Write('&'); + else + Console.Write(s); + }else + Console.Write(' '); + } + Console.ResetColor(); + } + Console.ResetColor(); + Console.WriteLine(); + } + Console.ResetColor(); + } + + public static void DrawPoints(List> data, char display) + { + var (min, max) = GetBounds(data); + + var output = new StringBuilder(); + for (int y = min.Y; y <= max.Y; y++) + { + for (int x = min.X; x <= max.X; x++) + { + var p = new Vec2(x,y); + if (data.Contains(p)) + output.Append(display); + else + output.Append(' '); + + } + output.AppendLine(); + } + Console.WriteLine(output); + } + + public static (Vec2 min, Vec2 max) GetBounds(List> points) + { + var min = Vec2.Splat(int.MaxValue); + var max = Vec2.Splat(int.MinValue); + foreach (var pos in points) + { + if (pos.X < min.X) + min.X = pos.X; + if (pos.Y < min.Y) + min.Y = pos.Y; + + if (pos.X > max.X) + max.X = pos.X; + if (pos.Y > max.Y) + max.Y = pos.Y; + } + return (min, max); + } + + public static bool IsInclosed(List> side, List>> sides, List> area) + { + var otherSides = sides.Where(g => g != side).SelectMany(s => s).ToFrozenSet(); + foreach (var point in side) + { + foreach (var dir in DIRS) + { + var n = point + dir; + if (side.Contains(n)) + continue; + if (!area.Contains(n)) + return false; + if (otherSides.Contains(n)) + return false; + } + } + return true; + } + + public static int CountSides(List>> groups, List> area) + { + int Sides(Vec2 point, List> group) + { + var s = 0; + foreach (var dir in DIRS) + { + var n = point + dir; + if(area.Contains(n)) + s++; + if (group.Count > 1 && groups.Any(g => group != g && g.Contains(n))) + s--; + } + return s; + } + return groups.Sum(s => s.Select(p => Sides(p, s)).Max() + (s.Count > 1 && IsInclosed(s, groups, area) ? 1 : 0)); + } + + private static List<(char plant, List> area, int perimeter, List> outline)> FindPlots(char[][] data) + { + var visited = new HashSet>(data.Length * data[0].Length); + + var results = new List<(char plant, List>, int perimeter, List> outline)>(); + + for (int y = 0; y < data.Length; y++) + { + var row = data[y]; + for (int x = 0; x < row.Length; x++) + { + var p = new Vec2(x, y); + if (visited.Contains(p)) + continue; + var members = new List>(); + var plant = data[y][x]; + var perimeter = 0; + var outline = new List>(); + GetMembers(data, plant, p, visited, members, ref perimeter, outline); + results.Add((plant, members, perimeter, outline)); + } + } + return results; + } + + private static void GetMembers(char[][] data, char plant, Vec2 point, HashSet> visited, List> members, ref int perimeter, List> outline) + { + if (visited.Contains(point)) + return; + visited.Add(point); + members.Add(point); + + foreach (var dir in DIRS) + { + var n = dir + point; + if (!IsInBounds(n, data)) + { + perimeter += 1; + outline.Add(n); + continue; + } + if (data[n.Y][n.X] != plant) + { + perimeter += 1; + outline.Add(n); + continue; + } + GetMembers(data, plant, n, visited, members, ref perimeter, outline); + } + } + + public static bool IsInBounds(Vec2 pos, char[][] data) + { + if (pos.X < 0 || pos.Y < 0) + return false; + if (pos.X >= data.Length || pos.Y >= data[0].Length) + return false; + return true; + } + + public override void LoadInput() + { + _data = ReadInputLines("sample3.txt").Select(ln => ln.ToCharArray()).ToArray(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2024/Day2/RedNosedReports.cs b/AdventOfCode/Problems/AOC2024/Day2/RedNosedReports.cs index b223ecd..1bcbdaa 100644 --- a/AdventOfCode/Problems/AOC2024/Day2/RedNosedReports.cs +++ b/AdventOfCode/Problems/AOC2024/Day2/RedNosedReports.cs @@ -1,107 +1,107 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2024.Day2; -[ProblemInfo(2024, 2, "Red-Nosed Reports")] -internal class RedNosedReports : Problem -{ - private int[][] _data = []; - - private static bool CheckIncrease(int l) => l >= 1 && l <= 3; - private static bool CheckDecrease(int l) => l <= -1 && l >= -3; - - public override void CalculatePart1() - { - var reportAnalysis = Analyze(); - var increasing = reportAnalysis.Count(r => r.All(CheckIncrease)); - var decreasing = reportAnalysis.Count(r => r.All(CheckDecrease)); - Part1 = increasing + decreasing; - } - - public override void CalculatePart2() - { - Console.WriteLine(); - foreach (var report in _data) - { - if (CheckSafety(report, out _)) - Part2++; - } - } - - private static bool CheckSafety(int[] report, out bool increase) - { - increase = false; - var inFail = Check(report, CheckIncrease); - var deFail = Check(report, CheckDecrease); - - if(inFail.Count == 0) - { - increase = true; - return true; - } - else - { - if (inFail.Count < report.Length && RemoveFails(report, inFail).Any(g => Check(g, CheckIncrease).Count == 0)) - { - increase = true; - return true; - } - } - if(deFail.Count == 0) - return true; - else - { - if (deFail.Count < report.Length && RemoveFails(report, deFail).Any(g => Check(g, CheckDecrease).Count == 0)) - return true; - } - return false; - } - - static int[][] RemoveFails(int[] report, List fails) - { - var results = new int[fails.Count][]; - for (int i = 0; i < fails.Count; i++) - { - var f = fails[i]; - results[i] = f == 0 ? report[1..] : f == report.Length-1 ? report[..^1] : [.. report[..f], .. report[(f+1)..]]; - } - return results; - } - - static List Check(int[] report, Func check) - { - var fails = new List(); - for (int i = 1; i < report.Length; i++) - { - var d = report[i] - report[i-1]; - if (!check(d)) - fails.AddRange([i, i-1]); - } - - return fails.Distinct().ToList(); - } - - private int[][] Analyze() - { - var reportAnalysis = new int[_data.Length][]; - for (int ridx = 0; ridx < _data.Length; ridx++) - { - int[]? report = _data[ridx]; - var safety = new int[report.Length - 1]; - for (int i = 1; i < report.Length; i++) - safety[i - 1] = report[i] - report[i - 1]; - reportAnalysis[ridx] = safety; - } - return reportAnalysis; - } - - public override void LoadInput() - { - _data = ReadInputLines("input.txt").Select(l => l.Split(' ').Select(int.Parse).ToArray()).ToArray(); - } -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2024.Day2; +[ProblemInfo(2024, 2, "Red-Nosed Reports")] +internal class RedNosedReports : Problem +{ + private int[][] _data = []; + + private static bool CheckIncrease(int l) => l >= 1 && l <= 3; + private static bool CheckDecrease(int l) => l <= -1 && l >= -3; + + public override void CalculatePart1() + { + var reportAnalysis = Analyze(); + var increasing = reportAnalysis.Count(r => r.All(CheckIncrease)); + var decreasing = reportAnalysis.Count(r => r.All(CheckDecrease)); + Part1 = increasing + decreasing; + } + + public override void CalculatePart2() + { + Console.WriteLine(); + foreach (var report in _data) + { + if (CheckSafety(report, out _)) + Part2++; + } + } + + private static bool CheckSafety(int[] report, out bool increase) + { + increase = false; + var inFail = Check(report, CheckIncrease); + var deFail = Check(report, CheckDecrease); + + if(inFail.Count == 0) + { + increase = true; + return true; + } + else + { + if (inFail.Count < report.Length && RemoveFails(report, inFail).Any(g => Check(g, CheckIncrease).Count == 0)) + { + increase = true; + return true; + } + } + if(deFail.Count == 0) + return true; + else + { + if (deFail.Count < report.Length && RemoveFails(report, deFail).Any(g => Check(g, CheckDecrease).Count == 0)) + return true; + } + return false; + } + + static int[][] RemoveFails(int[] report, List fails) + { + var results = new int[fails.Count][]; + for (int i = 0; i < fails.Count; i++) + { + var f = fails[i]; + results[i] = f == 0 ? report[1..] : f == report.Length-1 ? report[..^1] : [.. report[..f], .. report[(f+1)..]]; + } + return results; + } + + static List Check(int[] report, Func check) + { + var fails = new List(); + for (int i = 1; i < report.Length; i++) + { + var d = report[i] - report[i-1]; + if (!check(d)) + fails.AddRange([i, i-1]); + } + + return fails.Distinct().ToList(); + } + + private int[][] Analyze() + { + var reportAnalysis = new int[_data.Length][]; + for (int ridx = 0; ridx < _data.Length; ridx++) + { + int[]? report = _data[ridx]; + var safety = new int[report.Length - 1]; + for (int i = 1; i < report.Length; i++) + safety[i - 1] = report[i] - report[i - 1]; + reportAnalysis[ridx] = safety; + } + return reportAnalysis; + } + + public override void LoadInput() + { + _data = ReadInputLines("input.txt").Select(l => l.Split(' ').Select(int.Parse).ToArray()).ToArray(); + } +} diff --git a/AdventOfCode/Problems/AOC2024/Day3/MullItOver.cs b/AdventOfCode/Problems/AOC2024/Day3/MullItOver.cs index 80ea1c4..ef74be0 100644 --- a/AdventOfCode/Problems/AOC2024/Day3/MullItOver.cs +++ b/AdventOfCode/Problems/AOC2024/Day3/MullItOver.cs @@ -1,54 +1,54 @@ -using AdventOfCode.Runner.Attributes; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace AdventOfCode.Problems.AOC2024.Day3; -[ProblemInfo(2024, 3, "Mull It Over")] -internal partial class MullItOver : Problem -{ - private string _data = string.Empty; - - public override void CalculatePart1() - { - var matches = Mul().Matches(_data); - Part1 = matches.Select(m => (int.Parse(m.Groups["a"].ValueSpan), int.Parse(m.Groups["b"].ValueSpan))).Select(v => v.Item1 * v.Item2).Sum(); - } - - public override void CalculatePart2() - { - var doing = true; - var muls = DosAndDonts().Matches(_data); - foreach (Match match in muls) - { - switch (match.ValueSpan) - { - case ['d', 'o', 'n', ..]: - doing = false; - break; - case ['d', 'o', ..]: - doing = true; - break; - default: - if (!doing) - continue; - Part2 += int.Parse(match.Groups["a"].ValueSpan) * int.Parse(match.Groups["b"].ValueSpan); - break; - } - } - } - - public override void LoadInput() - { - _data = ReadInputText("input.txt"); - } - - [GeneratedRegex("(mul\\((?\\d+)\\,(?\\d+)\\))|(do\\(\\))|(don't\\(\\))")] - private static partial Regex DosAndDonts(); - [GeneratedRegex("mul\\((?\\d+)\\,(?\\d+)\\)")] - private static partial Regex Mul(); -} +using AdventOfCode.Runner.Attributes; + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace AdventOfCode.Problems.AOC2024.Day3; +[ProblemInfo(2024, 3, "Mull It Over")] +internal partial class MullItOver : Problem +{ + private string _data = string.Empty; + + public override void CalculatePart1() + { + var matches = Mul().Matches(_data); + Part1 = matches.Select(m => (int.Parse(m.Groups["a"].ValueSpan), int.Parse(m.Groups["b"].ValueSpan))).Select(v => v.Item1 * v.Item2).Sum(); + } + + public override void CalculatePart2() + { + var doing = true; + var muls = DosAndDonts().Matches(_data); + foreach (Match match in muls) + { + switch (match.ValueSpan) + { + case ['d', 'o', 'n', ..]: + doing = false; + break; + case ['d', 'o', ..]: + doing = true; + break; + default: + if (!doing) + continue; + Part2 += int.Parse(match.Groups["a"].ValueSpan) * int.Parse(match.Groups["b"].ValueSpan); + break; + } + } + } + + public override void LoadInput() + { + _data = ReadInputText("input.txt"); + } + + [GeneratedRegex("(mul\\((?\\d+)\\,(?\\d+)\\))|(do\\(\\))|(don't\\(\\))")] + private static partial Regex DosAndDonts(); + [GeneratedRegex("mul\\((?\\d+)\\,(?\\d+)\\)")] + private static partial Regex Mul(); +} diff --git a/AdventOfCode/Problems/AOC2024/Day4/CeresSearch.cs b/AdventOfCode/Problems/AOC2024/Day4/CeresSearch.cs index 291f98c..7a734d7 100644 --- a/AdventOfCode/Problems/AOC2024/Day4/CeresSearch.cs +++ b/AdventOfCode/Problems/AOC2024/Day4/CeresSearch.cs @@ -1,127 +1,127 @@ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Pos = (int x, int y); - -namespace AdventOfCode.Problems.AOC2024.Day4; -[ProblemInfo(2024, 4, "Ceres Search")] -internal class CeresSearch : Problem -{ - - private string[] _data = []; - private static readonly Pos[] dirs = [ - (-1, 0), //Left - (-1, -1), //Top Left - (0, -1), //Top - (1, -1), //Top Right - (1, 0), //Right - (1, 1), //Bottom Right - (0, 1), //Bottom - (-1, 1), //Bottom Left - ]; - - private static readonly Pos[] xdirs = [ - (-1, -1), //Top Left - (1, -1), //Top Right - (1, 1), //Bottom Right - (-1, 1), //Bottom Left - ]; - - public override void CalculatePart1() - { - Part1 = FindWord(_data, "XMAS"); - } - - public override void CalculatePart2() - { - Part2 = FindXWord(_data, "MAS"); - } - public override void LoadInput() - { - _data = ReadInputLines("input.txt"); - } - - private static int FindXWord(string[] data, string target) - { - var matches = 0; - var pivot = target.Length / 2; - var tgt = target[pivot]; - var branchA = string.Join("", target[..(pivot+1)].Reverse()); - var branchB = target[pivot..]; - for (int y = 1; y < data.Length-1; y++) - { - var row = data[y]; - for (int x = 1; x < row.Length-1; x++) - { - var c = row[x]; - if (c == tgt) - { - for (int i = 0; i < xdirs.Length; i++) - { - Pos dir = xdirs[i]; - Pos opposingDir = xdirs[(i + 2) % xdirs.Length]; - - if (CheckWord(data, (x, y), dir, branchA, 1) && CheckWord(data, (x,y), opposingDir, branchB, 1)) - { - Pos dir2 = xdirs[(i+1) % xdirs.Length]; - Pos opposingDir2 = xdirs[(i + 3) % xdirs.Length]; - if (CheckWord(data, (x, y), dir2, branchA, 1) && CheckWord(data, (x, y), opposingDir2, branchB, 1)) - matches++; - } - } - } - } - } - return matches; - } - - private static int FindWord(string[] data, string target) - { - var matches = 0; - var tgt = target[0]; - for (int y = 0; y < data.Length; y++) - { - var row = data[y]; - for (int x = 0; x < row.Length; x++) - { - var c = row[x]; - if(c == tgt) - { - foreach (var dir in dirs) - { - if(CheckWord(data, (x, y), dir, target, 1)) - matches++; - } - } - } - } - return matches; - } - - private static bool CheckWord(string[] data, Pos pos, Pos dir, string target, int targetPos) - { - Pos curPos = (pos.x + dir.x, pos.y + dir.y); - - - if(curPos.y < 0 || curPos.y >= data.Length) - return false; - if (curPos.x < 0 || curPos.x >= data[0].Length) - return false; - - var c = data[curPos.y][curPos.x]; - if(c == target[targetPos]) - { - if (targetPos == target.Length - 1) - return true; - return CheckWord(data, curPos, dir, target, targetPos + 1); - } - return false; - } - - - -} + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Pos = (int x, int y); + +namespace AdventOfCode.Problems.AOC2024.Day4; +[ProblemInfo(2024, 4, "Ceres Search")] +internal class CeresSearch : Problem +{ + + private string[] _data = []; + private static readonly Pos[] dirs = [ + (-1, 0), //Left + (-1, -1), //Top Left + (0, -1), //Top + (1, -1), //Top Right + (1, 0), //Right + (1, 1), //Bottom Right + (0, 1), //Bottom + (-1, 1), //Bottom Left + ]; + + private static readonly Pos[] xdirs = [ + (-1, -1), //Top Left + (1, -1), //Top Right + (1, 1), //Bottom Right + (-1, 1), //Bottom Left + ]; + + public override void CalculatePart1() + { + Part1 = FindWord(_data, "XMAS"); + } + + public override void CalculatePart2() + { + Part2 = FindXWord(_data, "MAS"); + } + public override void LoadInput() + { + _data = ReadInputLines("input.txt"); + } + + private static int FindXWord(string[] data, string target) + { + var matches = 0; + var pivot = target.Length / 2; + var tgt = target[pivot]; + var branchA = string.Join("", target[..(pivot+1)].Reverse()); + var branchB = target[pivot..]; + for (int y = 1; y < data.Length-1; y++) + { + var row = data[y]; + for (int x = 1; x < row.Length-1; x++) + { + var c = row[x]; + if (c == tgt) + { + for (int i = 0; i < xdirs.Length; i++) + { + Pos dir = xdirs[i]; + Pos opposingDir = xdirs[(i + 2) % xdirs.Length]; + + if (CheckWord(data, (x, y), dir, branchA, 1) && CheckWord(data, (x,y), opposingDir, branchB, 1)) + { + Pos dir2 = xdirs[(i+1) % xdirs.Length]; + Pos opposingDir2 = xdirs[(i + 3) % xdirs.Length]; + if (CheckWord(data, (x, y), dir2, branchA, 1) && CheckWord(data, (x, y), opposingDir2, branchB, 1)) + matches++; + } + } + } + } + } + return matches; + } + + private static int FindWord(string[] data, string target) + { + var matches = 0; + var tgt = target[0]; + for (int y = 0; y < data.Length; y++) + { + var row = data[y]; + for (int x = 0; x < row.Length; x++) + { + var c = row[x]; + if(c == tgt) + { + foreach (var dir in dirs) + { + if(CheckWord(data, (x, y), dir, target, 1)) + matches++; + } + } + } + } + return matches; + } + + private static bool CheckWord(string[] data, Pos pos, Pos dir, string target, int targetPos) + { + Pos curPos = (pos.x + dir.x, pos.y + dir.y); + + + if(curPos.y < 0 || curPos.y >= data.Length) + return false; + if (curPos.x < 0 || curPos.x >= data[0].Length) + return false; + + var c = data[curPos.y][curPos.x]; + if(c == target[targetPos]) + { + if (targetPos == target.Length - 1) + return true; + return CheckWord(data, curPos, dir, target, targetPos + 1); + } + return false; + } + + + +} diff --git a/AdventOfCode/Problems/AOC2024/Day5/PageList.cs b/AdventOfCode/Problems/AOC2024/Day5/PageList.cs index eb7dc4a..f91330a 100644 --- a/AdventOfCode/Problems/AOC2024/Day5/PageList.cs +++ b/AdventOfCode/Problems/AOC2024/Day5/PageList.cs @@ -1,96 +1,96 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Rule = (int after, int before); - - -namespace AdventOfCode.Problems.AOC2024.Day5; -internal class PageList -{ - private readonly List _rules; - private PageNode _root; - - public PageList(int[] pages, List rules) - { - _rules = rules.Where(r => pages.Contains(r.before)).ToList(); - _root = new PageNode(pages[0], GetRulesForPage(pages[0])); - for (int i = 1; i < pages.Length; i++) - AddPage(pages[i]); - } - - public void AddPage(int page) - { - var node = new PageNode(page, GetRulesForPage(page)); - if(node.IsBefore(_root)) - { - node.NextNode = _root; - _root = node; - return; - } - var curNode = _root; - while(curNode != null) - { - if(curNode.IsBefore(node)) - { - if(curNode.NextNode == null) - { - curNode.NextNode = node; - break; - } - else if(node.IsBefore(curNode.NextNode)) - { - node.NextNode = curNode.NextNode; - curNode.NextNode = node; - break; - } - - } - curNode = curNode.NextNode; - } - } - - public List GetRulesForPage(int page) - { - return _rules.Where(r => r.after == page).ToList(); - } - - public List Traverse() - { - var list = new List(); - var curNode = _root; - while(curNode != null) - { - list.Add(curNode.Page); - curNode = curNode.NextNode; - } - return list; - } -} - - -internal class PageNode -{ - public int Page { get; set; } - public int[] Before { get; set; } - public PageNode? NextNode { get; set; } - - public PageNode(int page, List rules) - { - Page = page; - Before = rules.Count == 0 ? [int.MinValue] : rules.Select(r => r.before).ToArray(); - } - - public override string ToString() - { - return $"{Page} << {Before}"; - } - - public bool IsBefore(PageNode other) - { - if(Before.Any(b => b == other.Page)) - return true; - return false; - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Rule = (int after, int before); + + +namespace AdventOfCode.Problems.AOC2024.Day5; +internal class PageList +{ + private readonly List _rules; + private PageNode _root; + + public PageList(int[] pages, List rules) + { + _rules = rules.Where(r => pages.Contains(r.before)).ToList(); + _root = new PageNode(pages[0], GetRulesForPage(pages[0])); + for (int i = 1; i < pages.Length; i++) + AddPage(pages[i]); + } + + public void AddPage(int page) + { + var node = new PageNode(page, GetRulesForPage(page)); + if(node.IsBefore(_root)) + { + node.NextNode = _root; + _root = node; + return; + } + var curNode = _root; + while(curNode != null) + { + if(curNode.IsBefore(node)) + { + if(curNode.NextNode == null) + { + curNode.NextNode = node; + break; + } + else if(node.IsBefore(curNode.NextNode)) + { + node.NextNode = curNode.NextNode; + curNode.NextNode = node; + break; + } + + } + curNode = curNode.NextNode; + } + } + + public List GetRulesForPage(int page) + { + return _rules.Where(r => r.after == page).ToList(); + } + + public List Traverse() + { + var list = new List(); + var curNode = _root; + while(curNode != null) + { + list.Add(curNode.Page); + curNode = curNode.NextNode; + } + return list; + } +} + + +internal class PageNode +{ + public int Page { get; set; } + public int[] Before { get; set; } + public PageNode? NextNode { get; set; } + + public PageNode(int page, List rules) + { + Page = page; + Before = rules.Count == 0 ? [int.MinValue] : rules.Select(r => r.before).ToArray(); + } + + public override string ToString() + { + return $"{Page} << {Before}"; + } + + public bool IsBefore(PageNode other) + { + if(Before.Any(b => b == other.Page)) + return true; + return false; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2024/Day5/PrintQueue.cs b/AdventOfCode/Problems/AOC2024/Day5/PrintQueue.cs index f91dc22..bfd48b3 100644 --- a/AdventOfCode/Problems/AOC2024/Day5/PrintQueue.cs +++ b/AdventOfCode/Problems/AOC2024/Day5/PrintQueue.cs @@ -1,77 +1,77 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Rule = (int after, int before); - - -namespace AdventOfCode.Problems.AOC2024.Day5; -[ProblemInfo(2024, 5, "Print Queue")] -internal class PrintQueue : Problem -{ - private List _rules = []; - private List updates = []; - public override void CalculatePart1() - { - foreach (var update in updates) - { - if (IsOrdered(update, out _)) - { - var mid = update[update.Length / 2]; - Part1 += mid; - } - } - } - - public bool IsOrdered(int[] update, out List orderd) - { - var list = new PageList(update, _rules); - orderd = list.Traverse(); - return orderd.Zip(update).All(e => e.First== e.Second); - - } - - public int[] SortUpdates(int[] updates) - { - throw new NotImplementedException(); - } - - public override void CalculatePart2() - { - foreach (var update in updates) - { - if (!IsOrdered(update, out var ordered)) - { - var mid = ordered[update.Length / 2]; - Part2 += mid; - } - } - } - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - - var parsingPages = false; - foreach (var line in lines) - { - if (string.IsNullOrWhiteSpace(line)) - { - parsingPages = true; - continue; - } - if (parsingPages) - { - updates.Add(line.Split(',').Select(int.Parse).ToArray()); - } - else{ - var d = line.Split('|').Select(int.Parse); - _rules.Add((d.First(), d.Last())); - } - } - - } -} - - +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Rule = (int after, int before); + + +namespace AdventOfCode.Problems.AOC2024.Day5; +[ProblemInfo(2024, 5, "Print Queue")] +internal class PrintQueue : Problem +{ + private List _rules = []; + private List updates = []; + public override void CalculatePart1() + { + foreach (var update in updates) + { + if (IsOrdered(update, out _)) + { + var mid = update[update.Length / 2]; + Part1 += mid; + } + } + } + + public bool IsOrdered(int[] update, out List orderd) + { + var list = new PageList(update, _rules); + orderd = list.Traverse(); + return orderd.Zip(update).All(e => e.First== e.Second); + + } + + public int[] SortUpdates(int[] updates) + { + throw new NotImplementedException(); + } + + public override void CalculatePart2() + { + foreach (var update in updates) + { + if (!IsOrdered(update, out var ordered)) + { + var mid = ordered[update.Length / 2]; + Part2 += mid; + } + } + } + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + + var parsingPages = false; + foreach (var line in lines) + { + if (string.IsNullOrWhiteSpace(line)) + { + parsingPages = true; + continue; + } + if (parsingPages) + { + updates.Add(line.Split(',').Select(int.Parse).ToArray()); + } + else{ + var d = line.Split('|').Select(int.Parse); + _rules.Add((d.First(), d.Last())); + } + } + + } +} + + diff --git a/AdventOfCode/Problems/AOC2024/Day6/GuardGallivant.cs b/AdventOfCode/Problems/AOC2024/Day6/GuardGallivant.cs index 8172806..027002c 100644 --- a/AdventOfCode/Problems/AOC2024/Day6/GuardGallivant.cs +++ b/AdventOfCode/Problems/AOC2024/Day6/GuardGallivant.cs @@ -1,392 +1,392 @@ -using AdventOfCode.Utils.Models; - -using System; -using System.Collections.Frozen; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -using Turn = (AdventOfCode.Utils.Models.Vec2 pos, int dir, int step); - -namespace AdventOfCode.Problems.AOC2024.Day6; - -[ProblemInfo(2024, 6, "Guard Gallivant")] -internal class GuardGallivant : Problem -{ - private char[][] _data = []; - private int _height; - private int _width; - public static readonly Vec2[] DIRS = [ - new (0, -1), - new (1, 0), - new (0, 1), - new (-1, 0), - ]; - - public override void CalculatePart1() - { - var map = new GuardMap(_data, GetStartPos()); - Part1 = map.GetPath().DistinctBy(p => p.pos).Count(); - } - - //this does not work - public override void CalculatePart2() - { - var start = GetStartPos(); - var map = new GuardMap(_data, start); - var path = map.GetPath(); - var visited = path.Select(p => p.pos).ToFrozenSet(); - var nodes = new List(); - var found = new HashSet>(); - foreach (var (pos, node) in path) - { - var turn = (node.Direction + 1) % 4; - if (pos == start) - continue; - if (map.GetNextObstacle(pos, turn, out var next)) - { - var obstacleNode = new GuardNode(pos, turn, 0); - var obstaclePos = pos + DIRS[node.Direction]; - if (!IsInBounds(obstaclePos)) - continue; - if (map.SolveNewPath(obstacleNode, pos + DIRS[node.Direction], nodes)) - { - if (!found.Contains(obstaclePos)) - { - Part2++; - //map.PrintBoard(nodes, pos, obstaclePos); - //Console.ReadLine(); - } - found.Add(obstaclePos); - } - } - } - } - - private Vec2 GetStartPos() - { - for (int y = 0; y < _data.Length; y++) - { - var row = _data[y]; - for (int x = 0; x < row.Length; x++) - { - if (row[x] == '^') - return new(x, y); - } - } - throw new Exception("Start Position not found"); - } - - private bool IsInBounds(Vec2 pos) - { - if (pos.X < 0 || pos.Y < 0) - return false; - if (pos.X >= _width || pos.Y >= _height) - return false; - return true; - } - - public override void LoadInput() - { - _data = ReadInputLines("input.txt").Select(r => r.ToCharArray()).ToArray(); - _height = _data.Length; - _width = _data[0].Length; - } -} - -file class GuardMap -{ - public List Nodes { get; set; } - private readonly bool[][] _map; - - private readonly int _height; - private readonly int _width; - - public GuardMap(char[][] map, Vec2 start) - { - _map = map.Select(r => r.Select(c => c == '#' ? true : false).ToArray()).ToArray(); - _height = map.Length; - _width = map[0].Length; - var startNode = new GuardNode(start, 0, 0); - Nodes = [startNode]; - Solve(); - } - - public List<(Vec2 pos, GuardNode node)> GetPath() - { - return GetPath(Nodes); - } - - public FrozenSet> GetPathSet(List nodes) - { - var path = GetPath(nodes); - return path.Select(p => p.pos).ToFrozenSet(); - } - - public List<(Vec2 pos, GuardNode node)> GetPath(List nodes) - { - var path = new List<(Vec2, GuardNode)>(); - - var curNode = nodes[0]; - while (true) - { - if (curNode.Next is int nextId && nextId >= 0) - { - var next = nodes[nextId]; - path.AddRange(GetPointsBetween(curNode.Pos, next.Pos, curNode.Direction).Select(p => (p, curNode))); - curNode = next; - } - else if (curNode.Next == -1) - { - var end = curNode.Direction switch - { - 0 => new Vec2(curNode.Pos.X, -1), - 1 => new Vec2(_width, curNode.Pos.Y), - 2 => new Vec2(curNode.Pos.X, _height), - 3 => new Vec2(-1, curNode.Pos.Y), - _ => throw new InvalidOperationException() - }; - path.AddRange(GetPointsBetween(curNode.Pos, end, curNode.Direction).Select(p => (p, curNode))); - break; - } - else - break; - } - - return path; - } - - private List> GetPointsBetween(Vec2 start, Vec2 end, int dir) - { - var result = new List>(); - switch (dir) - { - case 0: - for (int i = start.Y; i > end.Y; i--) - result.Add(new Vec2(start.X, i)); - break; - - case 1: - for (int i = start.X; i < end.X; i++) - result.Add(new Vec2(i, start.Y)); - break; - - case 2: - for (int i = start.Y; i < end.Y; i++) - result.Add(new Vec2(start.X, i)); - break; - - case 3: - for (int i = start.X; i > end.X; i--) - result.Add(new Vec2(i, start.Y)); - break; - } - - return result; - } - - private void Solve() - { - var curNode = Nodes[0]; - while (true) - { - if (!GetNextObstacle(curNode.Pos, curNode.Direction, out var next)) - { - curNode.Next = -1; - Nodes[curNode.Id] = curNode; - break; - } - var newNode = new GuardNode(next - GuardGallivant.DIRS[curNode.Direction], (curNode.Direction + 1) % 4, Nodes.Count); - curNode.Next = newNode.Id; - Nodes[curNode.Id] = curNode; - Nodes.Add(newNode); - curNode = newNode; - } - } - - public bool SolveNewPath(GuardNode start, Vec2 extraObsticle, List nodes) - { - var curNode = start; - nodes.Clear(); - nodes.Add(start); - while (true) - { - if (!GetNextObstacle(curNode.Pos, curNode.Direction, out var next, extraObsticle)) - return false; - var newNode = new GuardNode(next - GuardGallivant.DIRS[curNode.Direction], (curNode.Direction + 1) % 4, nodes.Count); - if (nodes.Any(n => n.Pos == newNode.Pos && n.Direction == newNode.Direction)) - { - return true; - } - curNode.Next = newNode.Id; - nodes[curNode.Id] = curNode; - curNode = newNode; - nodes.Add(newNode); - } - } - - public bool GetNextObstacle(Vec2 start, int dir, out Vec2 pos, Vec2? extraObsticle = null) - { - if (extraObsticle is Vec2 ex) - _map[ex.Y][ex.X] = true; - pos = default; - - var (sX, sY) = start; - switch (dir) - { - case 0: - for (int y = sY; y >= 0; y--) - { - if (_map[y][sX]) - { - pos = new(sX, y); - ResetExtraObsticle(); - return true; - } - } - break; - - case 1: - var rowRight = _map[sY]; - for (int x = sX; x < _width; x++) - { - if (rowRight[x]) - { - pos = new(x, sY); - ResetExtraObsticle(); - return true; - } - } - break; - - case 2: - for (int y = sY; y < _height; y++) - { - if (_map[y][sX]) - { - pos = new(sX, y); - ResetExtraObsticle(); - return true; - } - } - break; - - case 3: - var rowLeft = _map[sY]; - for (int x = sX; x >= 0; x--) - { - if (rowLeft[x]) - { - pos = new(x, sY); - ResetExtraObsticle(); - return true; - } - } - break; - } - - void ResetExtraObsticle() - { - if (extraObsticle is Vec2 ex) - _map[ex.Y][ex.X] = false; - } - ResetExtraObsticle(); - return false; - } - - public void PrintBoard(List nodes, Vec2 start, Vec2? extraObsticle = null) - { - var path = GetPathSet(nodes); - for (int y = 0; y < _height; y++) - { - for (int x = 0; x < _width; x++) - { - Console.ResetColor(); - var p = new Vec2(x, y); - var node = nodes.FirstOrDefault(n => n.Pos == p, new GuardNode(p, 0, -1)); - if (node.Id != -1) - { - Console.ForegroundColor = ConsoleColor.Green; - if (node.Id == 0) - Console.ForegroundColor = ConsoleColor.Yellow; - else if (node.Id == nodes.Count - 1) - Console.ForegroundColor = ConsoleColor.Red; - switch (node.Direction) - { - case 0: - Console.Write('^'); - break; - - case 1: - Console.Write('>'); - break; - - case 2: - Console.Write('v'); - break; - - case 3: - Console.Write('<'); - break; - } - continue; - } - if (p == start) - { - Console.ForegroundColor = ConsoleColor.Magenta; - Console.Write('S'); - } - if (_map[y][x]) - Console.Write('#'); - else if (p == extraObsticle) - { - Console.ForegroundColor = ConsoleColor.DarkBlue; - Console.Write('$'); - } - else if (path.Contains(p)) - { - Console.ForegroundColor = ConsoleColor.DarkGray; - Console.Write('.'); - } - else - Console.Write(' '); - } - Console.WriteLine(); - } - } -} - -file struct GuardNode -{ - public int Id { get; private set; } - public Vec2 Pos { get; } - public int Direction { get; } - public int? Next { get; set; } - public GuardNode(Vec2 pos, int dir, int id) - { - Pos = pos; - Direction = dir; - Id = id; - } - - public bool IsLoop(List nodes) - { - return NodeExists(Id, nodes); - } - - public bool NodeExists(int target, List nodes) - { - if (Next == target) - return true; - if (Next is int id) - return nodes[id].NodeExists(target, nodes); - return false; - } - - public override string ToString() - { - return $"{Pos}: {Direction}"; - } +using AdventOfCode.Utils.Models; + +using System; +using System.Collections.Frozen; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using Turn = (AdventOfCode.Utils.Models.Vec2 pos, int dir, int step); + +namespace AdventOfCode.Problems.AOC2024.Day6; + +[ProblemInfo(2024, 6, "Guard Gallivant")] +internal class GuardGallivant : Problem +{ + private char[][] _data = []; + private int _height; + private int _width; + public static readonly Vec2[] DIRS = [ + new (0, -1), + new (1, 0), + new (0, 1), + new (-1, 0), + ]; + + public override void CalculatePart1() + { + var map = new GuardMap(_data, GetStartPos()); + Part1 = map.GetPath().DistinctBy(p => p.pos).Count(); + } + + //this does not work + public override void CalculatePart2() + { + var start = GetStartPos(); + var map = new GuardMap(_data, start); + var path = map.GetPath(); + var visited = path.Select(p => p.pos).ToFrozenSet(); + var nodes = new List(); + var found = new HashSet>(); + foreach (var (pos, node) in path) + { + var turn = (node.Direction + 1) % 4; + if (pos == start) + continue; + if (map.GetNextObstacle(pos, turn, out var next)) + { + var obstacleNode = new GuardNode(pos, turn, 0); + var obstaclePos = pos + DIRS[node.Direction]; + if (!IsInBounds(obstaclePos)) + continue; + if (map.SolveNewPath(obstacleNode, pos + DIRS[node.Direction], nodes)) + { + if (!found.Contains(obstaclePos)) + { + Part2++; + //map.PrintBoard(nodes, pos, obstaclePos); + //Console.ReadLine(); + } + found.Add(obstaclePos); + } + } + } + } + + private Vec2 GetStartPos() + { + for (int y = 0; y < _data.Length; y++) + { + var row = _data[y]; + for (int x = 0; x < row.Length; x++) + { + if (row[x] == '^') + return new(x, y); + } + } + throw new Exception("Start Position not found"); + } + + private bool IsInBounds(Vec2 pos) + { + if (pos.X < 0 || pos.Y < 0) + return false; + if (pos.X >= _width || pos.Y >= _height) + return false; + return true; + } + + public override void LoadInput() + { + _data = ReadInputLines("input.txt").Select(r => r.ToCharArray()).ToArray(); + _height = _data.Length; + _width = _data[0].Length; + } +} + +file class GuardMap +{ + public List Nodes { get; set; } + private readonly bool[][] _map; + + private readonly int _height; + private readonly int _width; + + public GuardMap(char[][] map, Vec2 start) + { + _map = map.Select(r => r.Select(c => c == '#' ? true : false).ToArray()).ToArray(); + _height = map.Length; + _width = map[0].Length; + var startNode = new GuardNode(start, 0, 0); + Nodes = [startNode]; + Solve(); + } + + public List<(Vec2 pos, GuardNode node)> GetPath() + { + return GetPath(Nodes); + } + + public FrozenSet> GetPathSet(List nodes) + { + var path = GetPath(nodes); + return path.Select(p => p.pos).ToFrozenSet(); + } + + public List<(Vec2 pos, GuardNode node)> GetPath(List nodes) + { + var path = new List<(Vec2, GuardNode)>(); + + var curNode = nodes[0]; + while (true) + { + if (curNode.Next is int nextId && nextId >= 0) + { + var next = nodes[nextId]; + path.AddRange(GetPointsBetween(curNode.Pos, next.Pos, curNode.Direction).Select(p => (p, curNode))); + curNode = next; + } + else if (curNode.Next == -1) + { + var end = curNode.Direction switch + { + 0 => new Vec2(curNode.Pos.X, -1), + 1 => new Vec2(_width, curNode.Pos.Y), + 2 => new Vec2(curNode.Pos.X, _height), + 3 => new Vec2(-1, curNode.Pos.Y), + _ => throw new InvalidOperationException() + }; + path.AddRange(GetPointsBetween(curNode.Pos, end, curNode.Direction).Select(p => (p, curNode))); + break; + } + else + break; + } + + return path; + } + + private List> GetPointsBetween(Vec2 start, Vec2 end, int dir) + { + var result = new List>(); + switch (dir) + { + case 0: + for (int i = start.Y; i > end.Y; i--) + result.Add(new Vec2(start.X, i)); + break; + + case 1: + for (int i = start.X; i < end.X; i++) + result.Add(new Vec2(i, start.Y)); + break; + + case 2: + for (int i = start.Y; i < end.Y; i++) + result.Add(new Vec2(start.X, i)); + break; + + case 3: + for (int i = start.X; i > end.X; i--) + result.Add(new Vec2(i, start.Y)); + break; + } + + return result; + } + + private void Solve() + { + var curNode = Nodes[0]; + while (true) + { + if (!GetNextObstacle(curNode.Pos, curNode.Direction, out var next)) + { + curNode.Next = -1; + Nodes[curNode.Id] = curNode; + break; + } + var newNode = new GuardNode(next - GuardGallivant.DIRS[curNode.Direction], (curNode.Direction + 1) % 4, Nodes.Count); + curNode.Next = newNode.Id; + Nodes[curNode.Id] = curNode; + Nodes.Add(newNode); + curNode = newNode; + } + } + + public bool SolveNewPath(GuardNode start, Vec2 extraObsticle, List nodes) + { + var curNode = start; + nodes.Clear(); + nodes.Add(start); + while (true) + { + if (!GetNextObstacle(curNode.Pos, curNode.Direction, out var next, extraObsticle)) + return false; + var newNode = new GuardNode(next - GuardGallivant.DIRS[curNode.Direction], (curNode.Direction + 1) % 4, nodes.Count); + if (nodes.Any(n => n.Pos == newNode.Pos && n.Direction == newNode.Direction)) + { + return true; + } + curNode.Next = newNode.Id; + nodes[curNode.Id] = curNode; + curNode = newNode; + nodes.Add(newNode); + } + } + + public bool GetNextObstacle(Vec2 start, int dir, out Vec2 pos, Vec2? extraObsticle = null) + { + if (extraObsticle is Vec2 ex) + _map[ex.Y][ex.X] = true; + pos = default; + + var (sX, sY) = start; + switch (dir) + { + case 0: + for (int y = sY; y >= 0; y--) + { + if (_map[y][sX]) + { + pos = new(sX, y); + ResetExtraObsticle(); + return true; + } + } + break; + + case 1: + var rowRight = _map[sY]; + for (int x = sX; x < _width; x++) + { + if (rowRight[x]) + { + pos = new(x, sY); + ResetExtraObsticle(); + return true; + } + } + break; + + case 2: + for (int y = sY; y < _height; y++) + { + if (_map[y][sX]) + { + pos = new(sX, y); + ResetExtraObsticle(); + return true; + } + } + break; + + case 3: + var rowLeft = _map[sY]; + for (int x = sX; x >= 0; x--) + { + if (rowLeft[x]) + { + pos = new(x, sY); + ResetExtraObsticle(); + return true; + } + } + break; + } + + void ResetExtraObsticle() + { + if (extraObsticle is Vec2 ex) + _map[ex.Y][ex.X] = false; + } + ResetExtraObsticle(); + return false; + } + + public void PrintBoard(List nodes, Vec2 start, Vec2? extraObsticle = null) + { + var path = GetPathSet(nodes); + for (int y = 0; y < _height; y++) + { + for (int x = 0; x < _width; x++) + { + Console.ResetColor(); + var p = new Vec2(x, y); + var node = nodes.FirstOrDefault(n => n.Pos == p, new GuardNode(p, 0, -1)); + if (node.Id != -1) + { + Console.ForegroundColor = ConsoleColor.Green; + if (node.Id == 0) + Console.ForegroundColor = ConsoleColor.Yellow; + else if (node.Id == nodes.Count - 1) + Console.ForegroundColor = ConsoleColor.Red; + switch (node.Direction) + { + case 0: + Console.Write('^'); + break; + + case 1: + Console.Write('>'); + break; + + case 2: + Console.Write('v'); + break; + + case 3: + Console.Write('<'); + break; + } + continue; + } + if (p == start) + { + Console.ForegroundColor = ConsoleColor.Magenta; + Console.Write('S'); + } + if (_map[y][x]) + Console.Write('#'); + else if (p == extraObsticle) + { + Console.ForegroundColor = ConsoleColor.DarkBlue; + Console.Write('$'); + } + else if (path.Contains(p)) + { + Console.ForegroundColor = ConsoleColor.DarkGray; + Console.Write('.'); + } + else + Console.Write(' '); + } + Console.WriteLine(); + } + } +} + +file struct GuardNode +{ + public int Id { get; private set; } + public Vec2 Pos { get; } + public int Direction { get; } + public int? Next { get; set; } + public GuardNode(Vec2 pos, int dir, int id) + { + Pos = pos; + Direction = dir; + Id = id; + } + + public bool IsLoop(List nodes) + { + return NodeExists(Id, nodes); + } + + public bool NodeExists(int target, List nodes) + { + if (Next == target) + return true; + if (Next is int id) + return nodes[id].NodeExists(target, nodes); + return false; + } + + public override string ToString() + { + return $"{Pos}: {Direction}"; + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2024/Day7/BridgeRepair.cs b/AdventOfCode/Problems/AOC2024/Day7/BridgeRepair.cs index e3b3c09..7161ea3 100644 --- a/AdventOfCode/Problems/AOC2024/Day7/BridgeRepair.cs +++ b/AdventOfCode/Problems/AOC2024/Day7/BridgeRepair.cs @@ -1,70 +1,70 @@ -namespace AdventOfCode.Problems.AOC2024.Day7; - -[ProblemInfo(2024, 7, "Bridge Repair")] -internal class BridgeRepair : Problem -{ - private List<(ulong total, ulong[] nums)> _data = []; - - private enum Operator - { - Mul, - Add, - Concat - } - - public override void CalculatePart1() - { - foreach (var (target, nums) in _data) - { - if (IsSolvable(target, nums, [Operator.Mul, Operator.Add])) - Part1 += target; - } - } - - public override void CalculatePart2() - { - foreach (var (target, nums) in _data) - { - if (IsSolvable(target, nums, [Operator.Mul, Operator.Add, Operator.Concat])) - Part2 += target; - } - } - - private static bool IsSolvable(ulong target, ulong[] nums, Operator[] ops) - { - return ops.Any(o => IsSolvable(target, nums, o, nums[0], ops)); - } - - private static bool IsSolvable(ulong target, ulong[] nums, Operator curOperator, ulong curTotal, Operator[] ops, int idx = 1) - { - if (target == curTotal && idx == nums.Length) - return true; - if (curTotal > target) - return false; - if (idx >= nums.Length) - return false; - - curTotal = curOperator switch - { - Operator.Mul => curTotal * nums[idx], - Operator.Add => curTotal + nums[idx], - Operator.Concat => ulong.Parse($"{curTotal}{nums[idx]}"), - _ => throw new InvalidOperationException(), - }; - - return ops.Any(o => IsSolvable(target, nums, o, curTotal, ops, idx + 1)); - } - - public override void LoadInput() - { - var lines = ReadInputLines("input.txt"); - _data = new List<(ulong total, ulong[] nums)>(lines.Length); - foreach (var line in lines) - { - var s = line.Split(':'); - var sum = ulong.Parse(s[0].Trim()); - var nums = s[1].Trim().Split(' ').Select(ulong.Parse).ToArray(); - _data.Add((sum, nums)); - } - } +namespace AdventOfCode.Problems.AOC2024.Day7; + +[ProblemInfo(2024, 7, "Bridge Repair")] +internal class BridgeRepair : Problem +{ + private List<(ulong total, ulong[] nums)> _data = []; + + private enum Operator + { + Mul, + Add, + Concat + } + + public override void CalculatePart1() + { + foreach (var (target, nums) in _data) + { + if (IsSolvable(target, nums, [Operator.Mul, Operator.Add])) + Part1 += target; + } + } + + public override void CalculatePart2() + { + foreach (var (target, nums) in _data) + { + if (IsSolvable(target, nums, [Operator.Mul, Operator.Add, Operator.Concat])) + Part2 += target; + } + } + + private static bool IsSolvable(ulong target, ulong[] nums, Operator[] ops) + { + return ops.Any(o => IsSolvable(target, nums, o, nums[0], ops)); + } + + private static bool IsSolvable(ulong target, ulong[] nums, Operator curOperator, ulong curTotal, Operator[] ops, int idx = 1) + { + if (target == curTotal && idx == nums.Length) + return true; + if (curTotal > target) + return false; + if (idx >= nums.Length) + return false; + + curTotal = curOperator switch + { + Operator.Mul => curTotal * nums[idx], + Operator.Add => curTotal + nums[idx], + Operator.Concat => ulong.Parse($"{curTotal}{nums[idx]}"), + _ => throw new InvalidOperationException(), + }; + + return ops.Any(o => IsSolvable(target, nums, o, curTotal, ops, idx + 1)); + } + + public override void LoadInput() + { + var lines = ReadInputLines("input.txt"); + _data = new List<(ulong total, ulong[] nums)>(lines.Length); + foreach (var line in lines) + { + var s = line.Split(':'); + var sum = ulong.Parse(s[0].Trim()); + var nums = s[1].Trim().Split(' ').Select(ulong.Parse).ToArray(); + _data.Add((sum, nums)); + } + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2024/Day8/ResonantCollinearity.cs b/AdventOfCode/Problems/AOC2024/Day8/ResonantCollinearity.cs index 3e2b9e4..0d53531 100644 --- a/AdventOfCode/Problems/AOC2024/Day8/ResonantCollinearity.cs +++ b/AdventOfCode/Problems/AOC2024/Day8/ResonantCollinearity.cs @@ -1,139 +1,139 @@ -using AdventOfCode.Utils.Models; - -using System.Collections.Frozen; - -namespace AdventOfCode.Problems.AOC2024.Day8; - -[ProblemInfo(2024, 8, "Resonant Collinearity")] -internal class ResonantCollinearity : Problem -{ - private string[] _map = []; - private int _width; - private int _height; - private FrozenDictionary>> _nodes = FrozenDictionary>>.Empty; - - public override void CalculatePart1() - { - var antiNodes = new List>(); - foreach (var (nodeType, nodes) in _nodes) - { - foreach (var a in nodes) - { - foreach (var b in nodes) - { - if (a == b) - continue; - antiNodes.AddRange(GetAntiNodes(a, b)); - } - } - } - //PrintBoard(antiNodes); - Part1 = antiNodes.Where(IsInBounds).Distinct().Count(); - } - - public void PrintBoard(List> antinodes) - { - Console.WriteLine(); - for (int y = 0; y < _height; y++) - { - for (int x = 0; x < _width; x++) - { - Console.ResetColor(); - var p = new Vec2(x, y); - if (antinodes.Contains(p)) - Console.BackgroundColor = ConsoleColor.DarkGreen; - Console.Write(_map[y][x]); - } - Console.ResetColor(); - Console.WriteLine(); - } - Console.ResetColor(); - } - - public bool IsInBounds(Vec2 pos) - { - if (pos.X < 0 || pos.Y < 0) - return false; - if (pos.X >= _width || pos.Y >= _height) - return false; - return true; - } - - private Vec2[] GetAntiNodes(Vec2 a, Vec2 b) - { - var dir = a - b; - - var aNode1 = dir + a; - var aNode2 = -dir + b; - - return [aNode1, aNode2]; - } - - private Vec2[] GetHarmonicAntiNodes(Vec2 a, Vec2 b) - { - var dir = a - b; - - List> GetNodes(Vec2 start, Vec2 dir) - { - var results = new List>(); - while (true) - { - var p = dir + start; - if(!IsInBounds(p)) - break; - results.Add(p); - start = p; - - } - return results; - } - - return [.. GetNodes(a, dir), .. GetNodes(b, -dir)]; - } - - public override void CalculatePart2() - { - var antiNodes = new List>(); - foreach (var (nodeType, nodes) in _nodes) - { - foreach (var a in nodes) - { - foreach (var b in nodes) - { - if (a == b) - continue; - antiNodes.AddRange(GetHarmonicAntiNodes(a, b)); - } - } - } - //PrintBoard(antiNodes); - antiNodes.AddRange(_nodes.Values.Where(v => v.Count > 1).SelectMany(v => v)); - Part2 = antiNodes.Distinct().Count(); - } - - public override void LoadInput() - { - _map = ReadInputLines("input.txt"); - var nodes = new Dictionary>>(); - _width = _map[0].Length; - _height = _map.Length; - for (int y = 0; y < _map.Length; y++) - { - var row = _map[y]; - for (int x = 0; x < row.Length; x++) - { - switch (row[x]) - { - case '.': - continue; - default: - var p = new Vec2(x, y); - if (!nodes.TryAdd(row[x], [p])) - nodes[row[x]].Add(p); - continue; - } - } - } - _nodes = nodes.ToFrozenDictionary(); - } +using AdventOfCode.Utils.Models; + +using System.Collections.Frozen; + +namespace AdventOfCode.Problems.AOC2024.Day8; + +[ProblemInfo(2024, 8, "Resonant Collinearity")] +internal class ResonantCollinearity : Problem +{ + private string[] _map = []; + private int _width; + private int _height; + private FrozenDictionary>> _nodes = FrozenDictionary>>.Empty; + + public override void CalculatePart1() + { + var antiNodes = new List>(); + foreach (var (nodeType, nodes) in _nodes) + { + foreach (var a in nodes) + { + foreach (var b in nodes) + { + if (a == b) + continue; + antiNodes.AddRange(GetAntiNodes(a, b)); + } + } + } + //PrintBoard(antiNodes); + Part1 = antiNodes.Where(IsInBounds).Distinct().Count(); + } + + public void PrintBoard(List> antinodes) + { + Console.WriteLine(); + for (int y = 0; y < _height; y++) + { + for (int x = 0; x < _width; x++) + { + Console.ResetColor(); + var p = new Vec2(x, y); + if (antinodes.Contains(p)) + Console.BackgroundColor = ConsoleColor.DarkGreen; + Console.Write(_map[y][x]); + } + Console.ResetColor(); + Console.WriteLine(); + } + Console.ResetColor(); + } + + public bool IsInBounds(Vec2 pos) + { + if (pos.X < 0 || pos.Y < 0) + return false; + if (pos.X >= _width || pos.Y >= _height) + return false; + return true; + } + + private Vec2[] GetAntiNodes(Vec2 a, Vec2 b) + { + var dir = a - b; + + var aNode1 = dir + a; + var aNode2 = -dir + b; + + return [aNode1, aNode2]; + } + + private Vec2[] GetHarmonicAntiNodes(Vec2 a, Vec2 b) + { + var dir = a - b; + + List> GetNodes(Vec2 start, Vec2 dir) + { + var results = new List>(); + while (true) + { + var p = dir + start; + if(!IsInBounds(p)) + break; + results.Add(p); + start = p; + + } + return results; + } + + return [.. GetNodes(a, dir), .. GetNodes(b, -dir)]; + } + + public override void CalculatePart2() + { + var antiNodes = new List>(); + foreach (var (nodeType, nodes) in _nodes) + { + foreach (var a in nodes) + { + foreach (var b in nodes) + { + if (a == b) + continue; + antiNodes.AddRange(GetHarmonicAntiNodes(a, b)); + } + } + } + //PrintBoard(antiNodes); + antiNodes.AddRange(_nodes.Values.Where(v => v.Count > 1).SelectMany(v => v)); + Part2 = antiNodes.Distinct().Count(); + } + + public override void LoadInput() + { + _map = ReadInputLines("input.txt"); + var nodes = new Dictionary>>(); + _width = _map[0].Length; + _height = _map.Length; + for (int y = 0; y < _map.Length; y++) + { + var row = _map[y]; + for (int x = 0; x < row.Length; x++) + { + switch (row[x]) + { + case '.': + continue; + default: + var p = new Vec2(x, y); + if (!nodes.TryAdd(row[x], [p])) + nodes[row[x]].Add(p); + continue; + } + } + } + _nodes = nodes.ToFrozenDictionary(); + } } \ No newline at end of file diff --git a/AdventOfCode/Problems/AOC2025/Day1/SecretEntrance.cs b/AdventOfCode/Problems/AOC2025/Day1/SecretEntrance.cs new file mode 100644 index 0000000..c9f26f5 --- /dev/null +++ b/AdventOfCode/Problems/AOC2025/Day1/SecretEntrance.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using ZLinq; + +namespace AdventOfCode.Problems.AOC2025.Day1; + +[ProblemInfo(2025, 1, "Secret Entrance")] +internal class SecretEntrance : Problem +{ + public int[] Input { get; set; } = []; + public override void CalculatePart1() + { + var c = 0; + var v = 50; + foreach (var item in Input) + { + v += item; + v = v.Mod(100); + if (v == 0) + c++; + } + Part1 = c; + } + + public override void CalculatePart2() + { + var c = 0; + var v = 50; + foreach (var item in Input) + { + var sign = int.Sign(item); + for (int i = 0; i < Math.Abs(item); i++) + { + v += sign; + v = v.Mod(100); + if (v == 0) + c++; + } + } + Part2 = c; + } + + public override void LoadInput() + { + Input = ReadInputLines("input.txt") + .AsValueEnumerable() + .Select(l => + { + return l[0] switch + { + 'L' => -int.Parse(l[1..]), + 'R' => int.Parse(l[1..]), + _ => throw new NotImplementedException() + }; + }).ToArray(); + } +} diff --git a/AdventOfCode/Program.cs b/AdventOfCode/Program.cs index 5afc6f6..ab33153 100644 --- a/AdventOfCode/Program.cs +++ b/AdventOfCode/Program.cs @@ -1,7 +1,7 @@ -global using AdventOfCode.Runner; -global using AdventOfCode.Runner.Attributes; -global using AdventOfCode.Utils; - - -var runner = new AOCRunner(); +global using AdventOfCode.Runner; +global using AdventOfCode.Runner.Attributes; +global using AdventOfCode.Utils; + + +var runner = new AOCRunner(); runner.RenderInteractiveMenu(); \ No newline at end of file diff --git a/AdventOfCode/Runner/AOCRunner.cs b/AdventOfCode/Runner/AOCRunner.cs index 6aba236..31b45f9 100644 --- a/AdventOfCode/Runner/AOCRunner.cs +++ b/AdventOfCode/Runner/AOCRunner.cs @@ -1,424 +1,424 @@ -using AdventOfCode.Runner.Attributes; - -using System.Diagnostics; -using System.Reflection; -using System.Text; - -namespace AdventOfCode.Runner; - -public class AOCRunner -{ - private Dictionary> _loadedProblems; - private List _years; - private int _selectedYear; - private int _selectedDay; - private int _scollOffset = 0; - private int _maxProblemCount; - private bool _isQuiting; - - private bool _isProblemMode = false; - - public AOCRunner() - { - Console.OutputEncoding = Encoding.UTF8; - _loadedProblems = new(); - _years = new List(); - _selectedYear = DateTime.Now.Year; - FindProblemClasses(); - - if (!_loadedProblems.ContainsKey(_selectedYear)) - _selectedYear = _loadedProblems.Keys.First(); - - InitSizing(); - if (_years.Count > 0) - { - _selectedDay = _loadedProblems[_selectedYear].Count - 1; - ConstrainListScroll(); - } - } - - public AOCRunner WithDay(int day) - { - var problem = _loadedProblems[_selectedYear].FirstOrDefault(d => d.info.Day == day); - if (problem == default) - throw new ArgumentException($"There are no problems have been loaded for the day '{day}' of year '{_selectedYear}'", nameof(day)); - - _selectedDay = _loadedProblems[_selectedYear].IndexOf(problem); - return this; - } - - public AOCRunner WithYear(int year) - { - if (!_loadedProblems.ContainsKey(year)) - throw new ArgumentException($"There are no problems have been loaded for the year '{year}'", nameof(year)); - _selectedYear = year; - return this; - } - - private void InitSizing() - { - _maxProblemCount = Console.WindowHeight - 9; - } - - private void ConstrainListScroll() - { - if (_selectedDay >= _maxProblemCount) - { - _scollOffset = _loadedProblems[_selectedYear].Count - _maxProblemCount; - } - if (_selectedDay < _scollOffset) - { - _scollOffset = _selectedDay; - } - } - - private void FindProblemClasses() - { - var types = Assembly.GetExecutingAssembly().DefinedTypes.Where(t => !t.IsAbstract); - if (types == null) - return; - foreach (var type in types) - { - var info = type.GetCustomAttribute(); - if (info == null) - continue; - if (_loadedProblems.TryGetValue(info.Year, out var list)) - list.Add((info, type)); - else - _loadedProblems.Add(info.Year, new() { (info, type) }); - } - foreach (var (year, list) in _loadedProblems) - _loadedProblems[year] = list.OrderBy(l => l.info.Day).ToList(); - _years = _loadedProblems.Keys.OrderDescending().ToList(); - } - - private void RunDay(int year, int dayIndex) - { - var yearList = _loadedProblems[year]; - if (yearList.Count <= dayIndex || dayIndex < 0) - Console.WriteLine($"No problem exists for day index {dayIndex}"); - - Console.Clear(); - var (info, problemType) = yearList[dayIndex]; - Console.Write("Problem: "); - Console.ForegroundColor = ConsoleColor.Yellow; - Console.WriteLine($"\t{info.Name}"); - Console.ForegroundColor = ConsoleColor.DarkRed; - Console.WriteLine($"\t\t{info.Year} - Day {info.Day}"); - - Console.ForegroundColor = ConsoleColor.Gray; - - if (Activator.CreateInstance(problemType) is not IProblem problem) - { - Console.WriteLine("Failed to create problem isntance"); - return; - } - - var time = ReadInput(problem); - time += RunPart("Calculating Part 1", problem.CalculatePart1); - time += RunPart("Calculating Part 2", problem.CalculatePart2); - - Console.WriteLine(); - Console.Write($"Total Elapsed Time: "); - Console.ForegroundColor = ConsoleColor.Cyan; - Console.WriteLine($"{time.TotalMilliseconds}ms"); - - Console.ForegroundColor = ConsoleColor.Gray; - - Console.WriteLine(); - Console.WriteLine("Printing Results:"); - - Console.WriteLine("---- Part 1 ----"); - problem.PrintPart1(); - Console.Write("\n\n"); - Console.WriteLine("---- Part 2 ----"); - problem.PrintPart2(); - Console.Write("\n\n"); - } - - private static TimeSpan ReadInput(IProblem problem) - { - var sw = new Stopwatch(); - Console.WriteLine(); - Console.Write("Loading Input data... "); - sw.Start(); - problem.LoadInput(); - sw.Stop(); - - Console.ForegroundColor = ConsoleColor.Green; - Console.Write("Done in "); - Console.ForegroundColor = ConsoleColor.Cyan; - Console.WriteLine($"{sw.Elapsed.TotalMilliseconds:n}ms"); - return sw.Elapsed; - } - - private static TimeSpan RunPart(string name, Action action) - { - Console.ForegroundColor = ConsoleColor.Gray; - var sw = new Stopwatch(); - Console.Write($"{name}... "); - try - { - sw.Start(); - action(); - sw.Stop(); - Console.ForegroundColor = ConsoleColor.Green; - Console.Write("Done in "); - Console.ForegroundColor = ConsoleColor.Cyan; - Console.WriteLine($"{sw.Elapsed.TotalMilliseconds:n}ms"); - } - catch (NotImplementedException) - { - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Not Implemented"); - } - //catch (Exception e) - //{ - // Console.ForegroundColor = ConsoleColor.Red; - // Console.WriteLine("Failed"); - // Console.WriteLine(e); - //} - finally - { - sw.Stop(); - Console.ForegroundColor = ConsoleColor.Gray; - } - return sw.Elapsed; - } - - public void RenderInteractiveMenu() - { - Console.BackgroundColor = ConsoleColor.Black; - Console.ForegroundColor = ConsoleColor.Gray; - Console.CursorVisible = false; - Console.Clear(); - while (!_isQuiting) - { - InitSizing(); - RenderTopBar(); - RenderContentView(); - ReadInput(); - } - } - - private void ReadInput() - { - var input = Console.ReadKey(true); - if (_isProblemMode) - { - if (input.Key is ConsoleKey.Enter or ConsoleKey.Escape) - { - _isProblemMode = false; - Console.Clear(); - } - return; - } - var yearIndex = _years.IndexOf(_selectedYear); - var dayMax = _loadedProblems[_selectedYear].Count - 1; - switch (input.Key) - { - case ConsoleKey.LeftArrow: - _scollOffset = 0; - _selectedDay = 0; - if (yearIndex == 0) - { - _selectedYear = _years.Last(); - break; - } - _selectedYear = _years[--yearIndex]; - break; - - case ConsoleKey.RightArrow: - _scollOffset = 0; - _selectedDay = 0; - if (yearIndex == _years.Count - 1) - { - _selectedYear = _years.First(); - break; - } - _selectedYear = _years[++yearIndex]; - break; - - case ConsoleKey.UpArrow: - if (_selectedDay == 0) - { - _selectedDay = dayMax; - break; - } - _selectedDay--; - break; - - case ConsoleKey.DownArrow: - if (_selectedDay == dayMax) - { - _selectedDay = 0; - break; - } - _selectedDay++; - break; - - case ConsoleKey.Enter: - _isProblemMode = true; - break; - - case ConsoleKey.Escape: - _isQuiting = true; - break; - } - ConstrainListScroll(); - } - - private void RenderTopBar() - { - if (_isProblemMode) - return; - //Render Border - DrawBorder(1, 0, Console.WindowWidth, 3); - Console.SetCursorPosition(Console.WindowWidth / 2 - 4, 1); - Console.ForegroundColor = ConsoleColor.Blue; - Console.Write(" Years "); - //Render Tabs - RenderTabList(); - } - - private void RenderTabList() - { - var buttonWidth = 6; - var tabMaxPos = Console.WindowWidth - 3; - for (int i = 0; i < _years.Count; i++) - { - var year = _years[i]; - var col = (i * 7) + 2; - var end = col + buttonWidth; - if (end >= tabMaxPos) - break; - if (year == _selectedYear) - DrawSelectedButton(year.ToString(), 2, col, buttonWidth, 1, ConsoleColor.Red, ConsoleColor.Blue); - else - DrawButton(year.ToString(), 2, col, buttonWidth, 1, ConsoleColor.Gray, Console.BackgroundColor); - } - } - - private void RenderContentView() - { - if (!_isProblemMode) - { - DrawBorder(5, 0, Console.WindowWidth, Console.WindowHeight - 5); - Console.SetCursorPosition(Console.WindowWidth / 2 - 5, 5); - Console.ForegroundColor = ConsoleColor.Blue; - Console.Write(" Problems "); - RenderProblemList(); - } - else - RenderProblemResults(); - } - - private void RenderProblemList() - { - if (_loadedProblems.Count == 0) - { - DrawButton("There are no problems...", 6, 2, Console.WindowWidth - 2, Console.WindowHeight - 7); - return; - } - var problems = _loadedProblems[_selectedYear]; - - var listEnd = Math.Min(_maxProblemCount, problems.Count); - - for (int i = 0; i < listEnd; i++) - { - var (info, _) = problems[i + _scollOffset]; - var buttonText = $"{i + _scollOffset}.\t[Day {info.Day}] {info.Name}"; - var row = i + 7; - if (i + _scollOffset == _selectedDay) - DrawSelectedButton(buttonText, row, 2, Console.WindowWidth - 4, 1, ConsoleColor.DarkMagenta, ConsoleColor.DarkGray, false, 2); - else - DrawButton(buttonText, row, 2, Console.WindowWidth - 4, 1, ConsoleColor.Cyan, Console.BackgroundColor, false, 2); - } - for (int i = problems.Count + 7; i < Console.WindowHeight - 2; i++) - { - Console.SetCursorPosition(2, i); - Console.Write(new string(' ', Console.WindowWidth - 4)); - } - } - - private void RenderProblemResults() - { - Console.SetCursorPosition(2, 7); - RunDay(_selectedYear, _selectedDay); - } - - private void DrawSelectedButton(string text, int row, int col, int width, int height, ConsoleColor color = ConsoleColor.Gray, ConsoleColor background = ConsoleColor.Black, bool centered = true, int padding = 0) - { - //text = $"\ue0c7{text}\ue0c6"; - var origBg = Console.BackgroundColor; - Console.BackgroundColor = background; - for (int y = row; y < row + height; y++) - { - Console.SetCursorPosition(col, y); - Console.Write(new string(' ', width)); - } - Console.ForegroundColor = color; - var xOffset = centered ? (width / 2) - (text.Length / 2) : padding; - var yOffset = centered ? height / 2 : padding; - if (height == 1) - yOffset = 0; - Console.SetCursorPosition(col + xOffset, row + yOffset); - Console.Write(text); - Console.BackgroundColor = origBg; - Console.ForegroundColor = background; - Console.SetCursorPosition(col, row + height / 2); - Console.Write('\ue0c7'); - Console.SetCursorPosition(col + width - 1, row + height / 2); - Console.Write('\ue0c6'); - - Console.BackgroundColor = origBg; - } - - private void DrawButton(string text, int row, int col, int width, int height, ConsoleColor color = ConsoleColor.Gray, ConsoleColor background = ConsoleColor.Black, bool centered = true, int padding = 0) - { - var origBg = Console.BackgroundColor; - Console.BackgroundColor = background; - for (int y = row; y < row + height; y++) - { - Console.SetCursorPosition(col, y); - Console.Write(new string(' ', width)); - } - Console.ForegroundColor = color; - var xOffset = centered ? (width / 2) - (text.Length / 2) : padding; - var yOffset = centered ? height / 2 : padding; - if (height == 1) - yOffset = 0; - Console.SetCursorPosition(col + xOffset, row + yOffset); - Console.Write(text); - Console.BackgroundColor = origBg; - } - - private void DrawBorder(int row, int col, int width, int height, ConsoleColor color = ConsoleColor.Gray, bool drawFill = false) - { - //║═╔╗╝╚ - Console.ForegroundColor = ConsoleColor.Gray; - var w = col + width - 1; - var h = row + height - 1; - for (int x = col; x <= w; x++) - { - for (int y = row; y <= h; y++) - { - Console.SetCursorPosition(x, y); - if (x == col && y == row) - Console.Write('╔'); - else if (x == col && y == h) - Console.Write('╚'); - else if (x == w && y == row) - Console.Write('╗'); - else if (x == w && y == h) - Console.Write('╝'); - else if (x == col || x == w) - Console.Write('║'); - else if (y == row || y == h) - Console.Write('═'); - else if (drawFill) - Console.Write(' '); - } - } - } +using AdventOfCode.Runner.Attributes; + +using System.Diagnostics; +using System.Reflection; +using System.Text; + +namespace AdventOfCode.Runner; + +public class AOCRunner +{ + private Dictionary> _loadedProblems; + private List _years; + private int _selectedYear; + private int _selectedDay; + private int _scollOffset = 0; + private int _maxProblemCount; + private bool _isQuiting; + + private bool _isProblemMode = false; + + public AOCRunner() + { + Console.OutputEncoding = Encoding.UTF8; + _loadedProblems = new(); + _years = new List(); + _selectedYear = DateTime.Now.Year; + FindProblemClasses(); + + if (!_loadedProblems.ContainsKey(_selectedYear)) + _selectedYear = _loadedProblems.Keys.First(); + + InitSizing(); + if (_years.Count > 0) + { + _selectedDay = _loadedProblems[_selectedYear].Count - 1; + ConstrainListScroll(); + } + } + + public AOCRunner WithDay(int day) + { + var problem = _loadedProblems[_selectedYear].FirstOrDefault(d => d.info.Day == day); + if (problem == default) + throw new ArgumentException($"There are no problems have been loaded for the day '{day}' of year '{_selectedYear}'", nameof(day)); + + _selectedDay = _loadedProblems[_selectedYear].IndexOf(problem); + return this; + } + + public AOCRunner WithYear(int year) + { + if (!_loadedProblems.ContainsKey(year)) + throw new ArgumentException($"There are no problems have been loaded for the year '{year}'", nameof(year)); + _selectedYear = year; + return this; + } + + private void InitSizing() + { + _maxProblemCount = Console.WindowHeight - 9; + } + + private void ConstrainListScroll() + { + if (_selectedDay >= _maxProblemCount) + { + _scollOffset = _loadedProblems[_selectedYear].Count - _maxProblemCount; + } + if (_selectedDay < _scollOffset) + { + _scollOffset = _selectedDay; + } + } + + private void FindProblemClasses() + { + var types = Assembly.GetExecutingAssembly().DefinedTypes.Where(t => !t.IsAbstract); + if (types == null) + return; + foreach (var type in types) + { + var info = type.GetCustomAttribute(); + if (info == null) + continue; + if (_loadedProblems.TryGetValue(info.Year, out var list)) + list.Add((info, type)); + else + _loadedProblems.Add(info.Year, new() { (info, type) }); + } + foreach (var (year, list) in _loadedProblems) + _loadedProblems[year] = list.OrderBy(l => l.info.Day).ToList(); + _years = _loadedProblems.Keys.OrderDescending().ToList(); + } + + private void RunDay(int year, int dayIndex) + { + var yearList = _loadedProblems[year]; + if (yearList.Count <= dayIndex || dayIndex < 0) + Console.WriteLine($"No problem exists for day index {dayIndex}"); + + Console.Clear(); + var (info, problemType) = yearList[dayIndex]; + Console.Write("Problem: "); + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine($"\t{info.Name}"); + Console.ForegroundColor = ConsoleColor.DarkRed; + Console.WriteLine($"\t\t{info.Year} - Day {info.Day}"); + + Console.ForegroundColor = ConsoleColor.Gray; + + if (Activator.CreateInstance(problemType) is not IProblem problem) + { + Console.WriteLine("Failed to create problem isntance"); + return; + } + + var time = ReadInput(problem); + time += RunPart("Calculating Part 1", problem.CalculatePart1); + time += RunPart("Calculating Part 2", problem.CalculatePart2); + + Console.WriteLine(); + Console.Write($"Total Elapsed Time: "); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine($"{time.TotalMilliseconds}ms"); + + Console.ForegroundColor = ConsoleColor.Gray; + + Console.WriteLine(); + Console.WriteLine("Printing Results:"); + + Console.WriteLine("---- Part 1 ----"); + problem.PrintPart1(); + Console.Write("\n\n"); + Console.WriteLine("---- Part 2 ----"); + problem.PrintPart2(); + Console.Write("\n\n"); + } + + private static TimeSpan ReadInput(IProblem problem) + { + var sw = new Stopwatch(); + Console.WriteLine(); + Console.Write("Loading Input data... "); + sw.Start(); + problem.LoadInput(); + sw.Stop(); + + Console.ForegroundColor = ConsoleColor.Green; + Console.Write("Done in "); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine($"{sw.Elapsed.TotalMilliseconds:n}ms"); + return sw.Elapsed; + } + + private static TimeSpan RunPart(string name, Action action) + { + Console.ForegroundColor = ConsoleColor.Gray; + var sw = new Stopwatch(); + Console.Write($"{name}... "); + try + { + sw.Start(); + action(); + sw.Stop(); + Console.ForegroundColor = ConsoleColor.Green; + Console.Write("Done in "); + Console.ForegroundColor = ConsoleColor.Cyan; + Console.WriteLine($"{sw.Elapsed.TotalMilliseconds:n}ms"); + } + catch (NotImplementedException) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("Not Implemented"); + } + //catch (Exception e) + //{ + // Console.ForegroundColor = ConsoleColor.Red; + // Console.WriteLine("Failed"); + // Console.WriteLine(e); + //} + finally + { + sw.Stop(); + Console.ForegroundColor = ConsoleColor.Gray; + } + return sw.Elapsed; + } + + public void RenderInteractiveMenu() + { + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = ConsoleColor.Gray; + Console.CursorVisible = false; + Console.Clear(); + while (!_isQuiting) + { + InitSizing(); + RenderTopBar(); + RenderContentView(); + ReadInput(); + } + } + + private void ReadInput() + { + var input = Console.ReadKey(true); + if (_isProblemMode) + { + if (input.Key is ConsoleKey.Enter or ConsoleKey.Escape) + { + _isProblemMode = false; + Console.Clear(); + } + return; + } + var yearIndex = _years.IndexOf(_selectedYear); + var dayMax = _loadedProblems[_selectedYear].Count - 1; + switch (input.Key) + { + case ConsoleKey.LeftArrow: + _scollOffset = 0; + _selectedDay = 0; + if (yearIndex == 0) + { + _selectedYear = _years.Last(); + break; + } + _selectedYear = _years[--yearIndex]; + break; + + case ConsoleKey.RightArrow: + _scollOffset = 0; + _selectedDay = 0; + if (yearIndex == _years.Count - 1) + { + _selectedYear = _years.First(); + break; + } + _selectedYear = _years[++yearIndex]; + break; + + case ConsoleKey.UpArrow: + if (_selectedDay == 0) + { + _selectedDay = dayMax; + break; + } + _selectedDay--; + break; + + case ConsoleKey.DownArrow: + if (_selectedDay == dayMax) + { + _selectedDay = 0; + break; + } + _selectedDay++; + break; + + case ConsoleKey.Enter: + _isProblemMode = true; + break; + + case ConsoleKey.Escape: + _isQuiting = true; + break; + } + ConstrainListScroll(); + } + + private void RenderTopBar() + { + if (_isProblemMode) + return; + //Render Border + DrawBorder(1, 0, Console.WindowWidth, 3); + Console.SetCursorPosition(Console.WindowWidth / 2 - 4, 1); + Console.ForegroundColor = ConsoleColor.Blue; + Console.Write(" Years "); + //Render Tabs + RenderTabList(); + } + + private void RenderTabList() + { + var buttonWidth = 6; + var tabMaxPos = Console.WindowWidth - 3; + for (int i = 0; i < _years.Count; i++) + { + var year = _years[i]; + var col = (i * 7) + 2; + var end = col + buttonWidth; + if (end >= tabMaxPos) + break; + if (year == _selectedYear) + DrawSelectedButton(year.ToString(), 2, col, buttonWidth, 1, ConsoleColor.Red, ConsoleColor.Blue); + else + DrawButton(year.ToString(), 2, col, buttonWidth, 1, ConsoleColor.Gray, Console.BackgroundColor); + } + } + + private void RenderContentView() + { + if (!_isProblemMode) + { + DrawBorder(5, 0, Console.WindowWidth, Console.WindowHeight - 5); + Console.SetCursorPosition(Console.WindowWidth / 2 - 5, 5); + Console.ForegroundColor = ConsoleColor.Blue; + Console.Write(" Problems "); + RenderProblemList(); + } + else + RenderProblemResults(); + } + + private void RenderProblemList() + { + if (_loadedProblems.Count == 0) + { + DrawButton("There are no problems...", 6, 2, Console.WindowWidth - 2, Console.WindowHeight - 7); + return; + } + var problems = _loadedProblems[_selectedYear]; + + var listEnd = Math.Min(_maxProblemCount, problems.Count); + + for (int i = 0; i < listEnd; i++) + { + var (info, _) = problems[i + _scollOffset]; + var buttonText = $"{i + _scollOffset}.\t[Day {info.Day}] {info.Name}"; + var row = i + 7; + if (i + _scollOffset == _selectedDay) + DrawSelectedButton(buttonText, row, 2, Console.WindowWidth - 4, 1, ConsoleColor.DarkMagenta, ConsoleColor.DarkGray, false, 2); + else + DrawButton(buttonText, row, 2, Console.WindowWidth - 4, 1, ConsoleColor.Cyan, Console.BackgroundColor, false, 2); + } + for (int i = problems.Count + 7; i < Console.WindowHeight - 2; i++) + { + Console.SetCursorPosition(2, i); + Console.Write(new string(' ', Console.WindowWidth - 4)); + } + } + + private void RenderProblemResults() + { + Console.SetCursorPosition(2, 7); + RunDay(_selectedYear, _selectedDay); + } + + private void DrawSelectedButton(string text, int row, int col, int width, int height, ConsoleColor color = ConsoleColor.Gray, ConsoleColor background = ConsoleColor.Black, bool centered = true, int padding = 0) + { + //text = $"\ue0c7{text}\ue0c6"; + var origBg = Console.BackgroundColor; + Console.BackgroundColor = background; + for (int y = row; y < row + height; y++) + { + Console.SetCursorPosition(col, y); + Console.Write(new string(' ', width)); + } + Console.ForegroundColor = color; + var xOffset = centered ? (width / 2) - (text.Length / 2) : padding; + var yOffset = centered ? height / 2 : padding; + if (height == 1) + yOffset = 0; + Console.SetCursorPosition(col + xOffset, row + yOffset); + Console.Write(text); + Console.BackgroundColor = origBg; + Console.ForegroundColor = background; + Console.SetCursorPosition(col, row + height / 2); + Console.Write('\ue0c7'); + Console.SetCursorPosition(col + width - 1, row + height / 2); + Console.Write('\ue0c6'); + + Console.BackgroundColor = origBg; + } + + private void DrawButton(string text, int row, int col, int width, int height, ConsoleColor color = ConsoleColor.Gray, ConsoleColor background = ConsoleColor.Black, bool centered = true, int padding = 0) + { + var origBg = Console.BackgroundColor; + Console.BackgroundColor = background; + for (int y = row; y < row + height; y++) + { + Console.SetCursorPosition(col, y); + Console.Write(new string(' ', width)); + } + Console.ForegroundColor = color; + var xOffset = centered ? (width / 2) - (text.Length / 2) : padding; + var yOffset = centered ? height / 2 : padding; + if (height == 1) + yOffset = 0; + Console.SetCursorPosition(col + xOffset, row + yOffset); + Console.Write(text); + Console.BackgroundColor = origBg; + } + + private void DrawBorder(int row, int col, int width, int height, ConsoleColor color = ConsoleColor.Gray, bool drawFill = false) + { + //║═╔╗╝╚ + Console.ForegroundColor = ConsoleColor.Gray; + var w = col + width - 1; + var h = row + height - 1; + for (int x = col; x <= w; x++) + { + for (int y = row; y <= h; y++) + { + Console.SetCursorPosition(x, y); + if (x == col && y == row) + Console.Write('╔'); + else if (x == col && y == h) + Console.Write('╚'); + else if (x == w && y == row) + Console.Write('╗'); + else if (x == w && y == h) + Console.Write('╝'); + else if (x == col || x == w) + Console.Write('║'); + else if (y == row || y == h) + Console.Write('═'); + else if (drawFill) + Console.Write(' '); + } + } + } } \ No newline at end of file diff --git a/AdventOfCode/Runner/Attributes/ProblemInfoAttribute.cs b/AdventOfCode/Runner/Attributes/ProblemInfoAttribute.cs index 1ba6334..3ce3d42 100644 --- a/AdventOfCode/Runner/Attributes/ProblemInfoAttribute.cs +++ b/AdventOfCode/Runner/Attributes/ProblemInfoAttribute.cs @@ -1,15 +1,15 @@ -namespace AdventOfCode.Runner.Attributes; - -public class ProblemInfoAttribute : Attribute -{ - public int Day { get; init; } - public int Year { get; init; } - public string Name { get; init; } - - public ProblemInfoAttribute(int year, int day, string name) - { - Year = year; - Day = day; - Name = name; - } +namespace AdventOfCode.Runner.Attributes; + +public class ProblemInfoAttribute : Attribute +{ + public int Day { get; init; } + public int Year { get; init; } + public string Name { get; init; } + + public ProblemInfoAttribute(int year, int day, string name) + { + Year = year; + Day = day; + Name = name; + } } \ No newline at end of file diff --git a/AdventOfCode/Runner/Extensions.cs b/AdventOfCode/Runner/Extensions.cs index f0f65c3..e00ca90 100644 --- a/AdventOfCode/Runner/Extensions.cs +++ b/AdventOfCode/Runner/Extensions.cs @@ -1,63 +1,63 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Runner; -public static class Extensions -{ - public static IEnumerable Print(this IEnumerable values) - { - foreach (var item in values) - { - Console.WriteLine(item); - } - return values; - } - - public static T LCM(this IEnumerable values) where T : INumber - { - var a = values.First(); - values = values.Skip(1); - foreach (var item in values) - { - a = a.LCM(item); - } - return a; - } - - public static IEnumerable> Transpose(this IEnumerable data) where T: IEnumerable - { - var range = Enumerable.Range(0, data.First().Count()); - - return range.Select(i => data.Select(l => l.Skip(i).First())); - } - - public static IEnumerable Transpose(this IEnumerable data, Func, T> formatter) where T : IEnumerable - { - var range = Enumerable.Range(0, data.First().Count()); - - return range.Select(i => formatter(data.Select(l => l.Skip(i).First()))); - } - - public static IEnumerable Transpose(this IEnumerable data) - { - return Transpose(data, a => string.Join("", a)); - } - - public static IEnumerable> Permute(this IEnumerable values) - { - IEnumerable> permutate(IEnumerable reminder, IEnumerable prefix) - { - return !reminder.Any() - ? new List> { prefix.ToList() } - : reminder.SelectMany((c, i) => permutate( - reminder.Take(i).Concat(reminder.Skip(i + 1)).ToList(), - prefix.Append(c))); - } - return permutate(values, Enumerable.Empty()); - } - -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Runner; +public static class Extensions +{ + public static IEnumerable Print(this IEnumerable values) + { + foreach (var item in values) + { + Console.WriteLine(item); + } + return values; + } + + public static T LCM(this IEnumerable values) where T : INumber + { + var a = values.First(); + values = values.Skip(1); + foreach (var item in values) + { + a = a.LCM(item); + } + return a; + } + + public static IEnumerable> Transpose(this IEnumerable data) where T: IEnumerable + { + var range = Enumerable.Range(0, data.First().Count()); + + return range.Select(i => data.Select(l => l.Skip(i).First())); + } + + public static IEnumerable Transpose(this IEnumerable data, Func, T> formatter) where T : IEnumerable + { + var range = Enumerable.Range(0, data.First().Count()); + + return range.Select(i => formatter(data.Select(l => l.Skip(i).First()))); + } + + public static IEnumerable Transpose(this IEnumerable data) + { + return Transpose(data, a => string.Join("", a)); + } + + public static IEnumerable> Permute(this IEnumerable values) + { + IEnumerable> permutate(IEnumerable reminder, IEnumerable prefix) + { + return !reminder.Any() + ? new List> { prefix.ToList() } + : reminder.SelectMany((c, i) => permutate( + reminder.Take(i).Concat(reminder.Skip(i + 1)).ToList(), + prefix.Append(c))); + } + return permutate(values, Enumerable.Empty()); + } + +} diff --git a/AdventOfCode/Runner/ExtraMath.cs b/AdventOfCode/Runner/ExtraMath.cs index 3ec3b2c..f7fe5c3 100644 --- a/AdventOfCode/Runner/ExtraMath.cs +++ b/AdventOfCode/Runner/ExtraMath.cs @@ -1,37 +1,37 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Runner; - -public static class ExtraMath -{ - public static T GCF(this T a, T b) where T : INumber - { - while (!b.Equals(T.Zero)) - { - var t = b; - b = a % b; - a = t; - } - return a; - } - - public static T LCM(this T a, T b) where T : INumber - { - return (a / GCF(a, b)) * b; - } - - public static T Max(this T a, T b) where T : INumber - { - return T.Max(a, b); - } - - public static T Min(this T a, T b) where T : INumber - { - return T.Min(a, b); - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Runner; + +public static class ExtraMath +{ + public static T GCF(this T a, T b) where T : INumber + { + while (!b.Equals(T.Zero)) + { + var t = b; + b = a % b; + a = t; + } + return a; + } + + public static T LCM(this T a, T b) where T : INumber + { + return (a / GCF(a, b)) * b; + } + + public static T Max(this T a, T b) where T : INumber + { + return T.Max(a, b); + } + + public static T Min(this T a, T b) where T : INumber + { + return T.Min(a, b); + } } \ No newline at end of file diff --git a/AdventOfCode/Runner/Problem.cs b/AdventOfCode/Runner/Problem.cs index 4a965b0..e674470 100644 --- a/AdventOfCode/Runner/Problem.cs +++ b/AdventOfCode/Runner/Problem.cs @@ -1,89 +1,89 @@ -using AdventOfCode.Runner.Attributes; - -using System.Reflection; - -namespace AdventOfCode.Runner; - -public interface IProblem -{ - void LoadInput(); - - void CalculatePart1(); - - void PrintPart1(); - - void CalculatePart2(); - - void PrintPart2(); -} - -public abstract class Problem : Problem -{ -} - -public abstract class Problem : IProblem -{ - protected TPart1? Part1 { get; set; } - protected TPart2? Part2 { get; set; } - - public abstract void LoadInput(); - - public abstract void CalculatePart1(); - - public virtual void PrintPart1() - { - Console.ForegroundColor = ConsoleColor.Gray; - if (Part1 == null) - { - Console.Write("Part 1: "); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("No Solution"); - } - else - { - Console.Write("Part 1: "); - Console.ForegroundColor = ConsoleColor.DarkYellow; - Console.WriteLine($"{Part1}"); - } - Console.ForegroundColor = ConsoleColor.Gray; - } - - public abstract void CalculatePart2(); - - public virtual void PrintPart2() - { - Console.ForegroundColor = ConsoleColor.Gray; - if (Part2 == null) - { - Console.Write("Part 2: "); - Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("No Solution"); - } - else - { - Console.Write("Part 2: "); - Console.ForegroundColor = ConsoleColor.DarkYellow; - Console.WriteLine($"{Part2}"); - } - Console.ForegroundColor = ConsoleColor.Gray; - } - - protected string GetInputFile(string filename = "input.txt") - { - var info = this.GetType().GetCustomAttribute(); - if (info == null) - return filename; - - return Path.Combine($"Problems/AOC{info.Year}/Day{info.Day}", filename); - } - - protected string[] ReadInputLines(string filename = "input.txt") - { - return File.ReadAllLines(GetInputFile(filename)); - } - - protected string ReadInputText(string filename = "input.txt") - { - return File.ReadAllText(GetInputFile(filename)); - } +using AdventOfCode.Runner.Attributes; + +using System.Reflection; + +namespace AdventOfCode.Runner; + +public interface IProblem +{ + void LoadInput(); + + void CalculatePart1(); + + void PrintPart1(); + + void CalculatePart2(); + + void PrintPart2(); +} + +public abstract class Problem : Problem +{ +} + +public abstract class Problem : IProblem +{ + protected TPart1? Part1 { get; set; } + protected TPart2? Part2 { get; set; } + + public abstract void LoadInput(); + + public abstract void CalculatePart1(); + + public virtual void PrintPart1() + { + Console.ForegroundColor = ConsoleColor.Gray; + if (Part1 == null) + { + Console.Write("Part 1: "); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("No Solution"); + } + else + { + Console.Write("Part 1: "); + Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine($"{Part1}"); + } + Console.ForegroundColor = ConsoleColor.Gray; + } + + public abstract void CalculatePart2(); + + public virtual void PrintPart2() + { + Console.ForegroundColor = ConsoleColor.Gray; + if (Part2 == null) + { + Console.Write("Part 2: "); + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine("No Solution"); + } + else + { + Console.Write("Part 2: "); + Console.ForegroundColor = ConsoleColor.DarkYellow; + Console.WriteLine($"{Part2}"); + } + Console.ForegroundColor = ConsoleColor.Gray; + } + + protected string GetInputFile(string filename = "input.txt") + { + var info = this.GetType().GetCustomAttribute(); + if (info == null) + return filename; + + return Path.Combine($"Problems/AOC{info.Year}/Day{info.Day}", filename); + } + + protected string[] ReadInputLines(string filename = "input.txt") + { + return File.ReadAllLines(GetInputFile(filename)); + } + + protected string ReadInputText(string filename = "input.txt") + { + return File.ReadAllText(GetInputFile(filename)); + } } \ No newline at end of file diff --git a/AdventOfCode/Utils/Extensions.cs b/AdventOfCode/Utils/Extensions.cs index 80baa42..3a7904a 100644 --- a/AdventOfCode/Utils/Extensions.cs +++ b/AdventOfCode/Utils/Extensions.cs @@ -1,16 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace AdventOfCode.Utils; -public static class Extensions -{ - - - public static string AsJoinedString(this IEnumerable data, string delim = ", ") - { - return string.Join(delim, data); - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace AdventOfCode.Utils; +public static class Extensions +{ + public static string AsJoinedString(this IEnumerable data, string delim = ", ") + { + return string.Join(delim, data); + } + + public static T Mod(this T value, T divisor) where T : INumber + { + T remainder = value % divisor; + + if (remainder < T.Zero) + return remainder + divisor; + else + return remainder; + } +} diff --git a/AdventOfCode/Utils/Models/Common.cs b/AdventOfCode/Utils/Models/Common.cs index 7183ef1..3107a08 100644 --- a/AdventOfCode/Utils/Models/Common.cs +++ b/AdventOfCode/Utils/Models/Common.cs @@ -1,48 +1,48 @@ -using System.Numerics; - -namespace AdventOfCode.Utils.Models; - -public record struct Vec2(T X, T Y) where T : INumber -{ - public static Vec2 Zero => new (T.Zero, T.Zero); - public static Vec2 One => new (T.One, T.One); - - public readonly Vec2 YX => new(Y, X); - public readonly Vec2 YY => new(Y, Y); - public readonly Vec2 XX => new(X, X); - public static Vec2 Splat(T v) => new(v, v); - public static Vec2 operator +(Vec2 left, Vec2 right) => new Vec2(left.X + right.X, left.Y + right.Y); - public static Vec2 operator -(Vec2 left, Vec2 right) => new Vec2(left.X - right.X, left.Y - right.Y); - public static Vec2 operator -(Vec2 vec) => new Vec2(-vec.X, -vec.Y); - public static Vec2 operator *(Vec2 left, T right) => new Vec2(left.X * right, left.Y * right); - public static Vec2 operator *(T left, Vec2 right) => new Vec2(right.X * left, right.Y * left); - public static Vec2 operator /(Vec2 left, T right) => new Vec2(left.X / right, left.Y / right); - - public T DistanceSq(Vec2 other) - { - var a = other.X - this.X; - var b = other.Y - this.Y; - return (a * a) + (b * b); - } -} - -public record struct Vec3(T X, T Y, T Z) where T : INumber -{ - public static Vec3 Zero => new(T.Zero, T.Zero, T.Zero); - public static Vec3 One => new(T.One, T.One, T.One); - public static Vec3 Splat(T v) => new(v, v, v); - public static Vec3 operator +(Vec3 left, Vec3 right) => new Vec3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); - public static Vec3 operator -(Vec3 left, Vec3 right) => new Vec3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); - public static Vec3 operator -(Vec3 vec) => new Vec3(-vec.X, -vec.Y, -vec.Z); - public static Vec3 operator *(Vec3 left, T right) => new Vec3(left.X * right, left.Y * right, left.Z * right); - public static Vec3 operator *(T left, Vec3 right) => new Vec3(right.X * left, right.Y * left, right.Z * left); - public static Vec3 operator /(Vec3 left, T right) => new Vec3(left.X / right, left.Y / right, left.Z / right); - - public T DistanceSq(Vec3 other) - { - var a = other.X - this.X; - var b = other.Y - this.Y; - var c = other.Z - this.Z; - return (a * a) + (b * b) + (c * c); - } +using System.Numerics; + +namespace AdventOfCode.Utils.Models; + +public record struct Vec2(T X, T Y) where T : INumber +{ + public static Vec2 Zero => new (T.Zero, T.Zero); + public static Vec2 One => new (T.One, T.One); + + public readonly Vec2 YX => new(Y, X); + public readonly Vec2 YY => new(Y, Y); + public readonly Vec2 XX => new(X, X); + public static Vec2 Splat(T v) => new(v, v); + public static Vec2 operator +(Vec2 left, Vec2 right) => new Vec2(left.X + right.X, left.Y + right.Y); + public static Vec2 operator -(Vec2 left, Vec2 right) => new Vec2(left.X - right.X, left.Y - right.Y); + public static Vec2 operator -(Vec2 vec) => new Vec2(-vec.X, -vec.Y); + public static Vec2 operator *(Vec2 left, T right) => new Vec2(left.X * right, left.Y * right); + public static Vec2 operator *(T left, Vec2 right) => new Vec2(right.X * left, right.Y * left); + public static Vec2 operator /(Vec2 left, T right) => new Vec2(left.X / right, left.Y / right); + + public T DistanceSq(Vec2 other) + { + var a = other.X - this.X; + var b = other.Y - this.Y; + return (a * a) + (b * b); + } +} + +public record struct Vec3(T X, T Y, T Z) where T : INumber +{ + public static Vec3 Zero => new(T.Zero, T.Zero, T.Zero); + public static Vec3 One => new(T.One, T.One, T.One); + public static Vec3 Splat(T v) => new(v, v, v); + public static Vec3 operator +(Vec3 left, Vec3 right) => new Vec3(left.X + right.X, left.Y + right.Y, left.Z + right.Z); + public static Vec3 operator -(Vec3 left, Vec3 right) => new Vec3(left.X - right.X, left.Y - right.Y, left.Z - right.Z); + public static Vec3 operator -(Vec3 vec) => new Vec3(-vec.X, -vec.Y, -vec.Z); + public static Vec3 operator *(Vec3 left, T right) => new Vec3(left.X * right, left.Y * right, left.Z * right); + public static Vec3 operator *(T left, Vec3 right) => new Vec3(right.X * left, right.Y * left, right.Z * left); + public static Vec3 operator /(Vec3 left, T right) => new Vec3(left.X / right, left.Y / right, left.Z / right); + + public T DistanceSq(Vec3 other) + { + var a = other.X - this.X; + var b = other.Y - this.Y; + var c = other.Z - this.Z; + return (a * a) + (b * b) + (c * c); + } } \ No newline at end of file diff --git a/AdventOfCode/Utils/QuickMath.cs b/AdventOfCode/Utils/QuickMath.cs index 12a8c67..2f9990d 100644 --- a/AdventOfCode/Utils/QuickMath.cs +++ b/AdventOfCode/Utils/QuickMath.cs @@ -1,37 +1,37 @@ -namespace AdventOfCode.Utils; - -public static class QuickMath -{ - private static readonly long[] pow10Long = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000]; - private static readonly int[] pow10int = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; - - public static long FastPow10(long exp) - { - return pow10Long[exp]; - } - - public static int FastPow10(int exp) - { - return pow10int[exp]; - } - - private static readonly long[] longCorrectionTable= [9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999, 9999999999999999, 99999999999999999, 999999999999999999]; - private static readonly int[] intCorrectionTable = [9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999]; - public static long DigitCount(this long value) - { - var l2 = 63 - long.LeadingZeroCount(value | 1); - var ans = ((9 * l2) >> 5); - if (value > longCorrectionTable[ans]) - ans += 1; - return ans + 1; - } - - public static int DigitCount(this int value) - { - var l2 = 31 - int.LeadingZeroCount(value | 1); - var ans = ((9 * l2) >> 5); - if (value > intCorrectionTable[ans]) - ans += 1; - return ans + 1; - } +namespace AdventOfCode.Utils; + +public static class QuickMath +{ + private static readonly long[] pow10Long = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, 100000000000000000, 1000000000000000000]; + private static readonly int[] pow10int = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000]; + + public static long FastPow10(long exp) + { + return pow10Long[exp]; + } + + public static int FastPow10(int exp) + { + return pow10int[exp]; + } + + private static readonly long[] longCorrectionTable= [9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999, 9999999999, 99999999999, 999999999999, 9999999999999, 99999999999999, 999999999999999, 9999999999999999, 99999999999999999, 999999999999999999]; + private static readonly int[] intCorrectionTable = [9, 99, 999, 9999, 99999, 999999, 9999999, 99999999, 999999999]; + public static long DigitCount(this long value) + { + var l2 = 63 - long.LeadingZeroCount(value | 1); + var ans = ((9 * l2) >> 5); + if (value > longCorrectionTable[ans]) + ans += 1; + return ans + 1; + } + + public static int DigitCount(this int value) + { + var l2 = 31 - int.LeadingZeroCount(value | 1); + var ans = ((9 * l2) >> 5); + if (value > intCorrectionTable[ans]) + ans += 1; + return ans + 1; + } } \ No newline at end of file