Compare commits

..

12 Commits

Author SHA1 Message Date
625a9e5ad5 Aoc 2025 day 1 2025-12-01 21:21:14 -05:00
ef959284a5 misc 2025-04-21 09:58:20 -04:00
bba775fd4e wip day 12 2025-02-09 14:21:48 -05:00
f16899ff3c wip day 12 part 2 2025-02-08 17:22:39 -05:00
6606f40df9 day 12 part 1 2024-12-23 21:10:08 -05:00
199b940ff9 misc 2024-12-18 23:14:11 -05:00
63eb4d01b0 day 11 part 2 2024-12-18 23:13:40 -05:00
a33843ae1b Day 11 part 1 2024-12-18 21:59:43 -05:00
e08a60614a Merge branch 'master' of https://github.com/Amatsugu/AdventOfCode 2024-12-17 19:44:33 -05:00
6a9c813d08 day 10 2024-12-17 19:44:30 -05:00
ba7e6d4be0 Update DiskFragmenter.cs 2024-12-17 09:40:42 -05:00
a4cb169566 fix part 2 2024-12-17 09:40:15 -05:00
79 changed files with 7244 additions and 6631 deletions

126
.gitattributes vendored
View File

@@ -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

726
.gitignore vendored
View File

@@ -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

View File

@@ -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

View File

@@ -1,81 +1,83 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Problems\*\*\*.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Problems\*\*\*.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Remove="Problems\AOC2022\Day10\input.txt" />
<None Remove="Problems\AOC2022\Day10\sara.txt" />
<None Remove="Problems\AOC2022\Day10\simple.txt" />
<None Remove="Problems\AOC2022\Day10\test.txt" />
<None Remove="Problems\AOC2022\Day11\input.txt" />
<None Remove="Problems\AOC2022\Day11\test.txt" />
<None Remove="Problems\AOC2022\Day3\input.txt" />
<None Remove="Problems\AOC2022\Day3\test.txt" />
<None Remove="Problems\AOC2022\Day4\input.txt" />
<None Remove="Problems\AOC2022\Day4\test.txt" />
<None Remove="Problems\AOC2022\Day5\input.txt" />
<None Remove="Problems\AOC2022\Day5\test.txt" />
<None Remove="Problems\AOC2022\Day6\input.txt" />
<None Remove="Problems\AOC2022\Day6\test.txt" />
<None Remove="Problems\AOC2022\Day8\input.txt" />
<None Remove="Problems\AOC2022\Day8\test.txt" />
<None Remove="Problems\AOC2022\Day9\input.txt" />
<None Remove="Problems\AOC2022\Day9\test.txt" />
<None Remove="Problems\AOC2022\Day9\test2.txt" />
<None Remove="problems\aoc2023\day10\input.txt" />
<None Remove="problems\aoc2023\day10\sample.txt" />
<None Remove="problems\aoc2023\day11\input.txt" />
<None Remove="problems\aoc2023\day11\sample.txt" />
<None Remove="problems\aoc2023\day12\input.txt" />
<None Remove="problems\aoc2023\day12\sample.txt" />
<None Remove="problems\aoc2023\day1\input.txt" />
<None Remove="problems\aoc2023\day2\input.txt" />
<None Remove="problems\aoc2023\day3\input.txt" />
<None Remove="problems\aoc2023\day3\sample.txt" />
<None Remove="problems\aoc2023\day3\sara.txt" />
<None Remove="problems\aoc2023\day4\input.txt" />
<None Remove="problems\aoc2023\day4\sample.txt" />
<None Remove="problems\aoc2023\day5\input.txt" />
<None Remove="problems\aoc2023\day5\sample.txt" />
<None Remove="problems\aoc2023\day6\input.txt" />
<None Remove="problems\aoc2023\day6\sample.txt" />
<None Remove="problems\aoc2023\day7\input.txt" />
<None Remove="problems\aoc2023\day7\sample.txt" />
<None Remove="problems\aoc2023\day7\sara.txt" />
<None Remove="problems\aoc2023\day8\input.txt" />
<None Remove="problems\aoc2023\day8\sample.txt" />
<None Remove="problems\aoc2023\day9\input.txt" />
<None Remove="problems\aoc2023\day9\sample.txt" />
<None Remove="problems\aoc2023\day9\sara.txt" />
</ItemGroup>
<ItemGroup>
<Folder Include="Problems\AOC2015\" />
<Folder Include="Problems\AOC2021\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Superpower" Version="3.0.0" />
</ItemGroup>
</Project>
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="Problems\*\*\*.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Problems\*\*\*.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Remove="Problems\AOC2022\Day10\input.txt" />
<None Remove="Problems\AOC2022\Day10\sara.txt" />
<None Remove="Problems\AOC2022\Day10\simple.txt" />
<None Remove="Problems\AOC2022\Day10\test.txt" />
<None Remove="Problems\AOC2022\Day11\input.txt" />
<None Remove="Problems\AOC2022\Day11\test.txt" />
<None Remove="Problems\AOC2022\Day3\input.txt" />
<None Remove="Problems\AOC2022\Day3\test.txt" />
<None Remove="Problems\AOC2022\Day4\input.txt" />
<None Remove="Problems\AOC2022\Day4\test.txt" />
<None Remove="Problems\AOC2022\Day5\input.txt" />
<None Remove="Problems\AOC2022\Day5\test.txt" />
<None Remove="Problems\AOC2022\Day6\input.txt" />
<None Remove="Problems\AOC2022\Day6\test.txt" />
<None Remove="Problems\AOC2022\Day8\input.txt" />
<None Remove="Problems\AOC2022\Day8\test.txt" />
<None Remove="Problems\AOC2022\Day9\input.txt" />
<None Remove="Problems\AOC2022\Day9\test.txt" />
<None Remove="Problems\AOC2022\Day9\test2.txt" />
<None Remove="problems\aoc2023\day10\input.txt" />
<None Remove="problems\aoc2023\day10\sample.txt" />
<None Remove="problems\aoc2023\day11\input.txt" />
<None Remove="problems\aoc2023\day11\sample.txt" />
<None Remove="problems\aoc2023\day12\input.txt" />
<None Remove="problems\aoc2023\day12\sample.txt" />
<None Remove="problems\aoc2023\day1\input.txt" />
<None Remove="problems\aoc2023\day2\input.txt" />
<None Remove="problems\aoc2023\day3\input.txt" />
<None Remove="problems\aoc2023\day3\sample.txt" />
<None Remove="problems\aoc2023\day3\sara.txt" />
<None Remove="problems\aoc2023\day4\input.txt" />
<None Remove="problems\aoc2023\day4\sample.txt" />
<None Remove="problems\aoc2023\day5\input.txt" />
<None Remove="problems\aoc2023\day5\sample.txt" />
<None Remove="problems\aoc2023\day6\input.txt" />
<None Remove="problems\aoc2023\day6\sample.txt" />
<None Remove="problems\aoc2023\day7\input.txt" />
<None Remove="problems\aoc2023\day7\sample.txt" />
<None Remove="problems\aoc2023\day7\sara.txt" />
<None Remove="problems\aoc2023\day8\input.txt" />
<None Remove="problems\aoc2023\day8\sample.txt" />
<None Remove="problems\aoc2023\day9\input.txt" />
<None Remove="problems\aoc2023\day9\sample.txt" />
<None Remove="problems\aoc2023\day9\sara.txt" />
</ItemGroup>
<ItemGroup>
<Folder Include="Problems\AOC2015\" />
<Folder Include="Problems\AOC2021\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MaybeError" Version="1.2.0" />
<PackageReference Include="Superpower" Version="3.1.1-dev-00257" />
<PackageReference Include="ZLinq" Version="1.5.4" />
</ItemGroup>
</Project>

