diff --git a/.vsconfig b/.vsconfig index a991ed17..8114a325 100644 --- a/.vsconfig +++ b/.vsconfig @@ -3,7 +3,7 @@ "components": [ "Microsoft.VisualStudio.Component.CoreEditor", "Microsoft.VisualStudio.Workload.CoreEditor", - "Microsoft.NetCore.Component.Runtime.8.0", + "Microsoft.NetCore.Component.Runtime.9.0", "Microsoft.NetCore.Component.SDK", "Microsoft.VisualStudio.Component.Roslyn.Compiler", "Microsoft.VisualStudio.Component.Roslyn.LanguageServices" diff --git a/Directory.Build.props b/Directory.Build.props index a3f8502d..128a48a3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -36,7 +36,7 @@ snupkg true true - 8.0.0 + 9.0.0 diff --git a/benchmark.ps1 b/benchmark.ps1 index 81d8d914..b3c251a6 100755 --- a/benchmark.ps1 +++ b/benchmark.ps1 @@ -11,10 +11,6 @@ param( $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" -if ($null -eq ${env:MSBUILDTERMINALLOGGER}) { - ${env:MSBUILDTERMINALLOGGER} = "auto" -} - $solutionPath = $PSScriptRoot $sdkFile = Join-Path $solutionPath "global.json" diff --git a/build.ps1 b/build.ps1 index 98c90ce4..03e20d88 100755 --- a/build.ps1 +++ b/build.ps1 @@ -7,10 +7,6 @@ param( [Parameter(Mandatory = $false)][switch] $SkipTests ) -if ($null -eq ${env:MSBUILDTERMINALLOGGER}) { - ${env:MSBUILDTERMINALLOGGER} = "auto" -} - $Configuration = "Release" $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" diff --git a/crank.ps1 b/crank.ps1 index a917bc4f..12114e4a 100644 --- a/crank.ps1 +++ b/crank.ps1 @@ -12,10 +12,6 @@ param( $ErrorActionPreference = "Stop" $global:ProgressPreference = "SilentlyContinue" -if ($null -eq ${env:MSBUILDTERMINALLOGGER}) { - ${env:MSBUILDTERMINALLOGGER} = "auto" -} - $additionalArgs = @() if (![string]::IsNullOrEmpty($BranchOrCommitOrTag)) { diff --git a/crank.yml b/crank.yml index 5c2dca94..1a56bf02 100644 --- a/crank.yml +++ b/crank.yml @@ -15,7 +15,7 @@ jobs: scenarios: microbenchmarks: application: - framework: net8.0 + framework: net9.0 job: microbenchmarks profiles: diff --git a/global.json b/global.json index b962d273..217f7c9f 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.404", + "version": "9.0.100", "allowPrerelease": false, "rollForward": "latestMajor" } diff --git a/src/ProjectEuler/ProjectEuler.csproj b/src/ProjectEuler/ProjectEuler.csproj index ce1a1303..17d11833 100644 --- a/src/ProjectEuler/ProjectEuler.csproj +++ b/src/ProjectEuler/ProjectEuler.csproj @@ -7,7 +7,7 @@ true true MartinCostello.ProjectEuler - net8.0 + net9.0 diff --git a/src/ProjectEuler/Puzzles/Puzzle014.cs b/src/ProjectEuler/Puzzles/Puzzle014.cs index ce09a472..94a4ae39 100644 --- a/src/ProjectEuler/Puzzles/Puzzle014.cs +++ b/src/ProjectEuler/Puzzles/Puzzle014.cs @@ -13,11 +13,7 @@ public sealed class Puzzle014 : Puzzle /// private static readonly Dictionary _cache = new(1_000_000); -#if NET9_0_OR_GREATER private static readonly System.Threading.Lock _lock = new(); -#else - private static readonly object _lock = new(); -#endif /// public override string Question => "Which starting number, under one million, produces the longest chain?"; diff --git a/src/ProjectEuler/Puzzles/Puzzle025.cs b/src/ProjectEuler/Puzzles/Puzzle025.cs index 02a0bd16..052bc57d 100644 --- a/src/ProjectEuler/Puzzles/Puzzle025.cs +++ b/src/ProjectEuler/Puzzles/Puzzle025.cs @@ -45,15 +45,11 @@ internal static IEnumerable Fibonacci() /// protected override int SolveCore(string[] args) { - int index = 0; - - foreach (BigInteger value in Fibonacci()) + foreach ((int index, BigInteger value) in Fibonacci().Index()) { - index++; - if (value >= Limit) { - Answer = index; + Answer = index + 1; break; } } diff --git a/src/ProjectEuler/Puzzles/Puzzle042.cs b/src/ProjectEuler/Puzzles/Puzzle042.cs index ddf984fc..58fe7474 100644 --- a/src/ProjectEuler/Puzzles/Puzzle042.cs +++ b/src/ProjectEuler/Puzzles/Puzzle042.cs @@ -51,17 +51,16 @@ internal IList ReadWords() using var stream = ReadResource(); using var reader = new StreamReader(stream); - string rawWords = reader.ReadToEnd(); + var text = reader.ReadToEnd().AsSpan(); + var words = new List(); - string[] split = rawWords.Split(','); - - var words = new List(split.Length); - - foreach (string word in split) + foreach (var word in text.Split(',')) { - words.Add(word.Trim('\"')); + words.Add(text[word].Trim('\"').ToString()); } + words.TrimExcess(); + return words; } diff --git a/src/ProjectEuler/Puzzles/Puzzle059.cs b/src/ProjectEuler/Puzzles/Puzzle059.cs index 24266e3c..745fef1c 100644 --- a/src/ProjectEuler/Puzzles/Puzzle059.cs +++ b/src/ProjectEuler/Puzzles/Puzzle059.cs @@ -1,9 +1,6 @@ // Copyright (c) Martin Costello, 2015. All rights reserved. // Licensed under the Apache 2.0 license. See the LICENSE file in the project root for full license information. -using System.Buffers; -using System.Text; - namespace MartinCostello.ProjectEuler.Puzzles; /// @@ -17,65 +14,57 @@ public sealed class Puzzle059 : Puzzle /// protected override int SolveCore(string[] args) { - byte[] encrypted = LoadText(); - - byte[] alphabet = Enumerable.Range('a', 26) - .Select((p) => (byte)p) - .ToArray(); - - var passwords = new List((int)Math.Pow(alphabet.Length, 3)); + const int AlphabetLength = 26; + const int KeyLength = 3; - for (int x = 0; x < alphabet.Length; x++) + ReadOnlySpan passwords = string.Create( + AlphabetLength * AlphabetLength * AlphabetLength * KeyLength, + "abcdefghijklmnopqrstuvwxyz", + static (buffer, alphabet) => { - for (int y = 0; y < alphabet.Length; y++) + int i = 0; + + for (int x = 0; x < alphabet.Length; x++) { - for (int z = 0; z < alphabet.Length; z++) + for (int y = 0; y < alphabet.Length; y++) { - passwords.Add([alphabet[x], alphabet[y], alphabet[z]]); + for (int z = 0; z < alphabet.Length; z++) + { + buffer[i] = alphabet[x]; + buffer[i + 1] = alphabet[y]; + buffer[i + 2] = alphabet[z]; + i += KeyLength; + } } } - } + }); - var encoding = Encoding.ASCII; + var encrypted = LoadText(); + Span decrypted = stackalloc char[encrypted.Length]; - // Five most common English words - string[] commonWords = - [ - " the ", - " of ", - " and ", - " a ", - " to ", - ]; - - byte[][] words = commonWords.Select(encoding.GetBytes).ToArray(); - - byte[] key = new byte[encrypted.Length]; - byte[] decrypted = new byte[encrypted.Length]; - - foreach (byte[] password in passwords) + for (int i = 0; i < passwords.Length; i += KeyLength) { - for (int i = 0; i < key.Length;) - { - key[i++] = password[0]; - key[i++] = password[1]; - key[i++] = password[2]; - } + var password = passwords.Slice(i, KeyLength); - for (int i = 0; i < decrypted.Length; i++) + for (int j = 0; j < decrypted.Length; j += KeyLength) { - decrypted[i] = (byte)(encrypted[i] ^ key[i]); + decrypted[j] = (char)(encrypted[j] ^ password[0]); + decrypted[j + 1] = (char)(encrypted[j + 1] ^ password[1]); + decrypted[j + 2] = (char)(encrypted[j + 2] ^ password[2]); } - ReadOnlySpan plaintext = decrypted; + ReadOnlySpan span = decrypted; - if (plaintext.IndexOf(words[0]) > -1 && - plaintext.IndexOf(words[1]) > -1 && - plaintext.IndexOf(words[2]) > -1 && - plaintext.IndexOf(words[3]) > -1 && - plaintext.IndexOf(words[4]) > -1) + if (span.Contains("Euler", StringComparison.Ordinal)) { - Answer = decrypted.Select((p) => (int)p).Sum(); + int sum = 0; + + for (int j = 0; j < span.Length; j++) + { + sum += span[j]; + } + + Answer = sum; break; } } @@ -83,17 +72,20 @@ protected override int SolveCore(string[] args) return 0; } - private byte[] LoadText() + private ReadOnlySpan LoadText() { using var stream = ReadResource(); using var reader = new StreamReader(stream); - string text = reader.ReadToEnd(); + int length = 0; + ReadOnlySpan text = reader.ReadToEnd(); - string[] split = text.Split(','); - - return split - .Select((p) => byte.Parse(p, CultureInfo.InvariantCulture)) - .ToArray(); + return string.Create(text.Length, text, (buffer, value) => + { + foreach (var range in value.Split(',')) + { + buffer[length++] = (char)byte.Parse(value[range], CultureInfo.InvariantCulture); + } + }).AsSpan()[..length]; } } diff --git a/startvs.cmd b/startvs.cmd new file mode 100644 index 00000000..6a073110 --- /dev/null +++ b/startvs.cmd @@ -0,0 +1,24 @@ +@ECHO OFF +SETLOCAL + +:: This command launches a Visual Studio solution with environment variables required to use a local version of the .NET SDK. + +:: This tells .NET to use the same dotnet.exe that the build script uses. +SET DOTNET_ROOT=%~dp0.dotnetcli +SET DOTNET_ROOT(x86)=%~dp0.dotnetcli\x86 + +:: Put our local dotnet.exe on PATH first so Visual Studio knows which one to use. +SET PATH=%DOTNET_ROOT%;%PATH% + +SET sln=%~dp0ProjectEuler.sln + +IF NOT EXIST "%DOTNET_ROOT%\dotnet.exe" ( + echo The .NET SDK has not yet been installed. Run `%~dp0build.ps1` to install it + exit /b 1 +) + +IF "%VSINSTALLDIR%" == "" ( + start "" "%sln%" +) else ( + "%VSINSTALLDIR%\Common7\IDE\devenv.com" "%sln%" +) diff --git a/startvscode.cmd b/startvscode.cmd new file mode 100644 index 00000000..45ea8f6d --- /dev/null +++ b/startvscode.cmd @@ -0,0 +1,29 @@ +@ECHO OFF +SETLOCAL + +:: This command launches Visual Studio Code with environment variables required to use a local version of the .NET SDK. + +:: This tells .NET to use the same dotnet.exe that the build script uses. +SET DOTNET_ROOT=%~dp0.dotnetcli +SET DOTNET_ROOT(x86)=%~dp0.dotnetcli\x86 + +:: Put our local dotnet.exe on PATH first so Visual Studio Code knows which one to use. +SET PATH=%DOTNET_ROOT%;%PATH% + +:: Sets the Target Framework for Visual Studio Code. +SET TARGET=net9.0 + +SET FOLDER=%~1 + +IF NOT EXIST "%DOTNET_ROOT%\dotnet.exe" ( + echo The .NET SDK has not yet been installed. Run `%~dp0build.ps1` to install it + exit /b 1 +) + +IF "%FOLDER%"=="" ( + code . +) else ( + code "%FOLDER%" +) + +exit /b 1 diff --git a/tests/ProjectEuler.Benchmarks/ProjectEuler.Benchmarks.csproj b/tests/ProjectEuler.Benchmarks/ProjectEuler.Benchmarks.csproj index 613e8b52..f47a2855 100644 --- a/tests/ProjectEuler.Benchmarks/ProjectEuler.Benchmarks.csproj +++ b/tests/ProjectEuler.Benchmarks/ProjectEuler.Benchmarks.csproj @@ -5,7 +5,7 @@ Exe MartinCostello.ProjectEuler.Benchmarks Benchmarks for ProjectEuler. - net8.0 + net9.0 diff --git a/tests/ProjectEuler.Tests/ProjectEuler.Tests.csproj b/tests/ProjectEuler.Tests/ProjectEuler.Tests.csproj index 94fa435d..151c0578 100644 --- a/tests/ProjectEuler.Tests/ProjectEuler.Tests.csproj +++ b/tests/ProjectEuler.Tests/ProjectEuler.Tests.csproj @@ -5,7 +5,7 @@ $(NoWarn);CA1707;CA1812;CA1861;CA2007;SA1600 MartinCostello.ProjectEuler Tests for ProjectEuler. - net8.0 + net9.0