diff --git a/README.rst b/README.rst index 620cb255..cee055a6 100644 --- a/README.rst +++ b/README.rst @@ -48,7 +48,7 @@ LivInTheLookingGlass’s Project Euler solutions | | ``gcc``, ``clang`` |br| | | |Cp-Cov| |br| | | | C++14+ in ``msvc`` | | |CodeQL| | +------------+-------------------------+--------+-------------------+ -| C# | .NET 2+ | 10 | |C#i| |br| | +| C# | .NET 2+ | 12 | |C#i| |br| | | | | | |Cs-Cov| |br| | | | | | |CodeQL| | +------------+-------------------------+--------+-------------------+ diff --git a/csharp/Euler.Test/test.cs b/csharp/Euler.Test/test.cs index d40d4c46..c13eb16c 100644 --- a/csharp/Euler.Test/test.cs +++ b/csharp/Euler.Test/test.cs @@ -15,6 +15,8 @@ public static IEnumerable Data() yield return new object[] { typeof(p0008), false, 23514624000 }; yield return new object[] { typeof(p0009), false, 31875000 }; yield return new object[] { typeof(p0011), false, 70600674 }; + yield return new object[] { typeof(p0014), false, 837799 }; + yield return new object[] { typeof(p0015), false, 137846528820 }; yield return new object[] { typeof(p0017), false, 21124 }; yield return new object[] { typeof(p0076), true, 190569291 }; yield return new object[] { typeof(p0836), false, "aprilfoolsjoke" }; @@ -24,9 +26,9 @@ public static IEnumerable Data() [MemberData(nameof(Data))] public async Task EulerTest_Problem(Type problem, bool isSlow, object expected) { - IEuler? prob; - prob = (IEuler?)Activator.CreateInstance(problem); - Assert.NotNull(prob); + IEuler? prob = (IEuler?)Activator.CreateInstance(problem); + if (prob is null) + throw new Exception("Unable to construct test object"); Stopwatch sw = Stopwatch.StartNew(); object result = await prob.Answer(); sw.Stop(); diff --git a/csharp/Euler/include/math.cs b/csharp/Euler/include/math.cs new file mode 100644 index 00000000..d32841aa --- /dev/null +++ b/csharp/Euler/include/math.cs @@ -0,0 +1,86 @@ +using System; + +namespace Euler +{ + public static class Mathematics + { + public static ulong Factorial(ulong n) + { + ulong answer = 1; + for (ulong x = 2; x < n; x += 1) + answer *= x; + return answer; + } + + public static ulong NChooseR(ulong n, ulong r) + { + if (n < 20) + return Factorial(n) / Factorial(r) / Factorial(n - r); + ulong answer, tmp; + uint i, j; + sbyte[] factors = new sbyte[n + 1]; + // collect factors of final number + for (i = 2; i <= n; i += 1) + factors[i] = 1; + // negative factor values indicate need to divide + for (i = 2; i <= r; i += 1) + { + factors[i] -= 1; + } + for (i = 2; i <= n - r; i += 1) + { + factors[i] -= 1; + } + // this loop reduces to prime factors only + for (i = (uint)n; i > 1; i -= 1) + { + for (j = 2; j < i; j += 1) + { + if (i % j == 0) + { + factors[j] += factors[i]; + factors[i / j] += factors[i]; + factors[i] = 0; + break; + } + } + } + i = j = 2; + answer = 1; + while (i <= n) + { + while (factors[i] > 0) + { + tmp = answer; + answer *= i; + while (answer < tmp && j <= n) + { + while (factors[j] < 0) + { + tmp /= j; + factors[j] += 1; + } + j += 1; + answer = tmp * i; + } + if (answer < tmp) + { + return ulong.MaxValue; // this indicates an overflow + } + factors[i] -= 1; + } + i += 1; + } + while (j <= n) + { + while (factors[j] < 0) + { + answer /= j; + factors[j] += 1; + } + j += 1; + } + return answer; + } + } +} diff --git a/csharp/Euler/p0014.cs b/csharp/Euler/p0014.cs new file mode 100644 index 00000000..49c7487a --- /dev/null +++ b/csharp/Euler/p0014.cs @@ -0,0 +1,69 @@ +/* +Project Euler Problem 14 + +This was easier to do in C# than I would have thought + +Problem: + +The following iterative sequence is defined for the set of positive integers: + +n → n/2 (n is even) +n → 3n + 1 (n is odd) + +Using the rule above and starting with 13, we generate the following sequence: +13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1 + +It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been +proved yet (Collatz Problem), it is thought that all starting numbers finish at 1. + +Which starting number, under one million, produces the longest chain? + +NOTE: Once the chain starts the terms are allowed to go above one million. +*/ +using System; + +namespace Euler +{ + public class p0014 : IEuler + { + public Task Answer() + { + int biggestSeen = 0; + long biggestIdx = 0; + Dictionary cache = new(); + for (long x = 1; x < 1000000; x += 1) + { + int result = CollatzLen(x, cache); + if (result > biggestSeen) + { + biggestSeen = result; + biggestIdx = x; + } + } + return Task.FromResult((int)biggestIdx); + } + + static int CollatzLen(long n, IDictionary cache) + { + if (n == 1) + { + return 0; + } + else if (cache.ContainsKey(n)) + { + return cache[n]; + } + int result; + if (n % 2 == 0) + { + result = 1 + CollatzLen(n / 2, cache); + } + else + { + result = 2 + CollatzLen((3 * n + 1) / 2, cache); + } + cache.Add(n, result); + return result; + } + } +} diff --git a/csharp/Euler/p0015.cs b/csharp/Euler/p0015.cs new file mode 100644 index 00000000..16383bb0 --- /dev/null +++ b/csharp/Euler/p0015.cs @@ -0,0 +1,28 @@ +/* +Project Euler Problem 15 + +Turns out this is easy, if you think sideways a bit + +You can only go down or right. If we say right=1, then you can only have 20 1s, since otherwise you go off the grid. +You also can't have fewer than 20 1s, since then you go off the grid the other way. This means you can look at it as a +bit string, and the number of 40-bit strings with 20 1s is 40c20. + +Problem: + +Starting in the top left corner of a 2×2 grid, and only being able to move to the right and down, there are exactly 6 +routes to the bottom right corner. + +How many such routes are there through a 20×20 grid? +*/ +using System; + +namespace Euler +{ + public class p0015 : IEuler + { + public Task Answer() + { + return Task.FromResult((long)Mathematics.NChooseR(40, 20)); + } + } +} diff --git a/docs/csharp/p0014.rst b/docs/csharp/p0014.rst new file mode 100644 index 00000000..7900aa13 --- /dev/null +++ b/docs/csharp/p0014.rst @@ -0,0 +1,16 @@ +C# Implementation of Problem 14 +=============================== + +View source code `here on GitHub! `_ + +.. csharp:namespace:: Euler + +.. csharp:class:: p0014 + + .. csharp:inherits:: Euler.IEuler + + .. csharp:method:: Task Answer() + +.. literalinclude:: ../../csharp/Euler/p0014.cs + :language: csharp + :linenos: diff --git a/docs/csharp/p0015.rst b/docs/csharp/p0015.rst new file mode 100644 index 00000000..7900aa13 --- /dev/null +++ b/docs/csharp/p0015.rst @@ -0,0 +1,16 @@ +C# Implementation of Problem 14 +=============================== + +View source code `here on GitHub! `_ + +.. csharp:namespace:: Euler + +.. csharp:class:: p0014 + + .. csharp:inherits:: Euler.IEuler + + .. csharp:method:: Task Answer() + +.. literalinclude:: ../../csharp/Euler/p0014.cs + :language: csharp + :linenos: diff --git a/docs/index.rst b/docs/index.rst index daadcda2..8b7c75ed 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -140,9 +140,9 @@ Key: +-----------+------------+------------+------------+------------+------------+------------+ |:prob:`13` |:c-d:`0013` | | | |:py-d:`0013`|:rs-d:`0013`| +-----------+------------+------------+------------+------------+------------+------------+ -|:prob:`14` |:c-d:`0014` |:cp-d:`0014`| |:js-d:`0014`|:py-d:`0014`|:rs-d:`0014`| +|:prob:`14` |:c-d:`0014` |:cp-d:`0014`|:cs-d:`0014`|:js-d:`0014`|:py-d:`0014`|:rs-d:`0014`| +-----------+------------+------------+------------+------------+------------+------------+ -|:prob:`15` |:c-d:`0015` |:cp-d:`0015`| | |:py-d:`0015`|:rs-d:`0015`| +|:prob:`15` |:c-d:`0015` |:cp-d:`0015`|:cs-d:`0015`| |:py-d:`0015`|:rs-d:`0015`| +-----------+------------+------------+------------+------------+------------+------------+ |:prob:`16` |:c-d:`0016` | | | |:py-d:`0016`| | +-----------+------------+------------+------------+------------+------------+------------+