View File

@@ -1,2 +1,2 @@
*/*/*.txt
*/*/*.txt
*/*/*.csv

View File

@@ -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<int, int>
{
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<int, int>
{
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;
}
}

View File

@@ -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<int, int>
{
private string[] _inputData = Array.Empty<string>();
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<string, List<int>>();
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<int>() { 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<int, int>
{
private string[] _inputData = Array.Empty<string>();
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<string, List<int>>();
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<int>() { 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
};
}
}

View File

@@ -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<int, int>
{
private int[] _input = Array.Empty<int>();
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<int, int>
{
private int[] _input = Array.Empty<int>();
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);
}
}
}

View File

@@ -1,72 +1,72 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2019.Day2
{
[ProblemInfo(2019, 2, "Program Alarm")]
public class IntCode : Problem<int, int>
{
private int[] _inputPart1 = Array.Empty<int>();
private int[] _inputPart2 = Array.Empty<int>();
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<int, int>
{
private int[] _inputPart1 = Array.Empty<int>();
private int[] _inputPart2 = Array.Empty<int>();
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;
}
}
}
}
}
}

View File

@@ -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<int, int>
{
private string[] _inputLines = Array.Empty<string>();
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<WireSegment> 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<WireSegment> A, List<WireSegment> 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<WireSegment> CreateWire(string[] wires)
{
var wireSegments = new List<WireSegment>();
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<int, int>
{
private string[] _inputLines = Array.Empty<string>();
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<WireSegment> 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<WireSegment> A, List<WireSegment> 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<WireSegment> CreateWire(string[] wires)
{
var wireSegments = new List<WireSegment>();
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);
}
}
}

View File

@@ -1,147 +1,147 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2019.Day4
{
[ProblemInfo(2019, 4, "Secure Container")]
public class SecureContainer : Problem<int, int>
{
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<int, int>
{
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);
}
}
}

View File

@@ -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<int, int>
{
private IntCodeV2 _cpu = new IntCodeV2();
private int[] _baseInput = Array.Empty<int>();
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<int, int>
{
private IntCodeV2 _cpu = new IntCodeV2();
private int[] _baseInput = Array.Empty<int>();
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"));
}
}

View File

@@ -1,233 +1,233 @@
namespace AdventOfCode.Day_5
{
public class IntCodeV2
{
public struct Instruction
{
public int opcode;
public int paramCount;
public Func<int[], int[], int, int, int, bool> action;
public Instruction(int opcode, int paramCount, Func<int[], int[], int, int, int, bool> 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<int, Instruction> _instructions;
private int _instructionPointer;
private int[]? _inputBuffer;
private int _inputCounter = 0;
private int[]? _outputBuffer;
private int _outputCounter = 0;
private int[] memory = Array.Empty<int>();
public IntCodeV2(bool persistentMode = false, bool suspendOnOutput = false)
{
_instructions = new Dictionary<int, Instruction>();
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<int>();
_outputBuffer = outputBuffer ?? Array.Empty<int>();
}
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<int[], int[], int, int, int, bool> action;
public Instruction(int opcode, int paramCount, Func<int[], int[], int, int, int, bool> 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<int, Instruction> _instructions;
private int _instructionPointer;
private int[]? _inputBuffer;
private int _inputCounter = 0;
private int[]? _outputBuffer;
private int _outputCounter = 0;
private int[] memory = Array.Empty<int>();
public IntCodeV2(bool persistentMode = false, bool suspendOnOutput = false)
{
_instructions = new Dictionary<int, Instruction>();
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<int>();
_outputBuffer = outputBuffer ?? Array.Empty<int>();
}
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;
}
}
}

View File

@@ -1,119 +1,119 @@
namespace AdventOfCode.Problems.AOC2019.Day6
{
public class OrbitMap
{
public CelestialObject root;
public Dictionary<string, CelestialObject> objectMap;
public OrbitMap(string[] orbits)
{
objectMap = new Dictionary<string, CelestialObject>();
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<CelestialObject> FindPathTo(string name)
{
var path = new List<CelestialObject>();
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<CelestialObject> children;
public CelestialObject(string name)
{
children = new List<CelestialObject>();
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<CelestialObject> 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<string, CelestialObject> objectMap;
public OrbitMap(string[] orbits)
{
objectMap = new Dictionary<string, CelestialObject>();
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<CelestialObject> FindPathTo(string name)
{
var path = new List<CelestialObject>();
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<CelestialObject> children;
public CelestialObject(string name)
{
children = new List<CelestialObject>();
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<CelestialObject> 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;
}
}
}
}

View File

@@ -1,53 +1,53 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2019.Day6;
[ProblemInfo(2019, 6, "Universal Orbit Map")]
internal class UniversalOrbits : Problem<int, int>
{
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<string> 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<int, int>
{
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<string> 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());
}
}

View File

@@ -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<int, int>
{
private int[] _code = Array.Empty<int>();
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<int, int>
{
private int[] _code = Array.Empty<int>();
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;
}
}
}

View File

@@ -1,83 +1,83 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2019.Day8
{
[ProblemInfo(2019, 8, "Space Image Format")]
public class SpaceImageFormat : Problem<int, string>
{
private int[] _imageData = Array.Empty<int>();
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<int, string>
{
private int[] _imageData = Array.Empty<int>();
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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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<int, int>, IEnumerable<byte>
{
public byte[] dataPart1 = Array.Empty<byte>();
public byte[] dataPart2 = Array.Empty<byte>();
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<byte> GetEnumerator()
{
return ((IEnumerable<byte>)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<int, int>, IEnumerable<byte>
{
public byte[] dataPart1 = Array.Empty<byte>();
public byte[] dataPart2 = Array.Empty<byte>();
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<byte> GetEnumerator()
{
return ((IEnumerable<byte>)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();
// }
//}
}

View File

@@ -1,71 +1,71 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2021.Day3;
[ProblemInfo(2021, 3, "Binary Diagnostic")]
public class BinaryDiagnostic : Problem<int, int>
{
public int[][] Data { get; set; } = Array.Empty<int[]>();
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<int, int>
{
public int[][] Data { get; set; } = Array.Empty<int[]>();
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;
}
}

View File

@@ -1,50 +1,50 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2021.Day6;
[ProblemInfo(2021, 6, "Lanternfish")]
internal class LanternFish : Problem<long, long>
{
public int[] Data { get; private set; } = Array.Empty<int>();
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<long, long>
{
public int[] Data { get; private set; } = Array.Empty<int>();
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();
}
}

View File

@@ -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");
}
}

View File

@@ -1,54 +1,54 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2022.Day1;
[ProblemInfo(2022, 1, "Calorie Counting")]
internal class CalorieCounting : Problem
{
public List<List<int>> FlaresFood { get; set; }
private (int calories, int elf)? _mostestElf;
private IEnumerable<(int sum, int idx)>? _mostestElves;
public CalorieCounting()
{
FlaresFood = new List<List<int>>
{
new List<int>()
};
}
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<int>());
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<List<int>> FlaresFood { get; set; }
private (int calories, int elf)? _mostestElf;
private IEnumerable<(int sum, int idx)>? _mostestElves;
public CalorieCounting()
{
FlaresFood = new List<List<int>>
{
new List<int>()
};
}
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<int>());
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();
}
}

View File

@@ -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<int, int, int>? 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<int, int> 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<int, int, int>? 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<int, int> 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++;
}
}
}

View File

@@ -1,55 +1,55 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2022.Day10;
[ProblemInfo(2022, 10, "Cathode-Ray Tube")]
internal class CathodeRayTube : Problem<int, string>
{
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<CathodeCPU.Instruction>(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<int, string>
{
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<CathodeCPU.Instruction>(instruction[0], true), int.Parse(instruction[1]));
}
}
}
}

View File

@@ -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<BigInteger> 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<BigInteger>();
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<BigInteger> 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<BigInteger>();
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)}]";
}
}

View File

@@ -1,60 +1,60 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2022.Day11;
[ProblemInfo(2022, 11, "Monkey in the Middle")]
internal class MonkeyInTheMiddle : Problem<int, int>
{
private Monkey[] _monkeysPart1 = Array.Empty<Monkey>();
private Monkey[] _monkeysPart2 = Array.Empty<Monkey>();
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<int, int>
{
private Monkey[] _monkeysPart1 = Array.Empty<Monkey>();
private Monkey[] _monkeysPart2 = Array.Empty<Monkey>();
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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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();
}
}

View File

@@ -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<string>();
}
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<string>();
}
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();
}
}

View File

@@ -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<string>();
}
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<string>();
}
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();
}
}

View File

@@ -1,63 +1,63 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2022.Day4;
[ProblemInfo(2022, 4, "Camp Cleanup")]
internal class CampCleanup : Problem<int, int>
{
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<int, int>
{
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);
}
}

View File

@@ -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<char>[] _stacksPart1 = Array.Empty<List<char>>();
private List<char>[] _stacksPart2 = Array.Empty<List<char>>();
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<char>[] 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<char>[] 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<List<char>>();
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<char>() { 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<char> ParseCrateLine(string line)
{
var result = new List<char>(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<char>[] _stacksPart1 = Array.Empty<List<char>>();
private List<char>[] _stacksPart2 = Array.Empty<List<char>>();
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<char>[] 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<char>[] 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<List<char>>();
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<char>() { 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<char> ParseCrateLine(string line)
{
var result = new List<char>(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();
}

View File

@@ -1,35 +1,35 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2022.Day6;
[ProblemInfo(2022, 6, "Tuning Trouble")]
internal class TuningTrouble : Problem<int, int>
{
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<int, int>
{
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();
}
}

View File

@@ -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<DirectoryNode> 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<DirectoryNode> Where(Func<DirectoryNode, bool> filter)
{
var result = new List<DirectoryNode>();
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<DirectoryNode> 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<DirectoryNode> Where(Func<DirectoryNode, bool> filter)
{
var result = new List<DirectoryNode>();
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}";
}
}

View File

@@ -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<int, int>
{
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<string>();
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<string> 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<int, int>
{
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<string>();
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<string> 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;
}
}
}

View File

@@ -1,99 +1,99 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2022.Day8;
[ProblemInfo(2022, 8, "Treetop Tree House")]
internal class TreetopTreeHouse : Problem<int, int>
{
private int[][] _input = Array.Empty<int[]>();
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<int, int>
{
private int[][] _input = Array.Empty<int[]>();
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;
}
}

View File

@@ -1,31 +1,31 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2022.Day9;
[ProblemInfo(2022, 9, "Rope Bridge")]
internal class RopeBridge : Problem<int, int>
{
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<RopeSimulator.Direction>(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<int, int>
{
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<RopeSimulator.Direction>(move.First()), int.Parse(move.Last())))
.ToArray();
}
}

View File

@@ -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);
}
}

View File

@@ -1,97 +1,97 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2023.Day1;
[ProblemInfo(2023, 1, "Trebuchet!?")]
public partial class Trebuchet : Problem<int, int>
{
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<int, int>
{
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);
}
}

View File

@@ -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<int, int>
{
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<int, int>
{
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();
}
}

View File

@@ -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<int, long>
{
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<int, long>
{
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();
}
}

View File

@@ -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<int, int>
{
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<int, int>
{
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;
}
};
}

View File

@@ -1,31 +1,31 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2023.Day2;
[ProblemInfo(2023, 2, "Cube Conundrum")]
internal class CubeConundrum : Problem<int, int>
{
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<int> 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<int, int>
{
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<int> FindPossibleGames(CubeRound constraints)
{
return _gameInfo.Where(g => !g.Rounds.Any(r => !r.IsPossible(constraints)))
.Select(r => r.Id);
}
}

View File

@@ -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;
}
};

View File

@@ -1,136 +1,136 @@
using AdventOfCode.Runner.Attributes;
namespace AdventOfCode.Problems.AOC2023.Day3;
[ProblemInfo(2023, 3, "Gear Ratios")]
internal class GearRatios : Problem<int, int>
{
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<int>();
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<int>();
var curNums = new List<int>();
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<int> 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<int, int>
{
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<int>();
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<int>();
var curNums = new List<int>();
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<int> 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]);
}
}

View File

@@ -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<double, int>
{
private (int card, int[] win, int[] have)[] _cards = [];
private readonly Dictionary<int, int> _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<double, int>
{
private (int card, int[] win, int[] have)[] _cards = [];
private readonly Dictionary<int, int> _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());
}
}
}

View File

@@ -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<Category, CategoryMapper> destinations = [];
public CategoryEvaluator(CategoryMapper[] mappers)
{
destinations = mappers.ToDictionary(m => m.Destination);
}
public long Evaluate(Category source, long sourceValue, Category destination)
{
var mappers = new List<CategoryMapper>();
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<CategoryMapper>();
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<Category, CategoryMapper> destinations = [];
public CategoryEvaluator(CategoryMapper[] mappers)
{
destinations = mappers.ToDictionary(m => m.Destination);
}
public long Evaluate(Category source, long sourceValue, Category destination)
{
var mappers = new List<CategoryMapper>();
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<CategoryMapper>();
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
}
}

View File

@@ -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<CategoryEvaluator.Category>(names[0], true);
var dst = Enum.Parse<CategoryEvaluator.Category>(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<CategoryEvaluator.Category>(names[0], true);
var dst = Enum.Parse<CategoryEvaluator.Category>(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}";
}
}

View File

@@ -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<long, long>
{
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<long, long>
{
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);
}
}

View File

@@ -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<int, long>
{
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<int>();
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<int, long>
{
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<int>();
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++;
}
}
}

View File

@@ -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<int, int>
{
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<int, int>
{
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();
}
}

View File

@@ -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<CamelHand>
{
public static readonly List<char> CARDS = [ '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A' ];
public static readonly List<char> 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<CamelHand>
{
public static readonly List<char> CARDS = [ '2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A' ];
public static readonly List<char> 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
}
}

View File

@@ -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<int, long>
{
private string _path = string.Empty;
private Dictionary<string, (string left, string right)> _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<int, long>
{
private string _path = string.Empty;
private Dictionary<string, (string left, string right)> _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();
}
}

View File

@@ -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<long, long>
{
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<List<long>>
{
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<List<long>> 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<long, long>
{
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<List<long>>
{
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<List<long>> 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();
}
}

View File

@@ -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<int, int>
{
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<int, int>
{
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();
}
}

View File

@@ -1,25 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AdventOfCode.Problems.AOC2024.Day10;
//[ProblemInfo(2024, 10, "Hoof It")]
internal class HoofIt : Problem
{
public override void CalculatePart1()
{
throw new NotImplementedException();
}
public override void CalculatePart2()
{
throw new NotImplementedException();
}
public override void LoadInput()
{
throw new NotImplementedException();
}
}
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<int, int>
{
private int[][] _data = [];
public static Vec2<int>[] 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<int> pos)
{
return GetScore(pos, []);
}
public (int score, int scoreDistinct) GetScore(Vec2<int> pos, HashSet<Vec2<int>> 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<int> 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();
}
}

View File

@@ -1,25 +1,115 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AdventOfCode.Problems.AOC2024.Day11;
//[ProblemInfo(2024, 11, "Plutonian Pebbles")]
internal class PlutonianPebbles : Problem
{
public override void CalculatePart1()
{
throw new NotImplementedException();
}
public override void CalculatePart2()
{
throw new NotImplementedException();
}
public override void LoadInput()
{
throw new NotImplementedException();
}
}
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<long, long>
{
private List<long> _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<long>(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<long> 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<long> 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();
}
}

View File

@@ -0,0 +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<int, int>
{
private char[][] _data = [];
public static readonly Vec2<int>[] 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<List<Vec2<int>>> GroupSides(List<Vec2<int>> outline, List<Vec2<int>> area)
{
var result = new List<List<Vec2<int>>>();
var visited = new HashSet<Vec2<int>>();
var open = new HashSet<Vec2<int>>(outline);
while (open.Count > 0)
{
var p = open.First();
open.Remove(p);
if(visited.Contains(p))
continue;
visited.Add(p);
var group = new List<Vec2<int>>() { p };
GetGroup(p, group);
result.Add(group);
}
void GetGroup(Vec2<int> point, List<Vec2<int>> 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<int> point, Vec2<int> dir, List<Vec2<int>> 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<Vec2<int>> area, List<List<Vec2<int>>> outline, char plant)
{
var (min, max) = GetBounds(outline.SelectMany(v => v).ToList());
int Sides(Vec2<int> point, List<Vec2<int>> 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<int>(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<Vec2<int>> 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<int>(x,y);
if (data.Contains(p))
output.Append(display);
else
output.Append(' ');
}
output.AppendLine();
}
Console.WriteLine(output);
}
public static (Vec2<int> min, Vec2<int> max) GetBounds(List<Vec2<int>> points)
{
var min = Vec2<int>.Splat(int.MaxValue);
var max = Vec2<int>.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<Vec2<int>> side, List<List<Vec2<int>>> sides, List<Vec2<int>> 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<List<Vec2<int>>> groups, List<Vec2<int>> area)
{
int Sides(Vec2<int> point, List<Vec2<int>> 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<Vec2<int>> area, int perimeter, List<Vec2<int>> outline)> FindPlots(char[][] data)
{
var visited = new HashSet<Vec2<int>>(data.Length * data[0].Length);
var results = new List<(char plant, List<Vec2<int>>, int perimeter, List<Vec2<int>> 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<int>(x, y);
if (visited.Contains(p))
continue;
var members = new List<Vec2<int>>();
var plant = data[y][x];
var perimeter = 0;
var outline = new List<Vec2<int>>();
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<int> point, HashSet<Vec2<int>> visited, List<Vec2<int>> members, ref int perimeter, List<Vec2<int>> 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<int> 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();
}
}

View File

@@ -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<int, int>
{
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<int> 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<int> Check(int[] report, Func<int, bool> check)
{
var fails = new List<int>();
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<int, int>
{
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<int> 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<int> Check(int[] report, Func<int, bool> check)
{
var fails = new List<int>();
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();
}
}

View File

@@ -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<int, int>
{
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\\((?<a>\\d+)\\,(?<b>\\d+)\\))|(do\\(\\))|(don't\\(\\))")]
private static partial Regex DosAndDonts();
[GeneratedRegex("mul\\((?<a>\\d+)\\,(?<b>\\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<int, int>
{
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\\((?<a>\\d+)\\,(?<b>\\d+)\\))|(do\\(\\))|(don't\\(\\))")]
private static partial Regex DosAndDonts();
[GeneratedRegex("mul\\((?<a>\\d+)\\,(?<b>\\d+)\\)")]
private static partial Regex Mul();
}

View File

@@ -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<int, int>
{
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<int, int>
{
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;
}
}

View File

@@ -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<Rule> _rules;
private PageNode _root;
public PageList(int[] pages, List<Rule> 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<Rule> GetRulesForPage(int page)
{
return _rules.Where(r => r.after == page).ToList();
}
public List<int> Traverse()
{
var list = new List<int>();
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<Rule> 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<Rule> _rules;
private PageNode _root;
public PageList(int[] pages, List<Rule> 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<Rule> GetRulesForPage(int page)
{
return _rules.Where(r => r.after == page).ToList();
}
public List<int> Traverse()
{
var list = new List<int>();
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<Rule> 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;
}
}

View File

@@ -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<int, int>
{
private List<Rule> _rules = [];
private List<int[]> 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<int> 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<int, int>
{
private List<Rule> _rules = [];
private List<int[]> 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<int> 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()));
}
}
}
}

View File

@@ -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<int> pos, int dir, int step);
namespace AdventOfCode.Problems.AOC2024.Day6;
[ProblemInfo(2024, 6, "Guard Gallivant")]
internal class GuardGallivant : Problem<int, int>
{
private char[][] _data = [];
private int _height;
private int _width;
public static readonly Vec2<int>[] 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<GuardNode>();
var found = new HashSet<Vec2<int>>();
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<int> 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<int> 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<GuardNode> Nodes { get; set; }
private readonly bool[][] _map;
private readonly int _height;
private readonly int _width;
public GuardMap(char[][] map, Vec2<int> 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<int> pos, GuardNode node)> GetPath()
{
return GetPath(Nodes);
}
public FrozenSet<Vec2<int>> GetPathSet(List<GuardNode> nodes)
{
var path = GetPath(nodes);
return path.Select(p => p.pos).ToFrozenSet();
}
public List<(Vec2<int> pos, GuardNode node)> GetPath(List<GuardNode> nodes)
{
var path = new List<(Vec2<int>, 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<int>(curNode.Pos.X, -1),
1 => new Vec2<int>(_width, curNode.Pos.Y),
2 => new Vec2<int>(curNode.Pos.X, _height),
3 => new Vec2<int>(-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<Vec2<int>> GetPointsBetween(Vec2<int> start, Vec2<int> end, int dir)
{
var result = new List<Vec2<int>>();
switch (dir)
{
case 0:
for (int i = start.Y; i > end.Y; i--)
result.Add(new Vec2<int>(start.X, i));
break;
case 1:
for (int i = start.X; i < end.X; i++)
result.Add(new Vec2<int>(i, start.Y));
break;
case 2:
for (int i = start.Y; i < end.Y; i++)
result.Add(new Vec2<int>(start.X, i));
break;
case 3:
for (int i = start.X; i > end.X; i--)
result.Add(new Vec2<int>(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<int> extraObsticle, List<GuardNode> 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<int> start, int dir, out Vec2<int> pos, Vec2<int>? extraObsticle = null)
{
if (extraObsticle is Vec2<int> 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<int> ex)
_map[ex.Y][ex.X] = false;
}
ResetExtraObsticle();
return false;
}
public void PrintBoard(List<GuardNode> nodes, Vec2<int> start, Vec2<int>? 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<int>(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<int> Pos { get; }
public int Direction { get; }
public int? Next { get; set; }
public GuardNode(Vec2<int> pos, int dir, int id)
{
Pos = pos;
Direction = dir;
Id = id;
}
public bool IsLoop(List<GuardNode> nodes)
{
return NodeExists(Id, nodes);
}
public bool NodeExists(int target, List<GuardNode> 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<int> pos, int dir, int step);
namespace AdventOfCode.Problems.AOC2024.Day6;
[ProblemInfo(2024, 6, "Guard Gallivant")]
internal class GuardGallivant : Problem<int, int>
{
private char[][] _data = [];
private int _height;
private int _width;
public static readonly Vec2<int>[] 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<GuardNode>();
var found = new HashSet<Vec2<int>>();
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<int> 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<int> 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<GuardNode> Nodes { get; set; }
private readonly bool[][] _map;
private readonly int _height;
private readonly int _width;
public GuardMap(char[][] map, Vec2<int> 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<int> pos, GuardNode node)> GetPath()
{
return GetPath(Nodes);
}
public FrozenSet<Vec2<int>> GetPathSet(List<GuardNode> nodes)
{
var path = GetPath(nodes);
return path.Select(p => p.pos).ToFrozenSet();
}
public List<(Vec2<int> pos, GuardNode node)> GetPath(List<GuardNode> nodes)
{
var path = new List<(Vec2<int>, 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<int>(curNode.Pos.X, -1),
1 => new Vec2<int>(_width, curNode.Pos.Y),
2 => new Vec2<int>(curNode.Pos.X, _height),
3 => new Vec2<int>(-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<Vec2<int>> GetPointsBetween(Vec2<int> start, Vec2<int> end, int dir)
{
var result = new List<Vec2<int>>();
switch (dir)
{
case 0:
for (int i = start.Y; i > end.Y; i--)
result.Add(new Vec2<int>(start.X, i));
break;
case 1:
for (int i = start.X; i < end.X; i++)
result.Add(new Vec2<int>(i, start.Y));
break;
case 2:
for (int i = start.Y; i < end.Y; i++)
result.Add(new Vec2<int>(start.X, i));
break;
case 3:
for (int i = start.X; i > end.X; i--)
result.Add(new Vec2<int>(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<int> extraObsticle, List<GuardNode> 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<int> start, int dir, out Vec2<int> pos, Vec2<int>? extraObsticle = null)
{
if (extraObsticle is Vec2<int> 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<int> ex)
_map[ex.Y][ex.X] = false;
}
ResetExtraObsticle();
return false;
}
public void PrintBoard(List<GuardNode> nodes, Vec2<int> start, Vec2<int>? 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<int>(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<int> Pos { get; }
public int Direction { get; }
public int? Next { get; set; }
public GuardNode(Vec2<int> pos, int dir, int id)
{
Pos = pos;
Direction = dir;
Id = id;
}
public bool IsLoop(List<GuardNode> nodes)
{
return NodeExists(Id, nodes);
}
public bool NodeExists(int target, List<GuardNode> 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}";
}
}

View File

@@ -1,70 +1,70 @@
namespace AdventOfCode.Problems.AOC2024.Day7;
[ProblemInfo(2024, 7, "Bridge Repair")]
internal class BridgeRepair : Problem<ulong, ulong>
{
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<ulong, ulong>
{
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));
}
}
}

View File

@@ -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<int, int>
{
private string[] _map = [];
private int _width;
private int _height;
private FrozenDictionary<char, List<Vec2<int>>> _nodes = FrozenDictionary<char, List<Vec2<int>>>.Empty;
public override void CalculatePart1()
{
var antiNodes = new List<Vec2<int>>();
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<Vec2<int>> antinodes)
{
Console.WriteLine();
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
Console.ResetColor();
var p = new Vec2<int>(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<int> pos)
{
if (pos.X < 0 || pos.Y < 0)
return false;
if (pos.X >= _width || pos.Y >= _height)
return false;
return true;
}
private Vec2<int>[] GetAntiNodes(Vec2<int> a, Vec2<int> b)
{
var dir = a - b;
var aNode1 = dir + a;
var aNode2 = -dir + b;
return [aNode1, aNode2];
}
private Vec2<int>[] GetHarmonicAntiNodes(Vec2<int> a, Vec2<int> b)
{
var dir = a - b;
List<Vec2<int>> GetNodes(Vec2<int> start, Vec2<int> dir)
{
var results = new List<Vec2<int>>();
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<Vec2<int>>();
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<char, List<Vec2<int>>>();
_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<int>(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<int, int>
{
private string[] _map = [];
private int _width;
private int _height;
private FrozenDictionary<char, List<Vec2<int>>> _nodes = FrozenDictionary<char, List<Vec2<int>>>.Empty;
public override void CalculatePart1()
{
var antiNodes = new List<Vec2<int>>();
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<Vec2<int>> antinodes)
{
Console.WriteLine();
for (int y = 0; y < _height; y++)
{
for (int x = 0; x < _width; x++)
{
Console.ResetColor();
var p = new Vec2<int>(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<int> pos)
{
if (pos.X < 0 || pos.Y < 0)
return false;
if (pos.X >= _width || pos.Y >= _height)
return false;
return true;
}
private Vec2<int>[] GetAntiNodes(Vec2<int> a, Vec2<int> b)
{
var dir = a - b;
var aNode1 = dir + a;
var aNode2 = -dir + b;
return [aNode1, aNode2];
}
private Vec2<int>[] GetHarmonicAntiNodes(Vec2<int> a, Vec2<int> b)
{
var dir = a - b;
List<Vec2<int>> GetNodes(Vec2<int> start, Vec2<int> dir)
{
var results = new List<Vec2<int>>();
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<Vec2<int>>();
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<char, List<Vec2<int>>>();
_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<int>(x, y);
if (!nodes.TryAdd(row[x], [p]))
nodes[row[x]].Add(p);
continue;
}
}
}
_nodes = nodes.ToFrozenDictionary();
}
}

View File

@@ -22,7 +22,16 @@ internal class DiskFragmenter : Problem<long, long>
public override void CalculatePart2()
{
var blocks = ExpandBlocks(_data);
var empty = blocks.Where(b => b.isEmpty).Sum(b => b.length);
var files = blocks.Where(b => !b.isEmpty).Sum(b => b.length);
CompactV2(blocks);
var empty2 = blocks.Where(b => b.isEmpty).Sum(b => b.length);
var files2 = blocks.Where(b => !b.isEmpty).Sum(b => b.length);
if (empty != empty2)
Console.WriteLine("Empty space does not match");
if (files != files2)
Console.WriteLine($"Files space does not match Befor: {files} -> {files2}");
//Print(blocks);
// Too High: 8838426222802
Part2 = ComputeHashV2(blocks);
@@ -174,10 +183,16 @@ internal class DiskFragmenter : Problem<long, long>
}
//Extend Right Block
else if (idx + 1 < blocks.Count && blocks[idx + 1].isEmpty)
{
blocks[idx + 1].length += block.length;
blocks.RemoveAt(idx);
}
//Extend Left Block
else if (idx - 1 > 0 && blocks[idx - 1].isEmpty)
{
blocks[idx - 1].length += block.length;
blocks.RemoveAt(idx);
}
//Insert new Empty Block
else
blocks[idx] = new Block(block.length);

View File

@@ -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<int, int>
{
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();
}
}

View File

@@ -1,7 +1,7 @@
global using AdventOfCode.Runner;
global using AdventOfCode.Runner.Attributes;
global using AdventOfCode.Utils;
var runner = new AOCRunner();
runner.RenderInteractiveMenu();
global using AdventOfCode.Runner;
global using AdventOfCode.Runner.Attributes;
global using AdventOfCode.Utils;
var runner = new AOCRunner();
runner.RenderInteractiveMenu();

View File

@@ -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<int, List<(ProblemInfoAttribute info, Type type)>> _loadedProblems;
private List<int> _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<int>();
_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<ProblemInfoAttribute>();
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<int, List<(ProblemInfoAttribute info, Type type)>> _loadedProblems;
private List<int> _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<int>();
_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<ProblemInfoAttribute>();
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(' ');
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<T> Print<T>(this IEnumerable<T> values)
{
foreach (var item in values)
{
Console.WriteLine(item);
}
return values;
}
public static T LCM<T>(this IEnumerable<T> values) where T : INumber<T>
{
var a = values.First();
values = values.Skip(1);
foreach (var item in values)
{
a = a.LCM(item);
}
return a;
}
public static IEnumerable<IEnumerable<T2>> Transpose<T, T2>(this IEnumerable<T> data) where T: IEnumerable<T2>
{
var range = Enumerable.Range(0, data.First().Count());
return range.Select(i => data.Select(l => l.Skip(i).First()));
}
public static IEnumerable<T> Transpose<T, T2>(this IEnumerable<T> data, Func<IEnumerable<T2>, T> formatter) where T : IEnumerable<T2>
{
var range = Enumerable.Range(0, data.First().Count());
return range.Select(i => formatter(data.Select(l => l.Skip(i).First())));
}
public static IEnumerable<string> Transpose(this IEnumerable<string> data)
{
return Transpose<string, char>(data, a => string.Join("", a));
}
public static IEnumerable<List<T>> Permute<T>(this IEnumerable<T> values)
{
IEnumerable<List<T>> permutate(IEnumerable<T> reminder, IEnumerable<T> prefix)
{
return !reminder.Any()
? new List<List<T>> { prefix.ToList() }
: reminder.SelectMany((c, i) => permutate(
reminder.Take(i).Concat(reminder.Skip(i + 1)).ToList(),
prefix.Append(c)));
}
return permutate(values, Enumerable.Empty<T>());
}
}
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<T> Print<T>(this IEnumerable<T> values)
{
foreach (var item in values)
{
Console.WriteLine(item);
}
return values;
}
public static T LCM<T>(this IEnumerable<T> values) where T : INumber<T>
{
var a = values.First();
values = values.Skip(1);
foreach (var item in values)
{
a = a.LCM(item);
}
return a;
}
public static IEnumerable<IEnumerable<T2>> Transpose<T, T2>(this IEnumerable<T> data) where T: IEnumerable<T2>
{
var range = Enumerable.Range(0, data.First().Count());
return range.Select(i => data.Select(l => l.Skip(i).First()));
}
public static IEnumerable<T> Transpose<T, T2>(this IEnumerable<T> data, Func<IEnumerable<T2>, T> formatter) where T : IEnumerable<T2>
{
var range = Enumerable.Range(0, data.First().Count());
return range.Select(i => formatter(data.Select(l => l.Skip(i).First())));
}
public static IEnumerable<string> Transpose(this IEnumerable<string> data)
{
return Transpose<string, char>(data, a => string.Join("", a));
}
public static IEnumerable<List<T>> Permute<T>(this IEnumerable<T> values)
{
IEnumerable<List<T>> permutate(IEnumerable<T> reminder, IEnumerable<T> prefix)
{
return !reminder.Any()
? new List<List<T>> { prefix.ToList() }
: reminder.SelectMany((c, i) => permutate(
reminder.Take(i).Concat(reminder.Skip(i + 1)).ToList(),
prefix.Append(c)));
}
return permutate(values, Enumerable.Empty<T>());
}
}

View File

@@ -1,26 +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<T>(this T a, T b) where T : INumber<T>
{
while (!b.Equals(T.Zero))
{
var t = b;
b = a % b;
a = t;
}
return a;
}
public static T LCM<T>(this T a, T b) where T: INumber<T>
{
return (a / GCF(a, b)) * 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<T>(this T a, T b) where T : INumber<T>
{
while (!b.Equals(T.Zero))
{
var t = b;
b = a % b;
a = t;
}
return a;
}
public static T LCM<T>(this T a, T b) where T : INumber<T>
{
return (a / GCF(a, b)) * b;
}
public static T Max<T>(this T a, T b) where T : INumber<T>
{
return T.Max(a, b);
}
public static T Min<T>(this T a, T b) where T : INumber<T>
{
return T.Min(a, b);
}
}

View File

@@ -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<string, string>
{
}
public abstract class Problem<TPart1, TPart2> : 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<ProblemInfoAttribute>();
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<string, string>
{
}
public abstract class Problem<TPart1, TPart2> : 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<ProblemInfoAttribute>();
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));
}
}

View File

@@ -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<T>(this IEnumerable<T> 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<T>(this IEnumerable<T> data, string delim = ", ")
{
return string.Join(delim, data);
}
public static T Mod<T>(this T value, T divisor) where T : INumber<T>
{
T remainder = value % divisor;
if (remainder < T.Zero)
return remainder + divisor;
else
return remainder;
}
}

View File

@@ -1,38 +1,48 @@
using System.Numerics;
namespace AdventOfCode.Utils.Models;
public record struct Vec2<T>(T X, T Y) where T : INumber<T>
{
public static Vec2<T> operator +(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X + right.X, left.Y + right.Y);
public static Vec2<T> operator -(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X - right.X, left.Y - right.Y);
public static Vec2<T> operator -(Vec2<T> vec) => new Vec2<T>(-vec.X, -vec.Y);
public static Vec2<T> operator *(Vec2<T> left, T right) => new Vec2<T>(left.X * right, left.Y * right);
public static Vec2<T> operator *(T left, Vec2<T> right) => new Vec2<T>(right.X * left, right.Y * left);
public static Vec2<T> operator /(Vec2<T> left, T right) => new Vec2<T>(left.X / right, left.Y / right);
public T DistanceSq(Vec2<T> other)
{
var a = other.X - this.X;
var b = other.Y - this.Y;
return (a * a) + (b * b);
}
}
public record struct Vec3<T>(T X, T Y, T Z) where T : INumber<T>
{
public static Vec3<T> operator +(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
public static Vec3<T> operator -(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
public static Vec3<T> operator -(Vec3<T> vec) => new Vec3<T>(-vec.X, -vec.Y, -vec.Z);
public static Vec3<T> operator *(Vec3<T> left, T right) => new Vec3<T>(left.X * right, left.Y * right, left.Z * right);
public static Vec3<T> operator *(T left, Vec3<T> right) => new Vec3<T>(right.X * left, right.Y * left, right.Z * left);
public static Vec3<T> operator /(Vec3<T> left, T right) => new Vec3<T>(left.X / right, left.Y / right, left.Z / right);
public T DistanceSq(Vec3<T> 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>(T X, T Y) where T : INumber<T>
{
public static Vec2<T> Zero => new (T.Zero, T.Zero);
public static Vec2<T> One => new (T.One, T.One);
public readonly Vec2<T> YX => new(Y, X);
public readonly Vec2<T> YY => new(Y, Y);
public readonly Vec2<T> XX => new(X, X);
public static Vec2<T> Splat(T v) => new(v, v);
public static Vec2<T> operator +(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X + right.X, left.Y + right.Y);
public static Vec2<T> operator -(Vec2<T> left, Vec2<T> right) => new Vec2<T>(left.X - right.X, left.Y - right.Y);
public static Vec2<T> operator -(Vec2<T> vec) => new Vec2<T>(-vec.X, -vec.Y);
public static Vec2<T> operator *(Vec2<T> left, T right) => new Vec2<T>(left.X * right, left.Y * right);
public static Vec2<T> operator *(T left, Vec2<T> right) => new Vec2<T>(right.X * left, right.Y * left);
public static Vec2<T> operator /(Vec2<T> left, T right) => new Vec2<T>(left.X / right, left.Y / right);
public T DistanceSq(Vec2<T> other)
{
var a = other.X - this.X;
var b = other.Y - this.Y;
return (a * a) + (b * b);
}
}
public record struct Vec3<T>(T X, T Y, T Z) where T : INumber<T>
{
public static Vec3<T> Zero => new(T.Zero, T.Zero, T.Zero);
public static Vec3<T> One => new(T.One, T.One, T.One);
public static Vec3<T> Splat(T v) => new(v, v, v);
public static Vec3<T> operator +(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X + right.X, left.Y + right.Y, left.Z + right.Z);
public static Vec3<T> operator -(Vec3<T> left, Vec3<T> right) => new Vec3<T>(left.X - right.X, left.Y - right.Y, left.Z - right.Z);
public static Vec3<T> operator -(Vec3<T> vec) => new Vec3<T>(-vec.X, -vec.Y, -vec.Z);
public static Vec3<T> operator *(Vec3<T> left, T right) => new Vec3<T>(left.X * right, left.Y * right, left.Z * right);
public static Vec3<T> operator *(T left, Vec3<T> right) => new Vec3<T>(right.X * left, right.Y * left, right.Z * left);
public static Vec3<T> operator /(Vec3<T> left, T right) => new Vec3<T>(left.X / right, left.Y / right, left.Z / right);
public T DistanceSq(Vec3<T> 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);
}
}

View File

@@ -0,0 +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;
}
}