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