Compare commits
19 Commits
a92c9b4478
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f45853889 | |||
| 55a8ea0281 | |||
| e56befa18b | |||
| 9f1a2d2300 | |||
| a0c97e4b75 | |||
| 629b13abef | |||
| 4f4ccf7117 | |||
| 625a9e5ad5 | |||
| ef959284a5 | |||
| bba775fd4e | |||
| f16899ff3c | |||
| 6606f40df9 | |||
| 199b940ff9 | |||
| 63eb4d01b0 | |||
| a33843ae1b | |||
| e08a60614a | |||
| 6a9c813d08 | |||
| ba7e6d4be0 | |||
| a4cb169566 |
126
.gitattributes
vendored
126
.gitattributes
vendored
@@ -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
726
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>net10.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>
|
||||
|
||||
2
AdventOfCode/Problems/.gitignore
vendored
2
AdventOfCode/Problems/.gitignore
vendored
@@ -1,2 +1,2 @@
|
||||
*/*/*.txt
|
||||
*/*/*.txt
|
||||
*/*/*.csv
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)}]";
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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}";
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
301
AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs
Normal file
301
AdventOfCode/Problems/AOC2024/Day12/GardenGroups.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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}";
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
69
AdventOfCode/Problems/AOC2025/Day1/SecretEntrance.cs
Normal file
69
AdventOfCode/Problems/AOC2025/Day1/SecretEntrance.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
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 const int LOCK_SIZE = 100;
|
||||
|
||||
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(LOCK_SIZE);
|
||||
if (v == 0)
|
||||
c++;
|
||||
}
|
||||
Part1 = c;
|
||||
}
|
||||
|
||||
public override void CalculatePart2()
|
||||
{
|
||||
var c = 0;
|
||||
var v = 50;
|
||||
foreach (var item in Input)
|
||||
{
|
||||
var vStart = v;
|
||||
|
||||
v += item;
|
||||
if (item > 0)
|
||||
c += (int)Math.Floor(v / (float)LOCK_SIZE);
|
||||
else
|
||||
{
|
||||
var d = v / (float)LOCK_SIZE;
|
||||
var fl = Math.Floor(d);
|
||||
c += (int)Math.Abs(fl) - (vStart == 0 ? 1 : 0);
|
||||
if (fl == d)
|
||||
c += 1;
|
||||
}
|
||||
v = v.Mod(LOCK_SIZE);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
8
AdventOfCode/Problems/AOC2025/Day1/test.out
Normal file
8
AdventOfCode/Problems/AOC2025/Day1/test.out
Normal file
@@ -0,0 +1,8 @@
|
||||
[-100]: 1 | start: 50 v: 50
|
||||
[100]: 1 | start: 50 v: 50
|
||||
[-150]: 2 | start: 50 v: 0
|
||||
[150]: 1 | start: 0 v: 50
|
||||
[-500]: 5 | start: 50 v: 50
|
||||
[500]: 5 | start: 50 v: 50
|
||||
[-550]: 6 | start: 50 v: 0
|
||||
[550]: 5 | start: 0 v: 5
|
||||
100
AdventOfCode/Problems/AOC2025/Day2/GiftShop.cs
Normal file
100
AdventOfCode/Problems/AOC2025/Day2/GiftShop.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
using ZLinq;
|
||||
|
||||
namespace AdventOfCode.Problems.AOC2025.Day2;
|
||||
|
||||
[ProblemInfo(2025, 2, "Gift Shop")]
|
||||
internal class GiftShop : Problem<long, long>
|
||||
{
|
||||
private IdRange[] _ranges = [];
|
||||
public override void CalculatePart1()
|
||||
{
|
||||
var v = _ranges.SelectMany(GetDoubleSequences);
|
||||
//Console.WriteLine(v.AsJoinedString());
|
||||
Part1 = v.Sum();
|
||||
}
|
||||
|
||||
public static long[] GetDoubleSequences(IdRange range)
|
||||
{
|
||||
range = range.Snap();
|
||||
var minDigits = range.Min.DigitCount() / 2;
|
||||
var maxDigits = range.Max.DigitCount() / 2;
|
||||
|
||||
var min = GetMinValue((int)minDigits, range.Min);
|
||||
var max = GetMaxValue((int)maxDigits, range.Max);
|
||||
//Console.WriteLine($"{min}-{max}");
|
||||
if (max < min)
|
||||
return [];
|
||||
var n = (max - min) + 1;
|
||||
var result = new long[n];
|
||||
for (long i = min; i <= max; i++)
|
||||
{
|
||||
result[i - min] = (i * QuickMath.FastPow10(minDigits)) + i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static long SnapToUpNearestValidRange(long value)
|
||||
{
|
||||
var dc = value.DigitCount();
|
||||
if (dc.IsEven())
|
||||
return value;
|
||||
return QuickMath.FastPow10(dc);
|
||||
}
|
||||
public static long SnapToDownNearestValidRange(long value)
|
||||
{
|
||||
var dc = value.DigitCount();
|
||||
if (dc.IsEven())
|
||||
return value;
|
||||
return QuickMath.FastPow10(dc - 1) - 1;
|
||||
}
|
||||
|
||||
public static long GetMinValue(int digits, long value)
|
||||
{
|
||||
var val = long.Parse(value.ToString()[..^digits]);
|
||||
while ((val * QuickMath.FastPow10(digits)) + val < value)
|
||||
{
|
||||
val++;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static long GetMaxValue(int digits, long value)
|
||||
{
|
||||
var val = long.Parse(value.ToString()[..^digits]);
|
||||
while ((val * QuickMath.FastPow10(digits)) + val > value)
|
||||
{
|
||||
val--;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public override void CalculatePart2()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void LoadInput()
|
||||
{
|
||||
var text = ReadInputText("input.txt");
|
||||
_ranges = text.Split(',')
|
||||
.AsValueEnumerable()
|
||||
.Select(r => r.Split('-').Select(long.Parse))
|
||||
.Select(r => new IdRange(r.First(), r.Last()))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public record IdRange(long Min, long Max)
|
||||
{
|
||||
public IdRange Snap()
|
||||
{
|
||||
return new IdRange(SnapToUpNearestValidRange(Min), SnapToDownNearestValidRange(Max));
|
||||
}
|
||||
}
|
||||
}
|
||||
65
AdventOfCode/Problems/AOC2025/Day3/Lobby.cs
Normal file
65
AdventOfCode/Problems/AOC2025/Day3/Lobby.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using ZLinq;
|
||||
|
||||
namespace AdventOfCode.Problems.AOC2025.Day3;
|
||||
|
||||
[ProblemInfo(2025, 3, "Lobby")]
|
||||
internal class Lobby : Problem<long, long>
|
||||
{
|
||||
private (int val, int idx)[][] _batteryBanks = [];
|
||||
|
||||
public override void CalculatePart1()
|
||||
{
|
||||
Part1 = _batteryBanks.AsValueEnumerable().Select(bank =>
|
||||
{
|
||||
var batteries = GetViableBatteries(bank);
|
||||
return GetPower(batteries);
|
||||
}).Sum();
|
||||
}
|
||||
|
||||
|
||||
public override void CalculatePart2()
|
||||
{
|
||||
Console.WriteLine();
|
||||
var b = _batteryBanks.AsValueEnumerable().Select(bank =>
|
||||
{
|
||||
var batteries = GetViableBatteries(bank, 12);
|
||||
return GetPower(batteries);
|
||||
});
|
||||
Part2 = b.Sum();
|
||||
}
|
||||
|
||||
public static long GetPower(int[] values)
|
||||
{
|
||||
return values.Select((v, idx) =>
|
||||
{
|
||||
var mag = (long)Math.Pow(10, values.Length - idx - 1);
|
||||
return v * mag;
|
||||
}).Sum();
|
||||
}
|
||||
|
||||
public static int[] GetViableBatteries((int val, int idx)[] source, int count = 2)
|
||||
{
|
||||
var batteries = new int[count];
|
||||
var offset = 0;
|
||||
for (int i = count; i > 0; i--)
|
||||
{
|
||||
var tgt = i - 1;
|
||||
var (val, idx) = source[offset..^tgt].MaxBy(v => v.val);
|
||||
offset = idx + 1;
|
||||
batteries[count - i] = val;
|
||||
}
|
||||
return batteries;
|
||||
}
|
||||
|
||||
public override void LoadInput()
|
||||
{
|
||||
_batteryBanks = ReadInputLines("input.txt")
|
||||
.AsValueEnumerable()
|
||||
.Select(l => l.AsValueEnumerable().Select((v, idx) => (v - '0', idx)).ToArray())
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
62
AdventOfCode/Problems/AOC2025/Day4/PrintingDeparment.cs
Normal file
62
AdventOfCode/Problems/AOC2025/Day4/PrintingDeparment.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using AdventOfCode.Utils.Models;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace AdventOfCode.Problems.AOC2025.Day4;
|
||||
[ProblemInfo(2025, 4, "Printing Department")]
|
||||
internal class PrintingDeparment: Problem<int, int>
|
||||
{
|
||||
private string[] _data = [];
|
||||
private Vec2<int> _size;
|
||||
|
||||
public override void CalculatePart1()
|
||||
{
|
||||
var c = 0;
|
||||
for (int y = 0; y < _size.Y; y++)
|
||||
{
|
||||
for (int x = 0; x < _size.X; x++)
|
||||
{
|
||||
var pos = new Vec2<int>(x, y);
|
||||
if (_data[pos.Y][pos.X] != '@')
|
||||
continue;
|
||||
var n = CountNeighbors(pos);
|
||||
if (n < 4)
|
||||
c++;
|
||||
}
|
||||
}
|
||||
Part1 = c;
|
||||
}
|
||||
|
||||
public int CountNeighbors(Vec2<int> pos)
|
||||
{
|
||||
var c = 0;
|
||||
for (int y = pos.Y-1; y <= pos.Y + 1; y++)
|
||||
{
|
||||
if (y < 0 || y >= _size.Y)
|
||||
continue;
|
||||
for (int x = pos.X - 1; x <= pos.X + 1; x++)
|
||||
{
|
||||
if (x < 0 || x >= _size.X)
|
||||
continue;
|
||||
if (pos.X == x && pos.Y == y)
|
||||
continue;
|
||||
if (_data[y][x] == '@')
|
||||
c++;
|
||||
}
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public override void CalculatePart2()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void LoadInput()
|
||||
{
|
||||
_data = ReadInputLines("input.txt");
|
||||
_size = new Vec2<int>(_data[0].Length, _data.Length);
|
||||
}
|
||||
}
|
||||
85
AdventOfCode/Problems/AOC2025/Day5/Cafeteria.cs
Normal file
85
AdventOfCode/Problems/AOC2025/Day5/Cafeteria.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
using ZLinq;
|
||||
|
||||
namespace AdventOfCode.Problems.AOC2025.Day5;
|
||||
[ProblemInfo(2025, 5, "Cafeteria")]
|
||||
internal class Cafeteria : Problem<long, long>
|
||||
{
|
||||
private (long start, long end)[] _ranges = [];
|
||||
private long[] _values = [];
|
||||
|
||||
public override void CalculatePart1()
|
||||
{
|
||||
Part1 = _values.AsValueEnumerable().Count(v => _ranges.AsValueEnumerable().Any(r => IsInRange(r, v)));
|
||||
}
|
||||
|
||||
public static bool IsInRange((long start, long end) range, long value)
|
||||
{
|
||||
return (range.start <= value && range.end >= value);
|
||||
}
|
||||
|
||||
public override void CalculatePart2()
|
||||
{
|
||||
var merged = MergeRanges(_ranges);
|
||||
merged.Print();
|
||||
Console.WriteLine("----");
|
||||
MergeRanges(merged.ToArray()).Print();
|
||||
//merged.Print();
|
||||
Part2 = merged.Select(r => r.end - r.start + 1).Sum();
|
||||
}
|
||||
|
||||
public static List<(long start, long end)> MergeRanges((long start, long end)[] ranges)
|
||||
{
|
||||
var result = new List<(long start, long end)>(ranges.Length);
|
||||
var used = new HashSet<int>();
|
||||
for (int i = 0; i < ranges.Length; i++)
|
||||
{
|
||||
if (used.Contains(i))
|
||||
continue;
|
||||
var range = ranges[i];
|
||||
|
||||
for (int j = (i + 1); j < ranges.Length; j++)
|
||||
{
|
||||
if (used.Contains(j))
|
||||
continue;
|
||||
var range2 = ranges[j];
|
||||
if(IsOverlapping(range, range2))
|
||||
{
|
||||
range = Merge(range, range2);
|
||||
used.Add(j);
|
||||
j = i;
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(range);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool IsOverlapping((long start, long end) a, (long start, long end) b)
|
||||
{
|
||||
return IsInRange(a, b.start) || IsInRange(a, b.end) || IsInRange(b, a.start) || IsInRange(b, a.end);
|
||||
}
|
||||
|
||||
public static (long start, long end) Merge((long start, long end) a, (long start, long end) b)
|
||||
{
|
||||
return (a.start.Min(b.start), a.end.Max(b.end));
|
||||
}
|
||||
|
||||
|
||||
public override void LoadInput()
|
||||
{
|
||||
var lines = ReadInputLines("input.txt");
|
||||
_ranges = lines
|
||||
.TakeWhile(l => !string.IsNullOrWhiteSpace(l))
|
||||
.Select(l => l.Split('-').Select(long.Parse))
|
||||
.Select(v => (start: v.First(), end: v.Last()))
|
||||
.ToArray();
|
||||
_values = lines[(_ranges.Length + 1)..]
|
||||
.Select(long.Parse)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
88
AdventOfCode/Problems/AOC2025/Day6/TrashCompactor.cs
Normal file
88
AdventOfCode/Problems/AOC2025/Day6/TrashCompactor.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AdventOfCode.Problems.AOC2025.Day6;
|
||||
[ProblemInfo(2025, 6, "Trash Compactor")]
|
||||
public partial class TrashCompactor : Problem<long, long>
|
||||
{
|
||||
private long[][] _values = [];
|
||||
private string[] _operators = [];
|
||||
private IEnumerable<(char op, long[] values)> _part2Data = [];
|
||||
|
||||
public override void CalculatePart1()
|
||||
{
|
||||
for (int i = 0; i < _operators.Length; i++)
|
||||
{
|
||||
var op = _operators[i];
|
||||
var col = _values.Select(r => r[i]).ToArray();
|
||||
Part1 += op switch
|
||||
{
|
||||
"+" => col.Aggregate((a, b) => a + b),
|
||||
"*" => col.Aggregate((a, b) => a * b),
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void CalculatePart2()
|
||||
{
|
||||
foreach (var (op, values) in _part2Data)
|
||||
{
|
||||
Part2 += op switch
|
||||
{
|
||||
'+' => values.Aggregate((a, b) => a + b),
|
||||
'*' => values.Aggregate((a, b) => a * b),
|
||||
_ => throw new InvalidOperationException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void LoadInput()
|
||||
{
|
||||
var lines = ReadInputLines("input.txt");
|
||||
ParsePart1(lines);
|
||||
ParsePart2(lines);
|
||||
}
|
||||
|
||||
private void ParsePart1(string[] lines)
|
||||
{
|
||||
_values = lines[..^1].Select(l => LineMatch().Matches(l).Select(v => long.Parse(v.Value)).ToArray()).ToArray();
|
||||
_operators = LineMatch().Matches(lines[^1]).Select(v => v.Value).ToArray();
|
||||
}
|
||||
|
||||
private void ParsePart2(string[] lines)
|
||||
{
|
||||
var valueLines = lines[..^1];
|
||||
var opLines = lines[^1];
|
||||
|
||||
var opPos = 0;
|
||||
var len = 1;
|
||||
|
||||
var data = new List<(char op, string[] values)>();
|
||||
|
||||
for (int i = 1; i < opLines.Length; i++)
|
||||
{
|
||||
var curChar = opLines[i];
|
||||
if (curChar != ' ' || i == opLines.Length - 1)
|
||||
{
|
||||
if (i == opLines.Length - 1)
|
||||
len = opLines.Length - opPos + 1;
|
||||
var op = opLines[opPos];
|
||||
var values = valueLines.Select(v => v[opPos..(opPos + len - 1)]).ToArray();
|
||||
data.Add((op, values));
|
||||
|
||||
len = 1;
|
||||
opPos = i;
|
||||
}
|
||||
else
|
||||
len++;
|
||||
}
|
||||
|
||||
_part2Data = data.Select(v => (v.op, v.values.Transpose().Select(long.Parse).ToArray()));
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"(\S+)")]
|
||||
private static partial Regex LineMatch();
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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(' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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>());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,57 @@
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public static bool IsEven<T>(this T value) where T : INumber<T>
|
||||
{
|
||||
return T.IsEvenInteger(value);
|
||||
}
|
||||
|
||||
public static bool IsOdd<T>(this T value) where T : INumber<T>
|
||||
{
|
||||
return T.IsOddInteger(value);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,38 +1,58 @@
|
||||
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 override string ToString()
|
||||
{
|
||||
return $"({X}, {Y})";
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"({X}, {Y}, {Z})";
|
||||
}
|
||||
}
|
||||
37
AdventOfCode/Utils/QuickMath.cs
Normal file
37
AdventOfCode/Utils/QuickMath.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user